OnActionExecuting
メソッドでリクエストの本文を読み取ろうとしていますが、私は常にnull
を取得しています。
var request = context.HttpContext.Request;
var stream = new StreamReader(request.Body);
var body = stream.ReadToEnd();
ストリームの位置を明示的に0に設定しようとしましたが、それも機能しませんでした。これはASP.NET COREなので、物事は少し違うと思います。ここでは、古いwebapiバージョンを参照するすべてのサンプルを見ることができます。
これを行う他の方法はありますか?
リクエスト本文を巻き戻すことができるようにするために、@ Jeanの答えは私がうまくいくと思われる解決策を思い付くのに役立ちました。現在、これをグローバル例外ハンドラミドルウェアに使用していますが、原理は同じです。
(デコレータの代わりに)基本的にリクエスト本文の巻き戻しを可能にするミドルウェアを作成しました。
using Microsoft.AspNetCore.Http.Internal;
[...]
public class EnableRequestRewindMiddleware
{
private readonly RequestDelegate _next;
public EnableRequestRewindMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
context.Request.EnableRewind();
await _next(context);
}
}
public static class EnableRequestRewindExtension
{
public static IApplicationBuilder UseEnableRequestRewind(this IApplicationBuilder builder)
{
return builder.UseMiddleware<EnableRequestRewindMiddleware>();
}
}
これは、次のようにStartup.cs
で使用できます。
[...]
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
[...]
app.UseEnableRequestRewind();
[...]
}
このアプローチを使用して、リクエスト本文ストリームを正常に巻き戻すことができました。
より明確なソリューションは、ASP.Net Core 2.1で動作します。
フィルタークラス
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http.Internal;
using Microsoft.AspNetCore.Mvc.Filters;
public class ReadableBodyStreamAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
context.HttpContext.Request.EnableRewind();
}
}
コントローラー内
[HttpPost]
[ReadableBodyStream]
public string SomePostMethod()
{
using (StreamReader stream = new StreamReader(HttpContext.Request.Body))
{
string body = stream.ReadToEnd();
// body = "param=somevalue¶m2=someothervalue"
}
}
このルートを使用する場合、IHttpContextAccessor
メソッドは機能します。
TLDR;
IHttpContextAccessor
を注入します
巻き戻し-HttpContextAccessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);
読み取り-System.IO.StreamReader sr = new System.IO.StreamReader(HttpContextAccessor.HttpContext.Request.Body); JObject asObj = JObject.Parse(sr.ReadToEnd());
More-確実にコンパイルする必要のあるアイテムの例。使用可能なIHttpContextAccessor
。リクエストの本文を読み込もうとすると、最初に戻ってシークする必要があるという回答が正しく指摘されています。これを確認するのに役立つ、リクエストボディストリームのCanSeek
、Position
プロパティ。
// First -- Make the accessor DI available
//
// Add an IHttpContextAccessor to your ConfigureServices method, found by default
// in your Startup.cs file:
// Extraneous junk removed for some brevity:
public void ConfigureServices(IServiceCollection services)
{
// Typical items found in ConfigureServices:
services.AddMvc(config => { config.Filters.Add(typeof(ExceptionFilterAttribute)); });
// ...
// Add or ensure that an IHttpContextAccessor is available within your Dependency Injection container
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}
// Second -- Inject the accessor
//
// Elsewhere in the constructor of a class in which you want
// to access the incoming Http request, typically
// in a controller class of yours:
public class MyResourceController : Controller
{
public ILogger<PricesController> Logger { get; }
public IHttpContextAccessor HttpContextAccessor { get; }
public CommandController(
ILogger<CommandController> logger,
IHttpContextAccessor httpContextAccessor)
{
Logger = logger;
HttpContextAccessor = httpContextAccessor;
}
// ...
// Lastly -- a typical use
[Route("command/resource-a/{id}")]
[HttpPut]
public ObjectResult PutUpdate([FromRoute] string id, [FromBody] ModelObject requestModel)
{
if (HttpContextAccessor.HttpContext.Request.Body.CanSeek)
{
HttpContextAccessor.HttpContext.Request.Body.Seek(0, System.IO.SeekOrigin.Begin);
System.IO.StreamReader sr = new System.IO.StreamReader(HttpContextAccessor.HttpContext.Request.Body);
JObject asObj = JObject.Parse(sr.ReadToEnd());
var keyVal = asObj.ContainsKey("key-a");
}
}
}