Estou tentando ler o corpo da solicitação no OnActionExecuting
método, mas sempre consigo null
pelo corpo.
var request = context.HttpContext.Request;
var stream = new StreamReader(request.Body);
var body = stream.ReadToEnd();
Tentei definir explicitamente a posição do fluxo para 0, mas também não funcionou. Como este é o ASP.NET CORE, as coisas são um pouco diferentes, eu acho. Posso ver todos os exemplos aqui referentes a versões antigas do webapi.
Existe alguma outra maneira de fazer isso?
c#
asp.net-web-api
asp.net-core
Kasun Koswattha
fonte
fonte
Respostas:
No ASP.Net Core parece complicado ler várias vezes a solicitação do corpo, porém se sua primeira tentativa for da maneira certa, você deve estar bem para as próximas tentativas.
Eu li várias reviravoltas, por exemplo, substituindo o fluxo do corpo, mas acho que o seguinte é o mais limpo:
Os pontos mais importantes são
[EDITAR]
Conforme apontado por Murad, você também pode aproveitar a extensão .Net Core 2.1:
EnableBuffering
ela armazena grandes solicitações no disco em vez de mantê-lo na memória, evitando problemas de streams grandes armazenados na memória (arquivos, imagens, ...) . Você pode alterar a pasta temporária definindoASPNETCORE_TEMP
a variável de ambiente e os arquivos são excluídos assim que a solicitação terminar.Em um AuthorizationFilter , você pode fazer o seguinte:
Em seguida, você pode usar o corpo novamente no manipulador de solicitação.
No seu caso, se você obtiver um resultado nulo, provavelmente significa que o corpo já foi lido em um estágio anterior. Nesse caso, você pode precisar usar um middleware (veja abaixo).
No entanto, tenha cuidado ao lidar com grandes fluxos, esse comportamento implica que tudo é carregado na memória, isso não deve ser acionado no caso de um upload de arquivo.
Você pode querer usar isto como um Middleware
O meu se parece com isto (novamente, se você fizer download / upload de arquivos grandes, isso deve ser desativado para evitar problemas de memória):
fonte
req.EnableRewind();
? Eu uso o código acima e funciona bem.request.EnableBuffering()
(wrapper overEnableRewind()
) Ele está disponível no ASP.NET Core 2.1 docs.microsoft.com/en-us/dotnet/api/…Uma solução mais clara, funciona em ASP.Net Core 2.1 / 3.1
Classe de filtro
Em um controlador
fonte
.EnableRewind()
AuthorizeAttribute
paraAttribute
(no ASP.Net Core 3.1).Para poder retroceder o corpo do pedido, a resposta de @Jean me ajudou a encontrar uma solução que parece funcionar bem. Atualmente, eu uso isso para Global Exception Handler Middleware, mas o princípio é o mesmo.
Criei um middleware que basicamente permite o retrocesso no corpo da solicitação (em vez de um decorador).
Isso pode ser usado da seguinte
Startup.cs
maneira:Usando essa abordagem, consegui retroceder o fluxo do corpo da solicitação com êxito.
fonte
UseEnableRequestRewind(this IApplicationBuilder builder)
.Este é um tópico um pouco antigo, mas desde que cheguei aqui, decidi postar minhas descobertas para que possam ajudar outras pessoas.
Primeiro, eu tive o mesmo problema, onde eu queria pegar o Request.Body e fazer algo com ele (registro / auditoria). Mas, caso contrário, eu queria que o ponto final fosse o mesmo.
Portanto, parecia que a chamada EnableBuffering () poderia resolver o problema. Então você pode fazer uma busca (0, xxx) no corpo e reler o conteúdo, etc.
No entanto, isso levou ao meu próximo problema. Eu obteria exceções "Operações síncronas não são permitidas" ao acessar o ponto de extremidade. Portanto, a solução alternativa é definir a propriedade AllowSynchronousIO = true, nas opções. Existem várias maneiras de fazer isso (mas não é importante detalhar aqui ..)
ENTÃO, o próximo problema é que quando vou ler o Request.Body ele já foi descartado. Ugh. Então, o que aconteceu?
Estou usando o Newtonsoft.JSON como meu analisador [FromBody] na chamada do endpiont. Isso é o que é responsável pelas leituras síncronas e também fecha o fluxo quando é concluído. Solução? Leia o fluxo antes de chegar à análise JSON? Claro, isso funciona e acabei com o seguinte:
Agora, posso acessar o corpo usando HttpContext.Items ["request_body"] nos pontos de extremidade que têm o atributo [ReadRequestBodyIntoItems].
Mas cara, isso parece muitos obstáculos para pular. Então foi aqui que eu terminei e estou muito feliz com isso.
Meu endpoint começou como algo como:
Mas é muito mais simples apenas alterar a assinatura, assim:
Eu realmente gostei disso porque ele lê o fluxo do corpo apenas uma vez e eu tenho o controle da desserialização. Claro, é bom se o ASP.NET core fizer essa mágica para mim, mas aqui não perco tempo lendo o fluxo duas vezes (talvez armazenando em buffer a cada vez) e o código é bastante claro e limpo.
Se você precisar dessa funcionalidade em muitos terminais, talvez as abordagens de middleware possam ser mais limpas ou você pode pelo menos encapsular a extração do corpo em uma função de extensão para tornar o código mais conciso.
De qualquer forma, não encontrei nenhuma fonte que abordasse todos os 3 aspectos desse assunto, daí este post. Espero que isso ajude alguém!
BTW: isso estava usando ASP .NET Core 3.1.
fonte
Tive um problema semelhante ao usar o ASP.NET Core 2.1:
SaoBiz
por apontar esta solução.Portanto, a solução óbvia é permitir que a solicitação seja rebobinada, mas certifique-se de que, após a leitura do corpo, a vinculação ainda funcione.
EnableRequestRewindMiddleware
Startup.cs
(coloque isso no início do método de configuração)
Algum outro middleware
Isso é parte do middleware que requer a descompactação das informações do POST para verificação.
fonte
Recentemente me deparei com uma solução muito elegante que pega em JSON aleatório da qual você não tem ideia da estrutura:
Simples assim.
fonte
O
IHttpContextAccessor
método funciona se você quiser seguir esse caminho.TLDR;
Injetar o
IHttpContextAccessor
Retroceder -
HttpContextAccessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);
Ler --
System.IO.StreamReader sr = new System.IO.StreamReader(HttpContextAccessor.HttpContext.Request.Body); JObject asObj = JObject.Parse(sr.ReadToEnd());
Mais - uma tentativa de um exemplo conciso e não compilador dos itens que você precisa garantir que estejam no lugar para chegar a um utilizável
IHttpContextAccessor
. As respostas indicaram corretamente que você precisará voltar ao início ao tentar ler o corpo da solicitação. ACanSeek
,Position
propriedades no corpo da solicitação transmitir útil para verificar isso.Documentos DI do .NET Core
fonte
Consegui ler o corpo da solicitação em um aplicativo asp.net core 3.1 como este (junto com um middleware simples que permite o armazenamento em buffer - o retrocesso habilitado parece estar funcionando para versões anteriores do .Net Core-):
fonte
para leitura
Body
, você pode ler de forma assíncrona.use o
async
método a seguir:Teste com carteiro:
Está funcionando bem e testado na
Asp.net core
versão2.0 , 2.1 , 2.2, 3.0
.Espero que seja útil.
fonte
Eu também queria ler o Request.Body sem mapeá-lo automaticamente para algum modelo de parâmetro de ação. Testei de várias maneiras diferentes antes de resolver isso. E não encontrei nenhuma solução funcional aqui descrita. Esta solução é atualmente baseada na estrutura do .NET Core 3.0.
reader.readToEnd () parece uma maneira simples, embora tenha compilado, ele lançou uma exceção de tempo de execução que exigia que eu usasse uma chamada assíncrona. Então, em vez disso, usei ReadToEndAsync (), mas funcionou às vezes e às vezes não. Apresentando erros como, não consigo ler depois que o fluxo é fechado. O problema é que não podemos garantir que ele retornará o resultado no mesmo thread (mesmo se usarmos o await). Portanto, precisamos de algum tipo de retorno de chamada. Essa solução funcionou para mim.
fonte
A maneira mais simples possível de fazer isso é a seguinte:
No método Controller de onde você precisa extrair o corpo, adicione este parâmetro: [FromBody] SomeClass value
Declare o "SomeClass" como: class SomeClass {public string SomeParameter {get; conjunto; }}
Quando o corpo bruto é enviado como json, o .net core sabe como lê-lo com muita facilidade.
fonte
Para aqueles que simplesmente desejam obter o conteúdo (corpo da solicitação) da solicitação:
Use o
[FromBody]
atributo em seu parâmetro de método do controlador.Como diz o doc: este atributo especifica que um parâmetro ou propriedade deve ser vinculado usando o corpo da solicitação.
fonte
Uma maneira rápida de adicionar buffer de resposta no .NET Core 3.1 é
em Startup.cs. Descobri que isso também garante que o buffer será habilitado antes que o stream seja lido, o que era um problema para o .Net Core 3.1 com algumas das outras respostas de filtro de middleware / autorização que vi.
Em seguida, você pode ler o corpo da solicitação via
HttpContext.Request.Body
em seu manipulador, como vários outros sugeriram.Também vale a pena considerar que
EnableBuffering
tem sobrecargas que permitem limitar o quanto ele armazenará em buffer na memória antes de usar um arquivo temporário, e também um limite geral para o buffer. NB, se uma solicitação exceder esse limite, uma exceção será lançada e a solicitação nunca chegará ao seu manipulador.fonte