5

MVC4 を使用して構築されたインターネット向けの Web サイトを持っていますが、不完全な URL の要求を送信するボットや好奇心旺盛なユーザーからエラー レポートを受け取ることがあります。

例えば:

public class ProductController : Controller
{
    [HttpGet]
    public void View(int id)
    {
        // ...
  • へのGETリクエスト/product/view/1は有効です。
  • /product/view引数が指定されていないため、への GET リクエストは無効です。

このような無効なリクエストは、次のような例外を発生させます。

System.ArgumentException: The parameters dictionary contains a null entry
for parameter 'id' of non-nullable type 'System.Int32' for method
'System.Web.Mvc.ActionResult View(Int32)' in 'Foo.ProductController'. An
optional parameter must be a reference type, a nullable type, or be declared
as an optional parameter.

Parameter name: parameters
   at System.Web.Mvc.ActionDescriptor.ExtractParameterFromDictionary(ParameterInfo parameterInfo, IDictionary`2 parameters, MethodInfo methodInfo)
   at System.Web.Mvc.ReflectedActionDescriptor.<>c__DisplayClass1.<Execute>b__0(ParameterInfo parameterInfo)
   ...

例外メッセージが示すように、id引数を null 可能にして、アクション メソッド内でチェックすることはできましたが、多くのアクションを持つ多くコントローラーがあります。

BadRequest引数をアクション パラメーターにバインドできなかったリクエストに対して/レスポンスを返し、NotFoundこれをコード内の 1 か所で指定して、すべてのコントローラーに適用したいと考えています。

これはどのように行うことができますか?

4

2 に答える 2

3

機能しているように見える 1 つのアプローチは、コントローラーでオーバーライドOnActionExecutedすることです (私はベース コントローラーを使用しているので、そこに置きます)。

protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
    if (filterContext.Exception == null)
        return;

    // Avoid 'action parameter missing' exceptions by simply returning an error response
    if (filterContext.Exception.TargetSite.DeclaringType == typeof(ActionDescriptor) &&
        filterContext.Exception.TargetSite.Name == "ExtractParameterFromDictionary")
    {
        filterContext.ExceptionHandled = true;
        filterContext.Result = new HttpStatusCodeResult((int)HttpStatusCode.BadRequest);
    }
}

フレームワークの将来のバージョンで壊れる可能性があるため、これを行うのは少し不快に感じます。ただし、それが壊れた場合、サイトは 400 ではなく 500 を返すようになります。

于 2013-10-16T10:27:46.510 に答える
2

You can use the HandleError attribute to handle errors in your application. The HandleError attribute can be specified both at controller level and method level. I have used something like this before:

[HandleError(ExceptionType = typeof(ArgumentException), View = "MissingArgument")]
public ActionResult Test(int id)
{
    return View();
}

If you don't want to catch exceptions on a per method basis you can put the attribute on class level instead:

[HandleError(ExceptionType = typeof(ArgumentException), View = "MissingArgument")]
public class HomeController : Controller
{
}

If you want to handle this in a central place you can add it to the FilterConfig class in the App-Start folder:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    var error = new HandleErrorAttribute();
    error.ExceptionType = typeof (ArgumentException);
    error.View = "MissingArgument";
    filters.Add(error);
}

The MissingArgument view should be located in the Shared view folder. If you want to send a specific HTTP error code back to the client you can put that in the view:

@{
    ViewBag.Title = "Error";
    Context.Response.StatusCode = (int) HttpStatusCode.BadRequest;
 }

<h2>Not found</h2>
于 2013-10-15T15:04:39.713 に答える