Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/335.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 处理从绑定操作参数到路由不正确类型的值的错误_C#_Asp.net Mvc 4_Asp.net Web Api - Fatal编程技术网

C# 处理从绑定操作参数到路由不正确类型的值的错误

C# 处理从绑定操作参数到路由不正确类型的值的错误,c#,asp.net-mvc-4,asp.net-web-api,C#,Asp.net Mvc 4,Asp.net Web Api,我在处理ASP.NET WebAPI中的所有类型的错误时遇到问题 我已经成功地处理了在我的操作方法中抛出的异常,使用了和404 errors for。但是,我正在努力处理这样一个错误:控制器和操作都找到了,但是模型绑定的参数类型不正确 这是我的操作,它被路由到/api/users/{id} [HttpGet] public virtual TPoco Get(long id) { ... } 如果我请求URL/api/users/notinteger,我会得到一个400错误请求错误,该

我在处理ASP.NET WebAPI中的所有类型的错误时遇到问题

我已经成功地处理了在我的操作方法中抛出的异常,使用了和404 errors for。但是,我正在努力处理这样一个错误:控制器和操作都找到了,但是模型绑定的参数类型不正确

这是我的操作,它被路由到
/api/users/{id}

[HttpGet]
public virtual TPoco Get(long id)
{
    ...
}
如果我请求URL
/api/users/notinteger
,我会得到一个
400错误请求
错误,该错误在我的代码之外处理:

{
Message: "The request is invalid.",
MessageDetail: "The parameters dictionary contains a null entry for parameter 'id' of non-nullable type 'System.Int64' for method '___ Get(Int64)' in '___'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter."
}
如何截获此错误并使用自己的错误消息进行响应?最好不要在控制器本身,因为我希望以相同的方式处理多个控制器


我已经尝试按照使用
global.asax.cs
应用程序错误
事件,但在本例中似乎没有调用该事件。

如果您使用新的WebApi 2.1全局错误处理,效果会更好,

如果您出于正当理由不愿意使用WebApi 2.1,那么您可以尝试。(注意:我没有测试,但您可以尝试)。通过继承ReflectedHttpActionDescriptor和handle ExecuteAsync创建自定义操作描述符。这就是我的意思

public class HttpNotFoundActionDescriptor : ReflectedHttpActionDescriptor
{
    ReflectedHttpActionDescriptor _descriptor;
    public HttpNotFoundActionDescriptor(ReflectedHttpActionDescriptor descriptor)
    {
    _descriptor = descriptor;
    }

    public override Task<object> ExecuteAsync(HttpControllerContext controllerContext, IDictionary<string, object> arguments, CancellationToken cancellationToken)
    {
    try
        {
            return descriptor.ExecuteAsync(controllerContext, arguments, cancellationToken);
        }
        catch (HttpResponseException ex)
        {
         //..........................
    }   
    }
}

public class HttpNotFoundAwareControllerActionSelector : ApiControllerActionSelector
{
    public HttpNotFoundAwareControllerActionSelector()
    {
    }

