3

私のアクションメソッドのほとんどは、成功するとPartialViewsを返し、失敗するとRedirectToActionの結果を返します。そのために、モデル状態エラーをTempDataにコピーして、ユーザーに表示できるようにします。SOといくつかの外部リンクに関するいくつかの質問をここで読みましたが、どれもうまくいきませんでした... MvcContribのModelStateToTempData属性でActionMethodを装飾し、ビューに次のように表示しています:(これは単なるプロトタイプです)

        @if (TempData.Count > 0)
        {
            foreach (var obj in TempData)
            {
                var errors = ((ModelStateDictionary)obj.Value).Values;
                foreach (var error in errors)
                {
                <div style="position:absolute; background:Black; color:White; top:250px; left:550px;">
                    <span style="margin-bottom:5px; display:block; height:25px;">@error.Value</span>
                </div>
                }
            }
        }

エラー自体を表示するのではなく、取得し続けSystem.Web.Mvc.ValueProviderResultます。これがすべて間違っていることはわかっています。最終的には、モデルの状態エラーをTempData内のディクショナリにフィルタリングしたいのですが、今のところ、ビューにエラー文字列を表示したいだけです。

PS:MvcContrib属性を使用せずに手動で実行しようとしましたが、同じ結果が得られました。しかし、私は自分のコードを使用することを好みます。そうすれば、問題全体をより細かく制御できるようになります。

助言がありますか?

4

3 に答える 3

3

百万ものことを試した後、私は自分で答えを見つけました... :)

if (TempData["ModelErrors"] == null)
    TempData.Add("ModelErrors", new List<string>());
foreach (var obj in ModelState.Values)
{
    foreach (var error in obj.Errors)
    {
        if(!string.IsNullOrEmpty(error.ErrorMessage))
            ((List<string>)TempData["ModelErrors"]).Add(error.ErrorMessage);
    }
}
return RedirectToAction("Index", "Home");

そして、ビューで:

    <div id="validationMessages">
        @{
            var errors = (List<string>)TempData["ModelErrors"];
        }
        @if (errors != null && errors.Count() > 0)
        {
            <div style="position:absolute; background:Black; color:White; top:250px; left:550px;">
                @foreach (var error in errors)
                { 
                   <span style="margin-bottom:5px; display:block; height:25px;">@error</span> 
                }
            </div>
        }
    </div>

アップデート:

ここでは、ActionFilter内にあります。

public class CopyModelStateErrorsToTempData : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        //Only export when ModelState is not valid
        if (!filterContext.Controller.ViewData.ModelState.IsValid)
        {
            //Export if we are redirecting
            if ((filterContext.Result is RedirectResult) || (filterContext.Result is RedirectToRouteResult))
            {
                if (filterContext.Controller.TempData["ModelErrors"] == null)
                    filterContext.Controller.TempData.Add("ModelErrors", new List<string>());
                foreach (var obj in filterContext.Controller.ViewData.ModelState.Values)
                {
                    foreach (var error in obj.Errors)
                    {
                        if (!string.IsNullOrEmpty(error.ErrorMessage))
                            ((List<string>)filterContext.Controller.TempData["ModelErrors"]).Add(error.ErrorMessage);
                    }
                }
            }
        }

        base.OnActionExecuted(filterContext);
    }
}
于 2011-05-07T15:02:12.870 に答える
1

私はこの道を進み始め、それからあなたの答えを読みました。それらを次のファイルに結合しました。

TempDataDictionaryExtensions.cs

TempDataがアクションフィルター自体に属していないと感じたため、TempDataでダーティな作業を行うための拡張メソッドを作成しました。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

namespace Project.Web.UI.Domain
{
    public static class TempDataDictionaryExtensions
    {
        private const string _ModelStateErrorsKey = "ModelStateErrors";

        public static IEnumerable<string> GetModelErrors(this TempDataDictionary instance)
        {
            return TempDataDictionaryExtensions.GetErrorsFromTempData(instance);
        }

        public static void AddModelError(this TempDataDictionary instance, string error)
        {
            TempDataDictionaryExtensions.AddModelErrors(instance, new List<string>() { error });
        }

        public static void AddModelErrors(this TempDataDictionary instance, IEnumerable<string> errors)
        {
            TempDataDictionaryExtensions.AddErrorsToTempData(instance, errors);
        }

        private static List<string> GetErrorsFromTempData(TempDataDictionary instance)
        {
            object tempObject = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey);
            if (tempObject == null)
            {
                return new List<String>();
            }
            List<string> tempErrors = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey).Value as List<string>;
            if (tempErrors == null)
            {
                return new List<String>();
            }
            return tempErrors;
        }

        private static void AddErrorsToTempData(TempDataDictionary instance, IEnumerable<string> errors)
        {
            List<string> tempErrors;

            object tempObject = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey);
            if (tempObject == null)
            {
                tempErrors = new List<String>();
            }
            else
            {
                tempErrors = instance.FirstOrDefault(x => x.Key == TempDataDictionaryExtensions._ModelStateErrorsKey).Value as List<string>;
                if (tempErrors == null)
                {
                    tempErrors = new List<String>();
                }
            }

            tempErrors.AddRange(errors);

            instance[TempDataDictionaryExtensions._ModelStateErrorsKey] = tempErrors;
        }
    }
}

TempDataModelStateAttribute.cs

私のオリジナルは、ActionResultがを介して実行される前に、エラーをコピーしてTempData戻しました。これは、それらをコピーしてコピーしたり、元に戻したりすることの組み合わせです。ModelStateOnResultExecutingTempData

using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;

namespace Project.Web.UI.Domain
{
    public class TempDataModelStateAttribute : ActionFilterAttribute
    {
        public override void OnResultExecuting(ResultExecutingContext filterContext)
        {
            IEnumerable<string> modelErrors = ((Controller)filterContext.Controller).TempData.GetModelErrors();
            if (modelErrors != null
                && modelErrors.Count() > 0)
            {
                modelErrors.ToList()
                           .ForEach(x => ((Controller)filterContext.Controller).ModelState.AddModelError("GenericError", x));
            }
            base.OnResultExecuting(filterContext);
        }

        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            if (!filterContext.Controller.ViewData.ModelState.IsValid)
            {
                if (filterContext.Result is RedirectResult
                    || filterContext.Result is RedirectToRouteResult)
                {
                    List<string> errors = new List<string>();
                    foreach (var obj in filterContext.Controller.ViewData.ModelState.Values)
                    {
                        foreach (var error in obj.Errors)
                        {
                            errors.Add(error.ErrorMessage);
                        }
                    }
                    ((Controller)filterContext.Controller).TempData.AddModelErrors(errors); 
                }
            }

            base.OnActionExecuted(filterContext);
        }
    }
}
于 2012-04-29T17:17:09.310 に答える
0

この概念を真剣に検討する必要があります: http ://weblogs.asp.net/rashid/archive/2009/04/01/asp-net-mvc-best-practices-part-1.aspx#prg

于 2012-06-19T08:47:43.680 に答える