Search code examples
jsonlambdanancyonerror

Nancy OnError will not accept a Response object?


The Nancy documentation seems to say that Pipelines.OnError should return null - as opposed to BeforeResponse which allows both null and a Response object.

All the examples like this one and many code samples here on StackOverflow show a Response being returned in the OnError, just like in the BeforeRequest.

When I attempt to return an HTTPStatus string for the Pipelines.OnError, everything works OK!

But when I attempt to return a Response, I get a compiler error: Operator '+=' cannot be applied to operands of type 'Nancy.ErrorPipeline' and 'lambda expression'

I'm emulating almost exactly the code in the Nancy example, except for the fact that mine is a TinyIocContainer while the example's is using a StructureMap container and a StructureMap derived bootstrapper

Here's my code:

    const string errKey = "My proj error";
    const string creationProblem = "Message creation (HTTP-POST)";
    const string retrievalProblem = "Message retrieval (HTTP-GET)";

    public void Initialize(IPipelines pipelines)
    {
        string jsonContentType = "application/json";
        byte[] jsonFailedCreate = toJsonByteArray(creationProblem);
        byte[] jsonFailedRetrieve = toJsonByteArray(retrievalProblem);

        Response responseFailedCreate = new Response
        {
            StatusCode = HttpStatusCode.NotModified,
            ContentType = jsonContentType,
            Contents = (stream) => 
                stream.Write(jsonFailedCreate, 0, jsonFailedCreate.Length)
        };

        Response responseFailedRetrieve = new Response
        {
            StatusCode = HttpStatusCode.NotFound,
            ContentType = jsonContentType, 
            Contents = (stream) => 
                stream.Write(jsonFailedRetrieve, 0, jsonFailedRetrieve.Length)
        };

        // POST - error in Create call
        pipelines.OnError += (context, exception) =>
            {
                // POST - error during Create call
                if (context.Request.Method == "POST")
                    return responsefailedCreate;

                // GET - error during Retrieve call
                else if (context.Request.Method == "GET")
                    return responseFailedRetrieve;

                // All other cases - not supported
                else
                    return HttpStatusCode.InternalServerError;
            };
    }


    private byte[] toJsonByteArray(string plainString)
    {
        string jsonString = new JObject { { errKey, plainString } }.ToString();
        byte[] result = Encoding.UTF8.GetBytes(jsonString);
        return result;
    }

Solution

  • I had the same problem and I found a nice approach to the problem: http://paulstovell.com/blog/consistent-error-handling-with-nancy.

    you should override RequestStartup on the Bootstrapper, here my test code:

        protected override void RequestStartup(TinyIoCContainer container, IPipelines pipelines, NancyContext context)
        {           
            pipelines.OnError.AddItemToEndOfPipeline((ctx, ex) =>
                {                                       
                    DefaultJsonSerializer serializer = new DefaultJsonSerializer();
                    Response error = new JsonResponse(ex.Message,serializer);
                    error.StatusCode = HttpStatusCode.InternalServerError;
                    return error;
                });                 
    
            base.RequestStartup(container, pipelines, context);
        }