Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-mvc/14.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
Asp.net mvc 使用Handler在MVC上处理Web API异常_Asp.net Mvc_Error Handling_Asp.net Web Api - Fatal编程技术网

Asp.net mvc 使用Handler在MVC上处理Web API异常

Asp.net mvc 使用Handler在MVC上处理Web API异常,asp.net-mvc,error-handling,asp.net-web-api,Asp.net Mvc,Error Handling,Asp.net Web Api,我对MVC4的异常处理有一些疑问 我已经实现了HandleErrorAttribute,并派生了一个新属性进行自定义。它工作得非常好;但我不想每次都重定向用户自定义错误页 我在操作中遇到的一些错误,从WebAPI抛出,我想在当前页面上向用户显示它们。 例如,如果用户想要创建一条记录,但WebAPI由于modelstate无效而引发异常,则在create视图中以友好的方式显示异常详细信息 但是默认情况下HandleErrorAttribute重定向Error.cshtml 我可以处理行动中的每一个

我对MVC4的异常处理有一些疑问

我已经实现了
HandleErrorAttribute
,并派生了一个新属性进行自定义。它工作得非常好;但我不想每次都重定向用户自定义错误页

我在操作中遇到的一些错误,从WebAPI抛出,我想在当前页面上向用户显示它们。 例如,如果用户想要创建一条记录,但WebAPI由于modelstate无效而引发异常,则在create视图中以友好的方式显示异常详细信息

但是默认情况下HandleErrorAttribute重定向Error.cshtml

我可以处理行动中的每一个异常,但我认为还有另一种方法

我还遵循了实现
HandleErrorAttribute

 public class CustomHandleErrorAttribute : HandleErrorAttribute {
        private readonly ILogger _logger;

        public CustomHandleErrorAttribute() {
            _logger = new NLogger(typeof(CustomHandleErrorAttribute));
        }

        public override void OnException(ExceptionContext filterContext) {
            if(filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled) {
                return;
            }

            if(new HttpException(null, filterContext.Exception).GetHttpCode() != 500) {
                return;
            }

            if(!ExceptionType.IsInstanceOfType(filterContext.Exception)) {
                return;
            }

            // if the request is AJAX return JSON else view.
            if(filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest") {
                filterContext.Result = new JsonResult {
                    JsonRequestBehavior = JsonRequestBehavior.AllowGet,
                    Data = new {
                        error = true,
                        message = filterContext.Exception.Message
                    }
                };
            }
            else {
                var controllerName = (string)filterContext.RouteData.Values["controller"];
                var actionName = (string)filterContext.RouteData.Values["action"];
                var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
                filterContext.Result = new ViewResult {

                    ViewName = View,
                    MasterName = Master,
                    ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
                    TempData = filterContext.Controller.TempData
                };
            }

            _logger.Error(filterContext.Exception.Message, filterContext.Exception);

            filterContext.ExceptionHandled = true;
            filterContext.HttpContext.Response.Clear();
            filterContext.HttpContext.Response.StatusCode = 500;

            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
        }
    }
<代码>公共类CustomHandleErrorAttribute:HandleErrorAttribute{ 专用只读ILogger\u记录器; 公共CustomHandleErrorAttribute(){ _记录器=新的NLogger(类型(CustomHandleErrorAttribute)); } 公共覆盖无效OneException(例外上下文筛选器上下文){ if(filterContext.ExceptionHandled | | |!filterContext.HttpContext.IsCustomErrorEnabled){ 返回; } if(新的HttpException(null,filterContext.Exception).GetHttpCode()!=500){ 返回; } 如果(!ExceptionType.IsInstanceOfType(filterContext.Exception)){ 返回; } //如果请求是AJAX,则返回JSON else视图。 if(filterContext.HttpContext.Request.Headers[“X-Requested-With”]=“XMLHttpRequest”){ filterContext.Result=新的JsonResult{ JsonRequestBehavior=JsonRequestBehavior.AllowGet, 数据=新{ 错误=真, message=filterContext.Exception.message } }; } 否则{ var controllerName=(字符串)filterContext.RouteData.Values[“controller”]; var actionName=(字符串)filterContext.RouteData.Values[“action”]; var model=newhandleerrorinfo(filterContext.Exception、controllerName、actionName); filterContext.Result=新的ViewResult{ ViewName=视图, MasterName=Master, ViewData=新的ViewDataDictionary(型号), TempData=filterContext.Controller.TempData }; } _logger.Error(filterContext.Exception.Message,filterContext.Exception); filterContext.ExceptionHandled=true; filterContext.HttpContext.Response.Clear(); filterContext.HttpContext.Response.StatusCode=500; filterContext.HttpContext.Response.TrySkipIisCustomErrors=true; } } 我通过HttpClient和包装器类进行Web API调用。例如,Get请求如下所示

 public async Task<BrandInfo> Create(BrandInfo entity) {
            using(var apiResponse = await base.PostAsync(BaseUriTemplate, entity)) {

                if(apiResponse.IsSuccess) {
                    return apiResponse.Model;
                }

                throw new HttpApiRequestException(
                    string.Format(HttpRequestErrorFormat, (int)apiResponse.Response.StatusCode, apiResponse.Response.ReasonPhrase),
                    apiResponse.Response.StatusCode, apiResponse.HttpError);
            }
        }
公共异步任务创建(BrandInfo实体){
使用(var apiResponse=wait base.PostAsync(BaseUriTemplate,entity)){
if(apiResponse.issueccess){
返回apiResponse.Model;
}
抛出新的HttpApiRequestException(
格式(HttpRequestErrorFormat,(int)apiResponse.Response.StatusCode,apiResponse.Response.ReasonPhase),
apiResponse.Response.StatusCode,apiResponse.HttpError);
}
}

构建一个类,该类将封装HttpClient并使用它调用Web API。 从Web API返回不同的HTTP状态代码,用于希望发生重定向的情况(即500-内部服务器错误,或401-未经授权)和希望显示模型状态错误的情况(400-错误请求将是我的选择)。 将包装盒中的状态代码处理为:

a) 如果希望重定向(从Web API接收到500或401)时出错,则引发相应的异常

b) 当您不需要重定向(从WebAPI接收400)时,只需从包装器类返回一些响应模型,这些模型可以显示在客户端