    public override HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
    {
        HttpActionDescriptor decriptor = null;
        try
        {
            decriptor = base.SelectAction(controllerContext);
        }
        catch (HttpResponseException ex)
        {
            var code = ex.Response.StatusCode;
            if (code != HttpStatusCode.NotFound && code != HttpStatusCode.MethodNotAllowed)
                throw;
            var routeData = controllerContext.RouteData;
            routeData.Values["action"] = "Handle404";
            IHttpController httpController = new ErrorController();
            controllerContext.Controller = httpController;
            controllerContext.ControllerDescriptor = new HttpControllerDescriptor(controllerContext.Configuration, "Error", httpController.GetType());
            decriptor = base.SelectAction(controllerContext);
        }
        return new HttpNotFoundActionDescriptor(decriptor);
    }
}
公共类HttpNotFoundActionDescriptor:ReflectedHttpActionDescriptor
{
反射HttpActionDescriptor_描述符;
公共HttpNotFoundActionDescriptor(反射的HttpActionDescriptor描述符)
{
_描述符=描述符;
}
公共覆盖任务ExecuteAsync(HttpControllerContext controllerContext,IDictionary参数,CancellationToken CancellationToken)
{
尝试
{
返回描述符.ExecuteAsync(controllerContext、参数、cancellationToken);
}
捕获(HttpResponseException ex)
{
//..........................
}   
}
}
公共类HttpNotFoundAwareControllerActionSelector:ApiControllerActionSelector
{
公共HttpNotFoundAwareControllerActionSelector()
{
}
公共覆盖HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
{
HttpActionDescriptor decriptor=null;
尝试
{
descriptor=base.SelectAction(controllerContext);
}
捕获(HttpResponseException ex)
{
var代码=ex.Response.StatusCode;
if(code!=HttpStatusCode.NotFound&&code!=HttpStatusCode.MethodNotAllowed)
投掷;
var routeData=controllerContext.routeData;
RoutedData.Values[“action”]=“Handle404”;
IHttpController httpController=新的ErrorController();
controllerContext.Controller=httpController;
controllerContext.ControllerDescriptor=新的HttpControllerDescriptor(controllerContext.Configuration,“Error”,httpController.GetType());
descriptor=base.SelectAction(controllerContext);
}
返回新的HttpNotFoundActionDescriptor(decriptor);
}
}

注意,您需要覆盖所有虚拟方法。

这些错误似乎作为模型绑定错误添加到ModelState中。动作选择器选择正确的动作,动作调用器调用它而不抛出任何错误

我想到的解决方法是创建一个动作调用程序,用于检查
ModelState
是否存在错误。如果找到任何异常,它会将第一个异常传递给my
ExceptionFilter
ErrorController
使用的异常处理方法

internal class ThrowModelStateErrorsActionInvoker : ApiControllerActionInvoker
{
    public override Task<HttpResponseMessage> InvokeActionAsync(HttpActionContext actionContext, CancellationToken cancellationToken)
    {
        foreach (var error in actionContext.ModelState.SelectMany(kvp => kvp.Value.Errors))
        {
            var exception = error.Exception ?? new ArgumentException(error.ErrorMessage);
            //invoke global exception handling
        }

        return base.InvokeActionAsync(actionContext, cancellationToken);
    }
}
内部类ThrowModelStateErrorsActionInvoker:ApiControllerActionInvoker
{
公共覆盖任务InvokeActionAsync(HttpActionContext actionContext,CancellationToken CancellationToken)
{
foreach(actionContext.ModelState.SelectMany中的var错误(kvp=>kvp.Value.Errors))
{
var exception=error.exception??新参数exception(error.ErrorMessage);
//调用全局异常处理
}
返回base.InvokeActionAsync(actionContext,cancellationToken);
}
}
这很恶心,但很管用。这占据了我一天的大部分时间,我很高兴终于有了进展


我很想知道这会带来什么后果。Web API中的ModelState错误还有哪些用途?是否有人可以在此解决方案中添加一些可能的缺陷?

编写自定义筛选器属性。@dotnebeginner哪种类型的筛选器属性?我有一个全局
ExceptionFilterAttribute
集,但这似乎并没有捕获这些错误,只是在我的操作中抛出了异常。看看我已经更新到MVC 5.1和Web API 2.1,改为
IEExceptionHandler
,虽然我确实更喜欢使用此方法而不是使用过滤器,路由错误仍然忽略了这一点,并显示与以前相同的错误。@ConnellWatkins使用WebHost的问题是,路由发生在调用Web API基础结构之前,因此Web API无法提供任何帮助。但是,ASP.NET运行时中必须有一种方法来捕获这些错误。@ConnellWatkins,对于找不到的路由,您可以使用自定义的“匹配所有内容”路由。请参阅,@imran_ku07,谢谢,但正如问题中所述,我已经处理了这个问题。@ConnellWatkins,您的意思是全局错误没有处理
参数字典包含参数的空条目。