如何从南希谈判的回应? [英] How to get a response from the Nancy Negotiator?

查看:182
本文介绍了如何从南希谈判的回应?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 NancyContext ,我需要获得响应基于正确的内容谈判代表体该请求。我想我可以使用南希的谈判代表类以添加一个模型,设置状态,和其他的东西。但后来,我需要返回响应的子类型。 ?所以,我可以用使用谈判代表



来构建响应

下面是我的方法:



<预类=郎-CS prettyprint-覆盖> 公开回应ConvertToHttpResponse(例外的例外,NancyContext上下文)
{
变种谈判代表=新谈判代表(上下文)
.WithStatusCode(HttpStatusCode.BadRequest)
.WithReasonPhrase(exception.Message);

返回???;
}


解决方案

我个人更喜欢使用南希谈判代表返回快乐路径结果只(即视图/ jsondto收益),然后返回香草南希响应对象中可能出现的任何错误。



的一种方式这样做将是直接在模块内返回的错误,为例如:

 公共类ProductsModule:NancyModule 
{
公共ProductsModule()
:基地(/产品)
{
获得[/产品/ {}的ProductID] = _ =>
{
VAR请求= this.Bind< ProductRequest>();

变种产品= ProductRepository.GetById(request.ProductId);

如果(产品== NULL)
{
VAR误差=新的响应();
error.StatusCode = HttpStatusCode.BadRequest;
error.ReasonPhrase =无效的产品标识。
返回错误;
}

VAR用户= UserRepository.GetCurrentUser();

如果(假== user.CanView(产品))
{
VAR误差=新的响应();
error.StatusCode = HttpStatusCode.Unauthorized;
error.ReasonPhrase =用户没有足够的权限。
返回错误;
}

VAR productDto = CreateProductDto(产品);

变种htmlDto =新的{
产品= productDto,
RelatedProducts = GetRelatedProductsDto(产品)
};

返回协商
.WithAllowedMediaRange(MediaRange.FromString(text / html的))
.WithAllowedMediaRange(MediaRange.FromString(应用/ JSON))
.WithModel(htmlDto)//为text / html的'
.WithMediaRangeModel模型(
MediaRange.FromString(应用/ JSON),
productDto); //为应用/ JSON模式;
}
}
}

这可以得到相当混乱,虽然。我首选的方法是建立我的错误处理曾经我南希模块引导程序中,并将它捉知/预期的异常,并与相应的响​​应对象归还。



一bootrapper配置为一个简单的例子是:

 公共类MyNancyBootstrapper:DefaultNancyBootstrapper 
{
保护覆盖无效ApplicationStartup(
TinyIoCContainer容器,管道IPipelines)
{
base.ApplicationStartup(容器,管道);

//注册自定义异常处理程序。
pipelines.OnError + =(CTX,ERR)=> HandleExceptions(ERR,CTX); ;
}

私有静态响应HandleExceptions(异常错误,NancyContext CTX)
{
VAR的结果=新的响应();

result.ReasonPhrase = err.Message;

如果(ERR是NotImplementedException)
{
result.StatusCode = HttpStatusCode.NotImplemented;
}
,否则如果(ERR是UnauthorizedAccessException)
{
result.StatusCode = HttpStatusCode.Unauthorized;
}
,否则如果(ERR是ArgumentException的)
{
result.StatusCode = HttpStatusCode.BadRequest;
}
,否则
{
//发生意外的异常!
result.StatusCode = HttpStatusCode.InternalServerError;
}

返回结果;
}
}



利用这一点,可以重构模块,简单地抛出适当的异常,这将调用正确的响应类型。你就可以开始创建一个漂亮的一套标准,在这方面您的API。这方面的一个例子是:



 公共类ProductsModule:NancyModule 
{
公共ProductsModule()$ b $ A:基地(/产品)
{
获得[/产品/ {}的ProductID] = _ =>
{
VAR请求= this.Bind< ProductRequest>();

变种产品= ProductRepository.GetById(request.ProductId);

如果(产品== NULL)
{
抛出新的ArgumentException(
无效的产品标识。);
}

VAR用户= UserRepository.GetCurrentUser();

如果(假== user.CanView(产品))
{
抛出新UnauthorizedAccessException(
的用户没有足够的权限。);
}

VAR productDto = CreateProductDto(产品);

变种htmlDto =新的{
产品= productDto,
RelatedProducts = GetRelatedProductsDto(产品)
};

返回协商
.WithAllowedMediaRange(MediaRange.FromString(text / html的))
.WithAllowedMediaRange(MediaRange.FromString(应用/ JSON))
.WithModel(htmlDto)//为text / html的'
.WithMediaRangeModel模型(
MediaRange.FromString(应用/ JSON),
productDto); //为应用/ JSON模式;
}
}
}

这感觉比较清爽,干净给我,现在我介绍了一组标准纳入我的模块。 :)






别的东西,你可以考虑做,它可以在开发过程中特别有用。将附上一个完整的异常报告。你的错误响应对象的内容结果



这方面的一个基本的例子是:

  result.Contents = responseStream => 
{
串errorBody =的String.Format(
@< HTML>
< HEAD>
<标题>异常报告和LT; /标题>
< /头>
<身体GT;
< H1> {0}< / H1>
< p> {1}< / p>
< /身体GT;
< / HTML>中,
ex.Message,
ex.StackTrace);

//转换错误流并复制到响应流
变种的字节数组= Encoding.UTF8.GetBytes(errorBody);
使用(VAR errorStream =新的MemoryStream(字节阵列))
{
errorStream.CopyTo(responseStream);
}
}