在您的控制器中,只需假设您将从HTTP包装器类返回响应模型,因为异常将导致它永远无法返回控制器(您将全局处理它并执行重定向)

如果您需要一个代码示例,我可以提供一个,但我认为您更多的是寻找一个通用的概念,而不是具体的代码

编辑:

在Web API方面:

public class ModelValidationFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
        if (!actionContext.ModelState.IsValid)
        {
            Dictionary<string,string> errors = new Dictionary<string, string>();
            foreach (KeyValuePair<string, ModelState> keyValue in actionContext.ModelState)
            {
                errors[keyValue.Key] = keyValue.Value.Errors.Select(e => e.ErrorMessage).FirstOrDefault();
            }
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.BadRequest, new ApiError(ApiErrorCode.ModelBindingError, errors));
        }
    }
}
自定义API错误:

public class ApiError
{
    public ApiErrorCode ErrorCode { get; set; }
    public string ErrorMessage { get; set; }
    public Dictionary<string, string> ModelStateErrors;
}
public类错误
{
公共ApiErrorCode错误代码{get;set;}
公共字符串错误消息{get;set;}
公共字典错误;
}
说到MVC端,以下是您的包装器HttpClient包装器类的外观:

public class RPCService
{

    public async Task<RPCResponseModel<T>> GetAsync<T>(string controller, string action, Dictionary<string, string> queryParams, Dictionary<string, string> headers)
    {
        using (HttpClient client = new HttpClient())
        {
            client.BaseAddress = new Uri("your host goes here");
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); /// Tell RPC to return data as json
            if (headers != null) foreach (var header in headers) client.DefaultRequestHeaders.Add(header.Key, header.Value);
            string query = Query(queryParams);
                var response = await client.GetAsync(controller + "/" + action + query);
                if (response.IsSuccessStatusCode)
                {
                    return new RPCResponseModel<T>
                    {
                        StatusCode = response.StatusCode,
                        Data = await response.Content.ReadAsAsync<T>()
                    };
                }
                else if(response.StatusCode == HttpStatusCode.BadRequest)
                {
                    return new RPCResponseModel<T>
                    {
                        Error = await response.Content.ReadAsAsync<RPCErrorModel>(),
                        StatusCode = response.StatusCode
                    };
                }
else
{
    /// throw your exception to handle globally
}
        }
    }
公共类RPCService
{
公共异步任务GetAsync(字符串控制器、字符串操作、字典查询参数、字典头)
{
使用(HttpClient=new HttpClient())
{
client.BaseAddress=新Uri(“您的主机转到此处”);
client.DefaultRequestHeaders.Accept.Add(新的MediaTypeWithQualityHeaderValue(“应用程序/json”);///告诉RPC以json的形式返回数据
if(headers!=null)foreach(headers中的var header)client.DefaultRequestHeaders.Add(header.Key,header.Value);
字符串查询=查询(查询参数);
var response=wait client.GetAsync(控制器+“/”+操作+查询);
if(响应。IsSuccessStatusCode)
{
返回新的RPCresponsModel
{
StatusCode=response.StatusCode,
Data=wait response.Content.ReadAsAsync()
};
}
else if(response.StatusCode==HttpStatusCode.BadRequest)
{
public class RPCService
{

    public async Task<RPCResponseModel<T>> GetAsync<T>(string controller, string action, Dictionary<string, string> queryParams, Dictionary<string, string> headers)
    {
        using (HttpClient client = new HttpClient())
        {
            client.BaseAddress = new Uri("your host goes here");
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); /// Tell RPC to return data as json
            if (headers != null) foreach (var header in headers) client.DefaultRequestHeaders.Add(header.Key, header.Value);
            string query = Query(queryParams);
                var response = await client.GetAsync(controller + "/" + action + query);
                if (response.IsSuccessStatusCode)
                {
                    return new RPCResponseModel<T>
                    {
                        StatusCode = response.StatusCode,
                        Data = await response.Content.ReadAsAsync<T>()
                    };
                }
                else if(response.StatusCode == HttpStatusCode.BadRequest)
                {
                    return new RPCResponseModel<T>
                    {
                        Error = await response.Content.ReadAsAsync<RPCErrorModel>(),
                        StatusCode = response.StatusCode
                    };
                }
else
{
    /// throw your exception to handle globally
}
        }
    }
public class RPCErrorModel
{
    public int Code { get; set; }
    public string Message { get; set; }
    public Dictionary<string, string> ModelErrors;
}

public class RPCResponseModel
{
    public RPCErrorModel Error { get; set; }
    public HttpStatusCode StatusCode { get; set; }
}

public class RPCResponseModel<T> : RPCResponseModel
{
    public T Data { get; set; }
}