6

通常、データをデータベースにコミットする前に、アクション メソッドでモデルを検証しています。

[HttpPost]
public ActionResult MyActionMethod(MyModelType model){
if (ModelState.IsValid){
   //commit changes to database...
   return View("SuccessView",model);
}
return View(model);
}

しかし、ごくまれに、モデルのコミット中にビジネス層で追加の検証を実行する必要がある場合があります。検証エラーが発生した場合は、ビジネス レイヤーで例外を発生させ、その例外を使用して検証エラーのあるビューを返したいと考えています。

コントローラーのコードを変更せずにこれを実装する方法を探しています。だから私はこれを避ける方法を探しています:

[HttpPost]
public ActionResult MyActionMethod(MyModelType model){
if (ModelState.IsValid){
   try {
   //commit changes to database...
   } catch (ValidationException e){
      ModelState.AddModelError(...);
      return View(model);
   }
   return View("SuccessView",model);

}
return View(model);
}

これを行う方法はありますか?

ValidationExceptions をキャッチし、通常のフィルターが作動する前に検証エラーを含む適切なビューを返すアクション フィルターを考えてい[HandleError]ました。このようなことは可能ですか?

編集:解決策を見つけました(以下を参照)が、48時間が経過するまでこれを正解としてマークすることはできません...

4

3 に答える 3

6

ASP.NET MVCソースコードを少し検索したところ、解決策が見つかりました。

アクションフィルターは、アクションメソッドが呼び出される前後に呼び出されるため実行できませんが、実際にはアクションメソッド呼び出しをラップしません。

ただし、カスタムActionMethodInvokerを使用して実行できます。

public class CustomActionInvoker : ControllerActionInvoker
{
    protected override ActionResult InvokeActionMethod(
        ControllerContext controllerContext, 
        ActionDescriptor actionDescriptor, 
        System.Collections.Generic.IDictionary<string, object> parameters)
    {
        try
        {
            //invoke the action method as usual
            return base.InvokeActionMethod(controllerContext, actionDescriptor, parameters);
        }
        catch(ValidationException e)
        {
            //if some validation exception occurred (in my case in the business layer) 
            //mark the modelstate as not valid  and run the same action method again
            //so that it can return the proper view with validation errors. 
            controllerContext.Controller.ViewData.ModelState.AddModelError("",e.Message);
            return base.InvokeActionMethod(controllerContext, actionDescriptor, parameters);
        }
    }
}

そして、コントローラー上で:

protected override IActionInvoker CreateActionInvoker()
{
    return new CustomActionInvoker();
}
于 2011-05-14T17:57:50.110 に答える
3

明らかに、アクションフィルターでアクション結果を設定できます。ただし、ActionExecuting (filterContext.Result) を使用してアクションの結果を設定している場合、コントローラー コードは呼び出されません。ActionFilter の代わりに、追加の検証ロジックがモデルに関連付けられている場合、より良い解決策はカスタム モデル バインダーを使用することだと思います。

それが役立つことを願っています。

于 2011-05-14T12:31:22.567 に答える
1

静的な BusinessValidator ヘルパーを定義して、次のようなことをしてみませんか?

[HttpPost]
public ActionResult MyActionMethod(MyModelType model){
var businessErrors = null;
if ((ModelState.IsValid) && (BusinessValidator<MyModelType>.IsValid(model, out businesErrors)){
   //commit changes to database...
   return View("SuccessView",model);
}

if (businessErrors != null)
{
 // TODO: add errors to the modelstate
}

return View(model);
}
于 2011-05-14T14:45:17.873 に答える