开发者

Set the HTTP status code from an IOperationInterceptor in OpenRasta

I've written an ExceptionInterceptor that wraps the operation invocation in a try/catch to have centralized exception handling. What I also want to do is have centralized HTTP status code handling, but I seem to be unable to set the HTTP status code from within my IOperationInterceptor. My Interceptor takes ICommunicationContext as a dependency and se开发者_JAVA技巧ts its OperationResult to e.g. OperationResult.BadRequest, but OpenRasta still writes the following to the log:

Step into: Stepping over non-user code 'OpenRasta.Pipeline.PipelineRunner.RunCallGraph'
    38-[2011-07-08 09:11:37Z] Start(1) Entering PipelineRunner: Executing contributor OperationResultInvokerContributor.RunOperationResult
        38-[2011-07-08 09:11:37Z] Information(0) Executing OperationResult OperationResult: type=OK, statusCode=200.

I've also tried setting the IResponse.StatusCode explicitly, but it has no effect. It seems that because the ResponseResource I want to respond with is a valid resource registered in ResourceSpace (though without a URI), the status code is ignored and the regular rendering pipeline thrusts forward thinking "this looks okay".

Why is OpenRasta ignoring my StatusCode?


After some more digging I figured out that you can't override the HTTP status code directly from an IOperationInterceptor. Instead, you need to store whatever data you need in the ICommunicationContext.PipelineData collection from wherever makes sense in your IOperationInterceptor implementation. I, for instance, have the following BeforeExecute implementation:

public bool BeforeExecute(IOperation operation)
{
    if (operation.Inputs.Count() > 0)
        this.inputMember = operation.Inputs.First();

    return true;
}

Setting the inputMember in BeforeExecute allows me to retrieve the entity (received via HTTP POST or PUT) via this.inputMember.Binder.BuildObject().Instance as well as yielding a new OutputMember in the RewriteOperation method.

When you have stored all the data you want inside ICommunicationContext.PipelineData you can then go on to handle stored data and respond accordingly inside an IPipelineContributor implementation. You do this by subscribing to the After<KnownStages.IOperationExecution>() event like so:

public void Initialize(IPipeline pipelineRunner)
{
    pipelineRunner
        .Notify(RenderOnException)
        .After<KnownStages.IOperationExecution>();
}

The RenderOnException method looks like this:

private static PipelineContinuation RenderOnException(ICommunicationContext context)
{
    if (!context.PipelineData.ContainsKey(ExceptionInterceptor.Key))
        return PipelineContinuation.Continue;

    var interestingDataStoredByTheOperationInterceptorImplementation =
        context.PipelineData["SomeKey"];

    // Set context.OperationResult to something meaningful.

    // Instruct the pipeline to render now
    return PipelineContinuation.RenderNow;
}

While this might not be the best way to implement this, it works and ends up making the individual Handler methods thin and focused on the problem they are solving. Instead of returning OperationResults left and right, Handler methods can now throw regular exceptions that my IOperationInterceptor implementation will catch and then my IPipelineContributor implementation can override the OperationResult with an appropriate response.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