2009-08-20 16 views
1

NerdDinnerアプリケーションに精通しているかどうかはわかりません。メソッドGetRuleViolations()とプロパティIsValidをDinnerオブジェクトに追加します。オブジェクトが保存されると、オブジェクトが有効かどうかがチェックされます。そうでない場合は、例外がスローされます。例外がキャッチされたコントローラでは、ViewDataのModelStateがルール違反で満たされ、ビューが再表示されます。 Html.Validationヘルパーはエラーを強調表示します。ASP.NET MVC:例外フィルタ用のViewDataを作成する方法

私がしたいのは、(MVCフレームワークの一部である)HandleExceptionAttributeと同様のHandleRuleViolationExceptionAttributeを作成することです。問題は、この属性がViewのModelstateを再投入する必要があることです。

ビューは、そのモデルに任意のオブジェクト型を持つことができます。 RuleViolationExceptionをスローするコードは、RuleViolationException.ObjectをViewのモデルに設定します。

私はMVCのソースコードでHandleExceptionAttributeのコードを見上げて、それを修正:

<AttributeUsage(AttributeTargets.Class Or AttributeTargets.Method, _ 
    Inherited:=True, AllowMultiple:=False)> _ 
    Public Class HandleRuleViolationExceptionAttribute 
     Inherits FilterAttribute 
     Implements IExceptionFilter 

     Private m_View As String 
     Private m_MasterPage As String 

     Public Property View() As String 
      Get 
       Return m_View 
      End Get 
      Set(ByVal value As String) 
       m_View = value 
      End Set 
     End Property 

     Public Property MasterPage() As String 
      Get 
       Return If(m_MasterPage, String.Empty) 
      End Get 
      Set(ByVal value As String) 
       m_MasterPage = value 
      End Set 
     End Property 

     Public Sub OnException(ByVal filterContext As System.Web.Mvc.ExceptionContext) _ 
       Implements System.Web.Mvc.IExceptionFilter.OnException 
      If filterContext Is Nothing Then 
       Throw New ArgumentException("filterContext is null") 
      End If 

      'Ignore if the error is already handled. 
      If filterContext.ExceptionHandled Then Return 

      'Handle only ObjectIsInvalidExceptions. 
      If Not TypeOf filterContext.Exception Is ObjectIsInvalidException Then 
       Return 
      End If 

      Dim ex As ObjectIsInvalidException = DirectCast(filterContext.Exception, ObjectIsInvalidException) 

      'If this is not an HTTP 500 (for example, if somebody throws an HTTP 404 from an action method), 
      'ignore it. 
      If (New HttpException(Nothing, ex).GetHttpCode()) <> 500 Then Return 

      Dim actionName As String = CStr(filterContext.RouteData.Values("action")) 
      Dim viewName As String = If(String.IsNullOrEmpty(View), actionName, View) 

      Dim viewData = filterContext.Controller.ViewData 
      viewData.Model = ex.Object 
      For Each item As String In filterContext.HttpContext.Request.Form.Keys 
       viewData.Add(item, filterContext.HttpContext.Request.Form.Item(item)) 
      Next 
      For Each ruleViolation In ex.Object.GetRuleViolations() 
       viewData.ModelState.AddModelError(ruleViolation.PropertyName, ruleViolation.ErrorMessage) 
      Next 
      filterContext.Result = New ViewResult() With _ 
      { _ 
        .ViewName = viewName, _ 
        .MasterName = MasterPage, _ 
        .ViewData = viewData, _ 
        .TempData = filterContext.Controller.TempData _ 
      } 
      filterContext.ExceptionHandled = True 
      filterContext.HttpContext.Response.Clear() 
      filterContext.HttpContext.Response.StatusCode = 500 

      'Certain versions of IIS will sometimes use their own error page when 
      'they detect a server error. Setting this property indicates that we 
      'want it to try to render ASP.NET MVC's error page instead. 
      filterContext.HttpContext.Response.TrySkipIisCustomErrors = True 
     End Sub 
    End Class 

私はリクエストのフォームキーを反復ビューのモデルを記入し、ViewDataをするキーとその値を追加するにはインスタンス。それは今では機能しますが、私はこれがそれを行う方法だとは思わない。

