Negociação de conteúdo de Nancy

Nancy , a estrutura da web .NET leve, implementou recentemente a negociação automática de conteúdo na versão 0.12.0. Isso significa que você só precisa devolver seu modelo e Nancy fará a serialização com base no cabeçalho Aceitar fornecido com a solicitação. Petty cool. A documentação ainda não acompanhou o código, então pensei em escrever sobre uma ou duas coisas que precisava descobrir para fazer minha negociação automática funcionar bem.

Como funciona

Nancy registra algumas classes (XmlProcessor, JsonProcessor) que implementam IResponseProcessor. IResponseProcessors informam a Nancy se eles podem satisfazer um cabeçalho Aceitar específico (CanProcess) e como satisfazer esse cabeçalho (Processo). Quando uma solicitação chega, Nancy pergunta a cada IResponseProcessor se ele pode atender à solicitação, seleciona aqueles que podem e usa o primeiro para serializar a resposta.

Alterar o conteúdo de resposta padrão

Descobri que, se um cabeçalho Aceitar não for especificado, Nancy retornará JSON. Eu queria que isso fosse XML. O que realmente acontece quando um cabeçalho Accept não é especificado é que o cabeçalho Accept é alterado para “* / *”, portanto, todos os IResponseProcessors sinalizam que podem serializar a resposta. Portanto, tudo se resume ao pedido e à coleção IResponseProcessor. Felizmente, como a maioria das coisas em Nancy, os IResponseProcessors podem ser configurados.

Ao criar um bootstrapper personalizado, você pode substituir a ordem dos ResponseProcessors:

public class CustomResponseProcessorBootstrapper: DefaultNancyBootstrapper
{
protected override NancyInternalConfiguration InternalConfiguration
{
get
{
return NancyInternalConfiguration.WithOverrides((c) =>
{
c
.ResponseProcessors.Remove(typeof (JsonProcessor));
c
.ResponseProcessors.Insert(c.ResponseProcessors.Count, typeof(JsonProcessor));
});
}
}
}

Aqui, retirei o JsonProcessor que estava no topo da lista e o movi para o final.

editar 04/08/2013: Para melhor proteção contra alterações, provavelmente é melhor limpar a coleção ResponseProcessors e adicionar explicitamente exatamente quais processadores você deseja. Digo isso porque, desde que escrevi este post, Nancy incluiu um ViewProcessor que agora é o primeiro processador da lista.

Agora, quando um accept não tem um cabeçalho Accept, o XmlProcessor é escolhido primeiro. Você também pode ver o potencial aqui para adicionar facilmente seus próprios IResponseProcessors personalizados se XML ou JSON não forem sua preferência. Se você quiser mudar alguma coisa em Nancy, a NancyInternalConfiguration é sempre um bom lugar para começar. Como bônus, você pode fazer algo semelhante para trocar o serializador Json padrão (baseado em JavascriptSerializer) por Nancy.Serialization.JsonNet (baseado em JSON.Net):

public class CustomResponseProcessorBootstrapper: DefaultNancyBootstrapper
{
protected override NancyInternalConfiguration InternalConfiguration
{
get
{
return NancyInternalConfiguration.WithOverrides((c) =>
{
c
.Serializers.Remove(typeof (DefaultJsonSerializer));
c
.Serializers.Insert(c.Serializers.Count, typeof(JsonNetSerializer));

c
.ResponseProcessors.Remove(typeof (JsonProcessor));
c
.ResponseProcessors.Insert(c.ResponseProcessors.Count, typeof(JsonProcessor));
});
}
}
}

A propósito, seu bootstrapper personalizado será selecionado automaticamente.

Mudando a resposta

Antes da negociação automática de conteúdo, você retornaria um objeto de resposta, definindo propriedades como o código de status http:

return new Response
{
StatusCode = HttpStatusCode.OK
ContentType = "text/html",
Contents = StreamText(message)
};

Ao permitir que Nancy lide com a negociação de conteúdo retornando um objeto, você também está permitindo que ela lide com o objeto de resposta. Por padrão, o código de resposta será 200 ok. Você pode substituir isso ligando para o negociador:

return Negotiate
.WithModel(model)
.WithStatusCode(HttpStatusCode.BadRequest)

Existem também vários outros métodos que devem permitir que você modifique a resposta para o que quiser. Aqui está um exemplo retirado das demonstrações de Nancy :

public MainModule(IRouteCacheProvider routeCacheProvider)
{
Get["/negotiated"] = parameters => {
return Negotiate
.WithModel(new RatPack {FirstName = "Nancy "})
.WithMediaRangeModel("text/html", new RatPack {FirstName = "Nancy fancy pants"})
.WithView("negotiatedview")
.WithHeader("X-Custom", "SomeValue");
};
}

Eu sou novo em Nancy, mas tenho gostado de usá-lo até agora. Você pode colocar uma API em funcionamento muito rapidamente e pode estendê-la ou configurá-la quando precisar. A negociação automática de conteúdo se encaixa perfeitamente nesse estilo.