在OpenRasta中,您应该如何处理编解码器错误或异常?

时间:2012-03-29 15:05:57

标签: openrasta

我的情况是:

  1. 客户端应用程序针对OpenRasta公开的端点执行HTTP POST。
  2. 请求正文包含导致编解码器出现问题的错误 - 这是OpenRasta.Codecs.IMediaTypeReader的自定义实现。这会将JSON有效负载转换为处理程序所期望的POCO。
  3. 编解码器抛出一个以有用的方式描述错误的异常。例如:Newtonsoft.Json.JsonReaderException: After parsing a value an unexpected character was encountered: ". Line 4, position 5.
  4. 客户端应用程序收到HTTP 405 - MethodNotAllowed。客户端没有看到任何异常细节。
  5. 如果修改编解码器以捕获JsonReaderException并返回Missing.Value,类似于Implementing a codec wiki,则客户端会收到HTTP 500 - 内部服务器错误。响应正文还描述了以下异常:

    System.InvalidOperationException: The operation is not ready for invocation.
       at OpenRasta.OperationModel.MethodBased.MethodBasedOperation.Invoke()
       at OpenRasta.OperationModel.Interceptors.OperationWithInterceptors.<Invoke>b__0()
       at OpenRasta.OperationModel.Interceptors.OperationWithInterceptors.Invoke()
       at OpenRasta.OperationModel.OperationExecutor.Execute(IEnumerable`1 operations)
       at OpenRasta.Pipeline.Contributors.OperationInvokerContributor.ExecuteOperations(ICommunicationContext context)
       at OpenRasta.Pipeline.PipelineRunner.ExecuteContributor(ICommunicationContext context, ContributorCall call)
    

    我应该如何修改我的应用程序:

    • 客户端收到HTTP 400错误请求。
    • 客户端收到一个字符串,其中包含编解码器中遇到的异常的详细信息。

2 个答案:

答案 0 :(得分:3)

以上是上述答案的一个小变化 - 这次是根据操作结果数据选择编解码器。

IConfigurationSource内:

using (OpenRastaConfiguration.Manual)
{
    ResourceSpace.Uses.PipelineContributor<ErrorCheckingContributor>(); 

    ResourceSpace.Has.ResourcesOfType<ApplicationError>()
                 .WithoutUri
                 .TranscodedBy<ApplicationErrorCodec>();

                 // Or use a generic JSON serializer like this:
                 // .AsJsonDataContract();

    // Other configuration here
}

现在ErrorCheckingContributor看起来像这样:

public class ErrorCheckingContributor : IPipelineContributor
{
  public void Initialize(IPipeline pipelineRunner)
  {
    pipelineRunner
        .Notify(CheckRequestDecoding)
        .After<KnownStages.IOperationResultInvocation>()
        .And.Before<KnownStages.ICodecResponseSelection>();
  }

  private static PipelineContinuation CheckRequestDecoding(ICommunicationContext context)
  {
    if (context.ServerErrors.Count == 0)
    {
      return PipelineContinuation.Continue;
    }

    Error err = context.ServerErrors[0];

    // Get a suitable message (err.Message contains stack traces, so try to avoid that)
    string msg = err.Title;
    if (msg == null && err.Exception != null)
      msg = err.Exception.Message;
    if (msg == null)
      msg = err.Message;

    // Create instance of an error information resource which is specific for the application
    // - This one is rather simple and only contains a copy of the message
    ApplicationError error = new ApplicationError(msg);

    // Set operation result to be "400 Bad Request" and remove errors
    context.OperationResult = new OperationResult.BadRequest { ResponseResource = error };
    context.ServerErrors.Clear();

    // Render immediately without starting any handlers
    return PipelineContinuation.RenderNow;
  }
}

班级ApplicationError是:

public class ApplicationError
{
  public string Message { get; set; }

  public ApplicationError(string message)
  {
    Message = message;
  }
}

最后,我们需要ApplicationErrorCodec的编解码器ApplicationError。这与任何其他IMediaTypeWriter编解码器没有什么不同,但很大程度上取决于您预期的响应媒体类型。有关示例,请参阅https://github.com/openrasta/openrasta/wiki/Implementing-a-Codec

答案 1 :(得分:2)

在Google网上论坛上找到包含所有答案的this主题后,我当前的实现看起来像这样。

IConfigurationSource的实施中:

using (OpenRastaConfiguration.Manual)
{
    ResourceSpace.Uses.PipelineContributor<ErrorCheckingContributor>(); 

    // Other configuration here
}

然后ErrorCheckingContributor看起来像这样:

public class ErrorCheckingContributor : IPipelineContributor
{
    public void Initialize(IPipeline pipelineRunner)
    {
        pipelineRunner
            .Notify(CheckRequestDecoding)
            .After<KnownStages.IOperationResultInvocation>()
            .And.Before<KnownStages.ICodecResponseSelection>(); 
    }

    private static PipelineContinuation CheckRequestDecoding(ICommunicationContext context)
    {
        if (context.ServerErrors.Count == 0)
        {
            return PipelineContinuation.Continue;
        }

        var first = context.ServerErrors[0];
        if (first.Exception is Newtonsoft.Json.JsonReaderException)
        {
            context.Response.Entity.ContentType = MediaType.TextPlain;
            context.Response.Entity.ContentLength = first.Exception.Message.Length;
            using (var sw = new StreamWriter(context.Response.Entity.Stream))
            {
                sw.Write(first.Exception.Message);
            }
        }

        return PipelineContinuation.Continue;
    } 
}

上面有一些事情需要注意:

  • 如果处理程序要抛出JsonReaderException,它也会在此处理。
  • 它不会检查客户端接受的媒体类型。这与处理程序选择的处理程序抛出的异常不同。
  • 尝试将context.OperationResult设置为context.ServerErrors - 但它没有通过编解码器。