コントローラのアクションメソッドでは、モデルをUpdateModelメソッドで更新できました。これは、viewStatesのModelStateも更新します。私は、更新する必要があるプロパティ名を持つ文字列の配列を含めることができます。または、モデルをActionパラメータとして使用する場合、バインド属性を使用して一部のプロパティを除外または除外できます(作成アクション上記)。私の方法はこれに固執せず、セキュリティ上の問題が発生する可能性があります。

コントローラのUpdateModelメソッドと同様に機能するOnExceptionメソッドのViewDataオブジェクトを構築するより良い方法はありますか? ExceptionHandlerAttributeからUpdateModelメソッドを呼び出す方法はありますか?

おかげで、 ギヨームHanique

答えて

0

私の場合は

Dim methodInfo = GetType(Controller).GetMethod("View", _ 
     Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance, Nothing, _ 
     New Type() {GetType(Object)}, Nothing) 
Dim controller = DirectCast(filterContext.Controller, Controller) 
Dim viewResult As ViewResult = _ 
     CType(methodInfo.Invoke(controller, New Object() {ex.Object}), ViewResult) 

Dim viewData = viewResult.ViewData 
For Each ruleViolation In ex.Object.GetRuleViolations() 
    viewData.ModelState.AddModelError(_ 
      ruleViolation.PropertyName, ruleViolation.ErrorMessage) 
Next 
filterContext.Result = viewResult 

私はこのHandleRuleViolationsAttributeを使用する場合filterContext.Controllerは常にコントローラから派生していることを知っています。コントローラでは、ModelStateはreturn View(theObject)を呼び出すことによって設定されます。Viewメソッドは保護されているので、HandleRuleViolationsAttributeではリフレクションを使用して呼び出すため、ModelStateが正しく初期化されたViewResultインスタンスが表示されます。 AddModelErrorメソッドを使用して、ModelVateにRuleViolationsを追加することができます。私はそのviewResultをfilterContext.Resultに割り当てて、それを表示させます。

1

カップル迅速なポイント:
1.あなたが実際に(ビュープロパティとしてへのアクセス権を持っている)コントローラのにModelState 2.あなたがに結果を設定したいを更新したいですa無効なモデルオブジェクトで渡すビュー

あなたの説明から、コントローラのUpdateModelメソッドを呼び出す必要があるようです。あなたはこれを行うことによって、あなたのonExceptionをメソッドからこれを行うことができます。

filterContext.Controller.UpdateModel(ex.Object) 
... 
For Each ruleViolation In ex.Object.GetRuleViolations() 
      filterContext.Controller.ModelState.AddModelError(ruleViolation.PropertyName, ruleViolation.ErrorMessage) 
Next 
... 
filterContext.Result = filterContext.Controller.View(ex.Object) 

ユーザーは例外の場合に使用する代替ビューを指定することができるようにするには、属性に「VIEWNAME」と呼ばれるプロパティを露出し検討するかもしれない:

<HandleRuleViolationException(ViewName:="SomeErrorViewForThisControllerOrAction")> 

これはかなりきちんとした考えです。投稿に戻って更新したり、回答をマークしたり、結果についてコメントしてください。私はこれがどのように機能するかについて非常に興味があります!

+0

返信いただきありがとうございます! 属性には実際に設定可能なビュープロパティがありますが、設定できない場合は、アクション名がビュー名として使用されます。 filterContext.Controller.UpdateModel filterContext.Controllerは、UpdateModelメソッドを持たないControllerBase型です。他のアイデア? 実際のControllerインスタンスをこの属性(コントローラのアクションのthis/Me)に渡してモデルを更新することができますか? –

+0

良い点。私はそれを逃した。コードを振り返ってみると、私は実際にこれをここで行うために必要な作業はほとんどないと思います。 viewData.Modelをex.Objectに設定することで、同じことが達成されます。私はex.Objectからすべてのフォームデータを取得すると思いますか?そうでないかもしれない。 –

+0

私はあきらめます。私は、UpdateModelが呼び出すメソッドであるかどうか分からない。たとえそれがあっても、私はどのように考え出すことができません。ビューのModelプロパティを設定するときに誰かがModelStateを更新する方法を知っていますか? –

関連する問題