Bu biraz eski bir konu, ama buraya geldiğimden beri, bulgularımı başkalarına yardımcı olabilmeleri için göndereceğimi düşündüm.
İlk olarak, Request.Body'yi almak ve bununla bir şeyler yapmak istediğimde aynı sorunu yaşadım (kayıt / denetleme). Ama aksi halde uç noktanın aynı görünmesini istedim.
Dolayısıyla, EnableBuffering () çağrısı hile yapabilir gibi görünüyordu. Daha sonra gövde üzerinde bir Arama (0, xxx) yapabilir ve içeriği vb. Yeniden okuyabilirsiniz.
Ancak bu, bir sonraki sorunuma yol açtı. Uç noktaya erişirken "Eşzamanlı işlemlere izin verilmiyor" istisnaları alıyorum. Dolayısıyla, çözüm, seçeneklerde AllowSynchronousIO = true özelliğini ayarlamaktır. Bunu gerçekleştirmenin bir çok yolu vardır (ancak burada detaylandırmak önemli değildir ..)
O ZAMAN, bir sonraki sorun, Request.Body'yi okumaya gittiğimde zaten elden çıkarılmış olmasıdır. Ugh. Peki ne verir?
Newtonsoft.JSON'u endpiont çağrısında [FromBody] ayrıştırıcım olarak kullanıyorum. Eşzamanlı okumalardan sorumlu olan budur ve tamamlandığında akışı da kapatır. Çözüm? JSON ayrıştırmasına geçmeden önce akışı okuyun mu? Elbette, işe yarıyor ve sonunda şunu elde ettim:
public class ReadRequestBodyIntoItemsAttribute : AuthorizeAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationFilterContext context)
{
if (context == null) return;
var syncIOFeature = context.HttpContext.Features.Get<IHttpBodyControlFeature>();
if (syncIOFeature != null)
{
syncIOFeature.AllowSynchronousIO = true;
var req = context.HttpContext.Request;
req.EnableBuffering();
if (req.Body.CanSeek)
{
req.Body.Seek(0, SeekOrigin.Begin);
using (var reader = new StreamReader(
req.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false,
bufferSize: 8192,
leaveOpen: true))
{
var jsonString = reader.ReadToEnd();
context.HttpContext.Items.Add("request_body", jsonString);
}
req.Body.Seek(0, SeekOrigin.Begin);
}
}
}
}
Artık gövdeye, [ReadRequestBodyIntoItems] özniteliğine sahip uç noktalarda HttpContext.Items ["request_body"] kullanarak erişebilirim.
Ama adamım, bu atlamak için çok fazla çember gibi görünüyor. İşte burada bitirdim ve bundan gerçekten memnunum.
Uç noktam şöyle başladı:
[HttpPost("")]
[ReadRequestBodyIntoItems]
[Consumes("application/json")]
public async Task<IActionResult> ReceiveSomeData([FromBody] MyJsonObjectType value)
{
val bodyString = HttpContext.Items["request_body"];
}
Ancak imzayı değiştirmek çok daha kolaydır, örneğin:
[HttpPost("")]
[Consumes("application/json")]
public async Task<IActionResult> ReceiveSomeData()
{
using (var reader = new StreamReader(
Request.Body,
encoding: Encoding.UTF8,
detectEncodingFromByteOrderMarks: false
))
{
var bodyString = await reader.ReadToEndAsync();
var value = JsonConvert.DeserializeObject<MyJsonObjectType>(bodyString);
}
}
Bunu gerçekten beğendim çünkü vücut akışını yalnızca bir kez okuyor ve seriyi kaldırma işleminin kontrolü bende. Elbette, ASP.NET çekirdeğinin bu sihri benim için yapması güzel, ancak burada akışı iki kez okumakla (belki her seferinde ara belleğe alarak) zaman kaybetmiyorum ve kod oldukça açık ve temiz.
Bu işlevselliğe birçok uç noktada ihtiyacınız varsa, ara yazılım yaklaşımları daha temiz olabilir veya en azından gövde ayıklamayı kodu daha kısa hale getirmek için bir uzantı işlevine kapsülleyebilirsiniz.
Her neyse, bu konunun 3 yönüne de değinen herhangi bir kaynak bulamadım, dolayısıyla bu yazı. Umarım bu birine yardımcı olur!
BTW: Bu, ASP .NET Core 3.1 kullanıyordu.