同样,这仅仅是一个非常基本的,说明性的例子,你必须决定它是否适合你的解决方案,然后在其上展开。


I have a NancyContext and I need to get a Response with a body based on the correct content negotiator for the request. I think I can use Nancy's Negotiator class to add a model, set the status, and other things. But then, I need to return a subtype of Response. So, what can I use to build the response using the Negotiator?

Here's my method:

public Response ConvertToHttpResponse(Exception exception, NancyContext context)
{
    var negotiator = new Negotiator(context)
        .WithStatusCode(HttpStatusCode.BadRequest)
        .WithReasonPhrase(exception.Message);

    return ???;
}

解决方案

I personally prefer to use the Nancy negotiator to return "Happy Path" results only (i.e. the view/jsondto returns), and then return vanilla nancy Response objects for any errors that may occur.

One way of doing this would be to return the errors directly within your module, for e.g.:

public class ProductsModule : NancyModule
{
    public ProductsModule()
        : base("/products")
    {
        Get["/product/{productid}"] = _ => 
        {
            var request = this.Bind<ProductRequest>();

            var product = ProductRepository.GetById(request.ProductId);

            if (product == null)
            {
                var error = new Response();
                error.StatusCode = HttpStatusCode.BadRequest;
                error.ReasonPhrase = "Invalid product identifier.";
                return error;
            }

            var user = UserRepository.GetCurrentUser();

            if (false == user.CanView(product))
            {
                var error = new Response();
                error.StatusCode = HttpStatusCode.Unauthorized;
                error.ReasonPhrase = "User has insufficient privileges.";
                return error;
            }

            var productDto = CreateProductDto(product);

            var htmlDto = new {
              Product = productDto,
              RelatedProducts = GetRelatedProductsDto(product)
            };

            return Negotiate
                    .WithAllowedMediaRange(MediaRange.FromString("text/html"))
                    .WithAllowedMediaRange(MediaRange.FromString("application/json"))
                    .WithModel(htmlDto)  // Model for 'text/html'
                    .WithMediaRangeModel(
                          MediaRange.FromString("application/json"), 
                          productDto); // Model for 'application/json';
        }
    }
}

This can get pretty messy though. My preferred approach is to set up my error handling "once" within my Nancy module bootstrapper, and have it catch known/expected exceptions and return them with the appropriate response object.

A simple example of a bootrapper configuration for this could be:

public class MyNancyBootstrapper : DefaultNancyBootstrapper
{
    protected override void ApplicationStartup(
        TinyIoCContainer container, IPipelines pipelines)
    {
        base.ApplicationStartup(container, pipelines);

        // Register the custom exceptions handler.
        pipelines.OnError += (ctx, err) => HandleExceptions(err, ctx); ;
    }

    private static Response HandleExceptions(Exception err, NancyContext ctx)
    {
        var result = new Response();

        result.ReasonPhrase = err.Message;

        if (err is NotImplementedException)
        {
            result.StatusCode = HttpStatusCode.NotImplemented;
        }
        else if (err is UnauthorizedAccessException)
        {
            result.StatusCode = HttpStatusCode.Unauthorized;
        }
        else if (err is ArgumentException)
        {
            result.StatusCode = HttpStatusCode.BadRequest;
        }
        else
        {
            // An unexpected exception occurred!
            result.StatusCode = HttpStatusCode.InternalServerError;    
        }

        return result;
    }
}

Using this, you can refactor your module to simply throw the appropriate exception which will invoke the correct response type. You can start to create a nice set of standards for your API in this respect. An example of this would be:

public class ProductsModule : NancyModule
{
    public ProductsModule()
        : base("/products")
    {
        Get["/product/{productid}"] = _ => 
        {
            var request = this.Bind<ProductRequest>();

            var product = ProductRepository.GetById(request.ProductId);

            if (product == null)
            {
                throw new ArgumentException(
                    "Invalid product identifier.");
            }

            var user = UserRepository.GetCurrentUser();

            if (false == user.CanView(product))
            {
                throw new UnauthorizedAccessException(
                    "User has insufficient privileges.");
            }

            var productDto = CreateProductDto(product);

            var htmlDto = new {
              Product = productDto,
              RelatedProducts = GetRelatedProductsDto(product)
            };

            return Negotiate
                    .WithAllowedMediaRange(MediaRange.FromString("text/html"))
                    .WithAllowedMediaRange(MediaRange.FromString("application/json"))
                    .WithModel(htmlDto)  // Model for 'text/html'
                    .WithMediaRangeModel(
                          MediaRange.FromString("application/json"), 
                          productDto); // Model for 'application/json';
        }
    }
}

This feels slightly cleaner to me, and now I am introducing a set of standards into my modules. :)


Something else you could consider doing, which can be especially helpful during development would be to attach a full exception report to the Content result of your error Response objects.

A basic example of this would be:

result.Contents = responseStream =>
    {
        string errorBody = string.Format(
            @"<html>
                <head>
                    <title>Exception report</title>
                </head>
                <body>
                    <h1>{0}</h1>
                    <p>{1}</p>
                </body>
              </html>",
            ex.Message,
            ex.StackTrace);

        // convert error to stream and copy to response stream
        var byteArray = Encoding.UTF8.GetBytes(errorBody);
        using (var errorStream = new MemoryStream(byteArray))
        {
            errorStream.CopyTo(responseStream);
        }
    }

Again, this is just a very basic, illustrative example, and you would have to decide if it is appropriate to your solution and then expand upon it.

这篇关于如何从南希谈判的回应?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