C# 如何从谈判代表那里得到回应?

C# 如何从谈判代表那里得到回应?,c#,nancy,content-negotiation,C#,Nancy,Content Negotiation,我有一个NancyContext,我需要得到一个响应,其主体基于请求的正确内容谈判者。我想我可以使用Nancy的协商者类来添加模型、设置状态以及其他事情。但是,我需要返回Response的子类型。那么,我可以用什么来使用谈判者构建响应呢 以下是我的方法: 公共响应ConvertToHttpResponse(异常,NancyContext上下文) { 风险值谈判者=新谈判者(上下文) .WithStatusCode(HttpStatusCode.BadRequest) .WithReasonPhr

我有一个
NancyContext
,我需要得到一个
响应
,其主体基于请求的正确内容谈判者。我想我可以使用Nancy的协商者类来添加模型、设置状态以及其他事情。但是,我需要返回
Response
的子类型。那么,我可以用什么来使用
谈判者构建响应呢

以下是我的方法:

公共响应ConvertToHttpResponse(异常,NancyContext上下文)
{
风险值谈判者=新谈判者(上下文)
.WithStatusCode(HttpStatusCode.BadRequest)
.WithReasonPhrase(异常消息);
返回???;
}

我个人更喜欢使用Nancy谈判者只返回“快乐路径”结果(即视图/jsondto返回),然后返回可能发生的任何错误的响应对象

一种方法是直接在模块中返回错误,例如:

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';
        }
    }
}
使用此方法,您可以重构模块,只需抛出适当的异常即可调用正确的响应类型。在这方面,您可以开始为您的API创建一套很好的标准。这方面的一个例子是:

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';
        }
    }
}
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);
        }
    }
公共类产品模块:NancyModule
{
公共产品模块()
:基本(“/产品”)
{
获取[“/product/{productid}”]=\u=>
{
var request=this.Bind();
var product=ProductRepository.GetById(request.ProductId);
如果(产品==null)
{
抛出新的ArgumentException(
“无效的产品标识符。”);
}
var user=UserRepository.GetCurrentUser();
if(false==user.CanView(产品))
{
抛出新的UnauthorizedAccessException(
“用户没有足够的权限。”);
}
var productDto=CreateProductDto(产品);
var htmlDto=new{
Product=productDto,
RelatedProducts=GetRelatedProductsTo(产品)
};
返回谈判
.WithAllowedMediaRange(MediaRange.FromString(“text/html”))
.WithAllowedMediaRange(MediaRange.FromString(“应用程序/json”))
.WithModel(htmlDto)//文本/html的模型
.WithMediaRangeModel(
MediaRange.FromString(“应用程序/json”),
productDto);//应用程序/json的模型;
}
}
}
这让我感觉稍微干净了一点,现在我在我的模块中引入了一套标准。:)


<>您可以考虑在开发过程中特别有用的是将完整异常报告附加到错误响应对象的内容结果。

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

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';
        }
    }
}
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);
        }
    }
result.Contents=responseStream=>
{
string errorBody=string.Format(
@"
异常报告
{0}
{1}

", 例如,信息, 例如StackTrace); //将错误转换为流并复制到响应流 var byteArray=Encoding.UTF8.GetBytes(errorBody); 使用(var errorStream=newmemoryStream(byteArray)) { errorStream.CopyTo(responseStream); } }

同样,这只是一个非常基本的说明性示例,您必须确定它是否适合您的解决方案,然后对其进行扩展。

根据您的代码示例,这里有一种可能的方法:

public Response ConvertToHttpResponse(Exception exception, NancyContext context, IEnumerable<IResponseProcessor> processors, Nancy.Conventions.AcceptHeaderCoercionConventions coercionConventions)
{
    var negotiator = new Negotiator(context)
        .WithStatusCode(HttpStatusCode.BadRequest)
        .WithReasonPhrase(exception.Message);

    return new DefaultResponseNegotiator(processors, coercionConventions)
        .NegotiateResponse(negotiator, context);
}

您好,请看一下“控制谈判”一节。第二段建议你将谈判代表本人退回。我100%同意你的看法,@sean,关于抛出例外。实际上我就是这样做的,但我试图将异常处理程序提取到服务中,并且在协商错误响应的内容类型时遇到了问题。如果内容类型是json,我想将错误响应返回为json。html或xml也是如此。所以,这就是为什么我最初问的是关于谈判人员的问题。虽然我喜欢你的答案,但我不能接受,因为它没有回答最初的问题。我只是自己研究一下,因为我目前正在做这件事,为坏请求抛出异常,但我想象,随着我的API的扩展,这可能是坏的,如果客户机有一个失控的进程,发出很多坏请求,也许它能让我的服务器屈服。因此,我试图找到一种优雅的方法来做类似的事情,但不抛出异常。