从OWIN中间件

时间:2016-07-18 13:12:56

标签: c# asp.net-web-api2 owin

我有一个OWIN中间件类,可以根据一些自定义令牌进行一些身份验证。一切正常。但是,我想向客户端返回有用的错误响应。我的理由是,如果客户要求申请/ json'响应,他们期待一个序列化对象,然后他们应该得到什么,即使它是401状态代码。

以下是我的中间件的Invoke部分:

    public override async Task Invoke(IOwinContext context)
    {
        try
        {
            this.DoAuthorization(context);
            await this.Next.Invoke(context);
        }
        catch (UnauthorizedAccessException ex)
        {
            this.GenerateErrorResult(context, HttpStatusCode.Unauthorized, this.ExceptionToString(ex));
        }
        catch (Exception ex)
        {
            this.GenerateErrorResult(context, HttpStatusCode.InternalServerError, this.ExceptionToString(ex));
        }
    }

    private void GenerateErrorResult(IOwinContext context, HttpStatusCode code, string errorMessage)
    {
        var result = new Result { Status = Result.EStatus.Error, ErrorText = errorMessage };

        context.Response.StatusCode = (int)code;
        context.Response.ContentType = "application/json";
        context.Response.Write(JsonConvert.SerializeObject(result));
    }

然而,这一切都很好:

  • 这是正确的'方式是什么?
  • 如果客户端要求“application / xml”,显然Web API能够支持
  • ,该怎么办?

是否有更好的方法可以返回按客户端预期序列化的自定义响应对象(在我的情况下为'结果?)

1 个答案:

答案 0 :(得分:2)

这似乎有效,使用首先插入的额外OwinMiddleware:

   public override async Task Invoke(IOwinContext context)
    {
        try
        {
            await Next.Invoke(context);
        }
        catch (UnauthorizedAccessException ex)
        {
            var result = new Result { Status = Result.EStatus.Error, ErrorText = ExceptionToString(ex) };

            this.ReturnFormattedResult(result, HttpStatusCode.Unauthorized, context);
        }
        catch (Exception ex)
        {
            var result = new Result { Status = Result.EStatus.Error, ErrorText = ExceptionToString(ex) };

            this.ReturnFormattedResult(result, HttpStatusCode.InternalServerError, context);
        }
    }

    private void ReturnFormattedResult(Result result, HttpStatusCode code, IOwinContext context)
    {
        // what should our response be?
        var mediaType = context.Request.MediaType ?? context.Request.ContentType;

        // use the accept header (unless it is empty or '*/*' in which case use the content-type
        if (!string.IsNullOrEmpty(context.Request.Accept) && !context.Request.Accept.Contains("*/*"))
        {
            mediaType = context.Request.Accept;
        }

        // find a formatter for this media type, if no match then use the first one
        var formatter = this.config.Formatters.FindWriter(typeof(Result), new MediaTypeHeaderValue(mediaType));
        if (formatter == null)
        {
            formatter = this.config.Formatters.First();
            mediaType = formatter.SupportedMediaTypes.First().MediaType;
        }

        context.Response.StatusCode = (int)code;
        context.Response.ContentType = mediaType;
        formatter.WriteToStreamAsync(typeof(Result), result, context.Response.Body, null, null).Wait();
    }