कैसे एक asp.net कोर webapi नियंत्रक में अनुरोध शरीर को पढ़ने के लिए?


104

मैं OnActionExecutingविधि में अनुरोध शरीर को पढ़ने की कोशिश कर रहा हूं , लेकिन मैं हमेशा nullशरीर के लिए मिलता हूं ।

var request = context.HttpContext.Request;
var stream = new StreamReader(request.Body);
var body = stream.ReadToEnd();

मैंने स्ट्रीम स्थिति को स्पष्ट रूप से 0 पर सेट करने का प्रयास किया है, लेकिन यह भी काम नहीं किया। चूंकि यह ASP.NET CORE है, इसलिए चीजें मेरे हिसाब से थोड़ी अलग हैं। मैं पुराने वेबपीआई संस्करणों की चर्चा करते हुए सभी नमूने यहाँ देख सकता हूँ।
क्या ऐसा करने का कोई और तरीका है?


4
सावधान रहें, यदि अनुरोध बॉडी को अनुरोध पाइपलाइन के दौरान पहले ही पढ़ा गया था, तो यह खाली है जब आप इसे दूसरी बार पढ़ने की कोशिश करते हैं
Fabio


@ फैबियो जानकारी के लिए धन्यवाद, क्या हम स्थिति सेट कर सकते हैं और इसे फिर से पढ़ सकते हैं?
कसून कोसवत्था 19

@KasunKoswattha - डिजाइन द्वारा शरीर की सामग्री को केवल-केवल स्ट्रीम के रूप में माना जाता है जिसे केवल एक बार पढ़ा जा सकता है।
202 बजे user270576

मुझे लगता है कि सवाल नियंत्रकों के बजाय फिल्टर या मिडलवेयर को लक्षित करता है।
जिम आहो

जवाबों:


111

ASP.Net Core में शरीर के अनुरोध को कई बार पढ़ना जटिल लगता है, हालाँकि यदि आपका पहला प्रयास इसे सही तरीके से करता है, तो आपको अगले प्रयासों के लिए ठीक होना चाहिए।

मैंने शरीर की धारा को प्रतिस्थापित करके उदाहरण के लिए कई बदलाव पढ़े, लेकिन मुझे लगता है कि निम्नलिखित सबसे साफ है:

सबसे महत्वपूर्ण बिंदु

  1. अनुरोध को यह बताने के लिए कि आप इसके शरीर को दो या अधिक बार पढ़ेंगे,
  2. शरीर की धारा को बंद न करना, और
  3. इसे अपनी प्रारंभिक स्थिति में वापस लाने के लिए ताकि आंतरिक प्रक्रिया खो न जाए।

[संपादित करें]

जैसा कि मुराद ने कहा है, आप .Net Core 2.1 एक्सटेंशन का लाभ भी उठा सकते हैं: EnableBufferingयह मेमोरी में रखने के बजाय डिस्क पर बड़े अनुरोधों को संग्रहीत करता है, मेमोरी (फाइलों, छवियों, ...) में संग्रहीत बड़ी धाराओं से बचता है। । आप ASPNETCORE_TEMPपर्यावरण चर सेट करके अस्थायी फ़ोल्डर को बदल सकते हैं , और अनुरोध समाप्त होने पर फाइलें हटा दी जाती हैं।

एक प्राधिकरणफ़िल्टर में , आप निम्न कार्य कर सकते हैं:

// Helper to enable request stream rewinds
using Microsoft.AspNetCore.Http.Internal;
[...]
public class EnableBodyRewind : Attribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var bodyStr = "";
        var req = context.HttpContext.Request;

        // Allows using several time the stream in ASP.Net Core
        req.EnableRewind(); 

        // Arguments: Stream, Encoding, detect encoding, buffer size 
        // AND, the most important: keep stream opened
        using (StreamReader reader 
                  = new StreamReader(req.Body, Encoding.UTF8, true, 1024, true))
        {
            bodyStr = reader.ReadToEnd();
        }

        // Rewind, so the core is not lost when it looks the body for the request
        req.Body.Position = 0;

        // Do whatever work with bodyStr here

    }
}



public class SomeController : Controller
{
    [HttpPost("MyRoute")]
    [EnableBodyRewind]
    public IActionResult SomeAction([FromBody]MyPostModel model )
    {
        // play the body string again
    }
}

फिर आप अनुरोध हैंडलर में फिर से शरीर का उपयोग कर सकते हैं।

आपके मामले में यदि आपको एक अशक्त परिणाम मिलता है, तो इसका मतलब शायद यह है कि शरीर पहले से ही पहले चरण में पढ़ा जा चुका है। उस स्थिति में आपको एक मिडलवेयर (नीचे देखें) का उपयोग करने की आवश्यकता हो सकती है।

हालांकि सावधान रहें यदि आप बड़ी धाराओं को संभालते हैं, तो व्यवहार का अर्थ है कि सब कुछ मेमोरी में लोड है, यह एक फ़ाइल अपलोड के मामले में ट्रिगर नहीं होना चाहिए।

आप इसे एक मिडलवेयर के रूप में उपयोग करना चाह सकते हैं

मेरा ऐसा दिखता है (फिर, यदि आप बड़ी फ़ाइलों को डाउनलोड / अपलोड करते हैं, तो इसे स्मृति समस्याओं से बचने के लिए अक्षम किया जाना चाहिए):

public sealed class BodyRewindMiddleware
{
    private readonly RequestDelegate _next;

    public BodyRewindMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        try { context.Request.EnableRewind(); } catch { }
        await _next(context);
        // context.Request.Body.Dipose() might be added to release memory, not tested
    }
}
public static class BodyRewindExtensions
{
    public static IApplicationBuilder EnableRequestBodyRewind(this IApplicationBuilder app)
    {
        if (app == null)
        {
            throw new ArgumentNullException(nameof(app));
        }

        return app.UseMiddleware<BodyRewindMiddleware>();
    }

}

स्ट्रीम अभी भी खाली है, भले ही मैं स्थिति 0. पर
पलट जाऊं

2
क्या आपने उपयोग किया है req.EnableRewind();? मैं ऊपर दिए गए कोड का उपयोग करता हूं और यह अच्छी तरह से काम करता है।
जीन

req.EnableRewind () का उपयोग किया है; काम नहीं करता। मुझे पोजिशन = 0, बॉडी लेंथ = 26 मिलती है, लेकिन 'बॉडी' स्ट्रीम पढ़ने से एक स्ट्रींग खाली हो जाती है।
एड्रियन नसुई

आपको शरीर के पहले पढ़े जाने से पहले रिवाइंड करने में सक्षम होना है और दूसरे से पहले नहीं, अगर आपको नहीं लगता कि यह काम नहीं करेगा
जीन

3
इसका उपयोग करना भी संभव है request.EnableBuffering()(रैपर ओवर EnableRewind()) यह ASP.NET Core 2.1 में उपलब्ध है। docs.microsoft.com/en-us/dotnet/api/…
Murad

27

एक स्पष्ट समाधान, ASP.Net कोर 2.1 / 3.1 में काम करता है

फ़िल्टर वर्ग

using Microsoft.AspNetCore.Authorization;
// For ASP.NET 2.1
using Microsoft.AspNetCore.Http.Internal;
// For ASP.NET 3.1
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Filters;

public class ReadableBodyStreamAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        // For ASP.NET 2.1
        // context.HttpContext.Request.EnableRewind();
        // For ASP.NET 3.1
        // context.HttpContext.Request.EnableBuffering();
    }
}

एक नियंत्रक में

[HttpPost]
[ReadableBodyStream]
public string SomePostMethod()
{
    //Note: if you're late and body has already been read, you may need this next line
    //Note2: if "Note" is true and Body was read using StreamReader too, then it may be necessary to set "leaveOpen: true" for that stream.
    HttpContext.Request.Body.Seek(0, SeekOrigin.Begin);

    using (StreamReader stream = new StreamReader(HttpContext.Request.Body))
    {
        string body = stream.ReadToEnd();
        // body = "param=somevalue&param2=someothervalue"
    }
}

2
Netcore3.0 के लिए, यह .EnableBuffering () के बजाय.EnableRewind()
mr5

धन्यवाद @ mr5 - मेरे उत्तर को अपडेट करें
Andriod

मैंने इसे कुछ .net Core 2.2 -> Core 3.1 अपग्रेड करते हुए ठीक किया, जो कि EnableRewind () के रास्ते को तोड़ दिया। मुझे लगता है कि इसे कोड की एक और पंक्ति की आवश्यकता है, जिसके बिना मैं शरीर को फिर से नहीं पढ़ सकता था: HttpContext.Request.Body.Seek (0, SeekOrigin.Begin);
लैरी स्मिथ

2
यह केवल मेरे AuthorizeAttributeलिए Attribute(ASP.Net कोर 3.1 में) बदलने के बाद काम किया ।
सिगमंड

दोस्तों pls उल्लेखित पुस्तकालयों को जोड़ना सुनिश्चित करें। मेरे पास पहले से ही कोड था, लेकिन जब तक मुझे Microsoft.AspNetCore का एहसास नहीं हुआ, तब तक EnableBuffering रेड स्क्विगली लाइन दिखा रहा था। संदर्भ गायब था। Android के लिए धन्यवाद!
कार्तिक रमण

18

अनुरोध निकाय को वापस लाने में सक्षम होने के लिए, @ जीन के जवाब ने मुझे एक समाधान के साथ आने में मदद की, जो अच्छी तरह से काम करता है। मैं वर्तमान में ग्लोबल एक्सेप्शन हैंडलर मिडलवेयर के लिए इसका उपयोग करता हूं लेकिन सिद्धांत समान है।

मैंने एक मिडलवेयर बनाया जो मूल रूप से अनुरोध बॉडी (एक डेकोरेटर के बजाय) पर रिवाइंड को सक्षम करता है।

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();
    [...]
}

इस दृष्टिकोण का उपयोग करते हुए, मैं सफलतापूर्वक अनुरोध करने में सक्षम हूं।


1
यह मेरे लिए बहुत अच्छा काम किया @SaoBiz धन्यवाद! एक टाइपो, परिवर्तन 2 इस के लिए बिल्डर में UseEnableRequestRewind(this IApplicationBuilder builder)
रिचर्ड लोगवुड

@ रीचर्डलॉगवुड ने मदद की! टाइपो खोजने के लिए धन्यवाद! फिक्स्ड। :)
साओबिज

6

यह एक पुराना धागा है, लेकिन जब से मैं यहां आया, मुझे लगा कि मैं अपने निष्कर्षों को पोस्ट करूंगा ताकि वे दूसरों की मदद कर सकें।

सबसे पहले, मेरे पास एक ही मुद्दा था, जहां मैं अनुरोध प्राप्त करना चाहता था। बॉडी और उस (लॉगिंग / ऑडिटिंग) के साथ कुछ करना चाहिए। लेकिन अन्यथा मैं चाहता था कि समापन बिंदु समान दिखे।

तो, यह लग रहा था कि EnableBuffering () कॉल चाल कर सकती है। फिर आप शरीर पर एक सीक (0, एक्सएक्सएक्स) कर सकते हैं और सामग्री को फिर से पढ़ सकते हैं, आदि।

हालाँकि, इससे मेरा अगला मुद्दा बन गया। जब समापन बिंदु तक पहुँच हो, तो मुझे "सिन्कोर्नस संचालन रोक दिया जाता है" अपवाद। इसलिए, विकल्प में संपत्ति AllowSynchronousIO = true को सेट करने के लिए वर्कअराउंड है। इसे पूरा करने के कई तरीके हैं (लेकिन यहां पर विस्तार से बताना महत्वपूर्ण नहीं है ..)

फिर, अगला मुद्दा यह है कि जब मैं अनुरोध पढ़ने के लिए जाता हूं। लेकिन यह पहले ही निपटा दिया गया है। ओह। तो, क्या देता है?

मैं एंडपियन कॉल में न्यूटनसॉफ्ट.जॉन को अपने [FromBody] पार्सर के रूप में उपयोग कर रहा हूं। यही वह है जो सिंक्रोनस रीड के लिए जिम्मेदार है और जब यह पूरा हो जाता है तो यह स्ट्रीम को भी बंद कर देता है। उपाय? JSON को पार्स करने से पहले स्ट्रीम पढ़ें यकीन है, कि काम करता है और मैं इस के साथ समाप्त हुआ:

 /// <summary>
/// quick and dirty middleware that enables buffering the request body
/// </summary>
/// <remarks>
/// this allows us to re-read the request body's inputstream so that we can capture the original request as is
/// </remarks>
public class ReadRequestBodyIntoItemsAttribute : AuthorizeAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        if (context == null) return;

        // NEW! enable sync IO beacuse the JSON reader apparently doesn't use async and it throws an exception otherwise
        var syncIOFeature = context.HttpContext.Features.Get<IHttpBodyControlFeature>();
        if (syncIOFeature != null)
        {
            syncIOFeature.AllowSynchronousIO = true;

            var req = context.HttpContext.Request;

            req.EnableBuffering();

            // read the body here as a workarond for the JSON parser disposing the stream
            if (req.Body.CanSeek)
            {
                req.Body.Seek(0, SeekOrigin.Begin);

                // if body (stream) can seek, we can read the body to a string for logging purposes
                using (var reader = new StreamReader(
                     req.Body,
                     encoding: Encoding.UTF8,
                     detectEncodingFromByteOrderMarks: false,
                     bufferSize: 8192,
                     leaveOpen: true))
                {
                    var jsonString = reader.ReadToEnd();

                    // store into the HTTP context Items["request_body"]
                    context.HttpContext.Items.Add("request_body", jsonString);
                }

                // go back to beginning so json reader get's the whole thing
                req.Body.Seek(0, SeekOrigin.Begin);
            }
        }
    }
}

इसलिए अब, मैं [ReadRequestBodyIntoItems] विशेषता वाले समापन बिंदुओं में HttpContext.Items ["request_body"] का उपयोग करके शरीर तक पहुंच सकता हूं।

लेकिन यार, ऐसा लगता है जैसे बहुत से हूपों के माध्यम से कूदना है। तो यहाँ मैं कहाँ समाप्त हो गया, और मैं वास्तव में इसके साथ खुश हूँ।

मेरा समापन बिंदु कुछ इस तरह शुरू हुआ:

[HttpPost("")]
[ReadRequestBodyIntoItems]
[Consumes("application/json")]
public async Task<IActionResult> ReceiveSomeData([FromBody] MyJsonObjectType value)
{
    val bodyString = HttpContext.Items["request_body"];
    // use the body, process the stuff...
}

लेकिन यह सिर्फ हस्ताक्षर बदलने के लिए बहुत अधिक सीधा है, जैसे:

[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);

        // use the body, process the stuff...
    }
}

मुझे यह वास्तव में पसंद आया क्योंकि यह केवल एक बार शरीर की धारा को पढ़ता है, और मेरे पास डीसेरलाइज़ेशन का नियंत्रण है। यकीन है, यह अच्छा है अगर ASP.NET कोर मेरे लिए यह जादू करता है, लेकिन यहां मैं दो बार स्ट्रीम पढ़ने में समय बर्बाद नहीं करता (शायद हर बार बफरिंग), और कोड काफी स्पष्ट और साफ है।

यदि आपको बहुत से समापन बिंदुओं पर इस कार्यक्षमता की आवश्यकता है, तो शायद मिडलवेयर दृष्टिकोण क्लीनर हो सकता है, या आप कोड को अधिक संक्षिप्त बनाने के लिए शरीर के निष्कर्षण को कम से कम विस्तार समारोह में संलग्न कर सकते हैं।

वैसे भी, मुझे इस मुद्दे के सभी 3 पहलुओं को छूने वाला कोई स्रोत नहीं मिला, इसलिए यह पोस्ट। उम्मीद है कि यह किसी की मदद करता है!

BTW: यह ASP .NET कोर 3.1 का उपयोग कर रहा था।


यदि प्रोग्राम JSON स्ट्रिंग को NyObjectType पर पार्स नहीं कर सकता है, तो मैं "request_body" से मान नहीं पढ़ सकता हूं
Ericyu67

2

ASP.NET Core 2.1 का उपयोग करते समय मेरे पास एक समान समस्या थी:

  • मुझे POSTed डेटा को पढ़ने और इसके खिलाफ कुछ सुरक्षा जांच करने के लिए कस्टम मिडलवेयर की आवश्यकता है
  • बड़ी संख्या में कार्य प्रभावित होने के कारण प्राधिकरण फ़िल्टर का उपयोग करना व्यावहारिक नहीं है
  • मुझे वस्तुओं को क्रियाओं में बाँधने की अनुमति है ([FromBody] someObject)। SaoBizइस समाधान को इंगित करने के लिए धन्यवाद ।

तो, स्पष्ट समाधान यह है कि अनुरोध को वापस लाने की अनुमति दी जाए, लेकिन सुनिश्चित करें कि शरीर को पढ़ने के बाद, बंधन अभी भी काम करता है।

EnableRequestRewindMiddleware

public class EnableRequestRewindMiddleware
{
    private readonly RequestDelegate _next;

    ///<inheritdoc/>
    public EnableRequestRewindMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public async Task Invoke(HttpContext context)
    {
        context.Request.EnableRewind();
        await _next(context);
    }
}

Startup.cs

(इसे कॉन्फ़िगर विधि की शुरुआत में रखें)

app.UseMiddleware<EnableRequestRewindMiddleware>();

कुछ अन्य मिडलवेयर

यह उस मिडलवेयर का हिस्सा है जिसमें सामान की जाँच के लिए POSTed जानकारी को अनपैक करने की आवश्यकता होती है।

using (var stream = new MemoryStream())
{
    // make sure that body is read from the beginning
    context.Request.Body.Seek(0, SeekOrigin.Begin);
    context.Request.Body.CopyTo(stream);
    string requestBody = Encoding.UTF8.GetString(stream.ToArray());

    // this is required, otherwise model binding will return null
    context.Request.Body.Seek(0, SeekOrigin.Begin);
}

2

हाल ही में मैं एक बहुत ही सुंदर समाधान में आया था जो यादृच्छिक JSON में ले जाता है कि आपको संरचना का कोई पता नहीं है:

    [HttpPost]
    public JsonResult Test([FromBody] JsonElement json)
    {
        return Json(json);
    }

बस इतना आसान है।


1

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());

अधिक - एक संक्षिप्त, गैर-संकलन पर एक प्रयास, उन वस्तुओं का उदाहरण जो आपको सुनिश्चित करने की आवश्यकता होगी ताकि एक प्रयोग करने योग्य स्थान प्राप्त कर सकें IHttpContextAccessor। उत्तर ने सही ढंग से इंगित किया है कि जब आप अनुरोध शरीर को पढ़ने का प्रयास करेंगे तो आपको फिर से शुरू करने की आवश्यकता होगी। CanSeek, Positionअनुरोध शरीर पर गुण इस की पुष्टि करने के लिए उपयोगी स्ट्रीम।

.NET कोर डि डॉक्स

// 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");
        }
    }
}    

1

मैं इस तरह से एक asp.net कोर 3.1 आवेदन में अनुरोध शरीर को पढ़ने में सक्षम था (साथ में एक साधारण मिडलवेयर जो बफ़र करने योग्य-सक्षम रिवाइंडिंग पहले .Net कोर संस्करणों के लिए काम करता प्रतीत होता है-)।

var reader = await Request.BodyReader.ReadAsync();
Request.Body.Position = 0;
var buffer = reader.Buffer;
var body = Encoding.UTF8.GetString(buffer.FirstSpan);
Request.Body.Position = 0;

0

पढ़ने के लिए Body, आप एसिंक्रोनस रूप से पढ़ सकते हैं।

asyncपालन करने की विधि का उपयोग करें:

public async Task<IActionResult> GetBody()
{
      string body="";
      using (StreamReader stream = new StreamReader(Request.Body))
      {
           body = await stream.ReadToEndAsync();
      }
    return Json(body);
}

पोस्टमैन के साथ टेस्ट:

यहां छवि विवरण दर्ज करें

यह अच्छी तरह से काम कर रहा है और Asp.net coreसंस्करण में परीक्षण किया गया है 2.0 , 2.1 , 2.2, 3.0

मुझे आशा है कि उपयोगी है।


0

मैं रिक्वेस्ट को भी पढ़ना चाहता था। बॉडी के बिना यह स्वतः ही कुछ एक्शन पैरामीटर मॉडल पर मैप हो जाता है। इसे हल करने से पहले कई अलग-अलग तरीकों का परीक्षण किया। और मुझे यहाँ वर्णित कोई भी कार्य समाधान नहीं मिला। यह समाधान वर्तमान में .NET कोर 3.0 फ्रेमवर्क पर आधारित है।

Reader.readToEnd () एक सरल तरीके की तरह सीमेड है, भले ही इसे संकलित किया गया हो, इसने एक रनटाइम अपवाद को फेंक दिया, जिससे मुझे async कॉल का उपयोग करने की आवश्यकता हुई। इसलिए इसके बजाय मैंने ReadToEndAsync () का उपयोग किया, हालांकि यह कभी-कभी काम करता था, और कभी-कभी नहीं। मुझे त्रुटियों की तरह देना, धारा बंद होने के बाद नहीं पढ़ सकता। समस्या यह है कि हम यह गारंटी नहीं दे सकते कि यह उसी थ्रेड में परिणाम देगा (भले ही हम प्रतीक्षा का उपयोग करें)। इसलिए हमें किसी तरह के कॉलबैक की जरूरत है। इस समाधान ने मेरे लिए काम किया।

[Route("[controller]/[action]")]
public class MyController : ControllerBase
{

    // ...

    [HttpPost]
    public async void TheAction()
    {
        try
        {
            HttpContext.Request.EnableBuffering();
            Request.Body.Position = 0;
            using (StreamReader stream = new StreamReader(HttpContext.Request.Body))
            {
                var task = stream
                    .ReadToEndAsync()
                    .ContinueWith(t => {
                        var res = t.Result;
                        // TODO: Handle the post result!
                    });

                // await processing of the result
                task.Wait();
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed to handle post!");
        }
    }

0

ऐसा करने का सबसे सरल संभव तरीका निम्नलिखित है:

  1. नियंत्रक विधि से आपको शरीर को निकालने की आवश्यकता है, इस पैरामीटर को जोड़ें: [FromBody] SomeClass मान

  2. "SomeClass" को इस रूप में घोषित करें: कक्षा SomeClass {सार्वजनिक स्ट्रिंग SomeParameter {प्राप्त करें; सेट; }}

जब कच्चे शरीर को जस्सन के रूप में भेजा जाता है, तो .net कोर यह आसानी से पढ़ना जानता है।


0

उन लोगों के लिए जो केवल अनुरोध से सामग्री (अनुरोध निकाय) प्राप्त करना चाहते हैं:

[FromBody]अपने नियंत्रक विधि पैरामीटर में विशेषता का उपयोग करें ।

[Route("api/mytest")]
[ApiController]
public class MyTestController : Controller
{
    [HttpPost]
    [Route("content")]
    public async Task<string> ReceiveContent([FromBody] string content)
    {
        // Do work with content
    }
}

जैसा कि डॉक्टर कहते हैं: यह विशेषता निर्दिष्ट करती है कि अनुरोध बॉडी का उपयोग करके एक पैरामीटर या संपत्ति बाध्य होनी चाहिए।


0

.NET Core 3.1 में प्रतिक्रिया बफरिंग जोड़ने का एक त्वरित तरीका है

    app.Use((context, next) =>
    {
        context.Request.EnableBuffering();
        return next();
    });

स्टार्टअप्स में। मैंने पाया कि यह गारंटी भी दी गई है कि स्ट्रीम पढ़ने से पहले बफरिंग सक्षम हो जाएगी, जो कि .net Core 3.1 के लिए एक समस्या थी जो मैंने देखी हुई कुछ अन्य मिडलवेयर / ऑथराइजेशन फ़िल्टर उत्तर के साथ देखी है।

फिर आप अपने अनुरोध बॉडी को HttpContext.Request.Bodyअपने हैंडलर के माध्यम से पढ़ सकते हैं जैसा कि कई अन्य लोगों ने सुझाया है।

यह भी ध्यान देने योग्य है कि आपके EnableBufferingपास एक ओवरलोड है जो आपको यह सीमित करने की अनुमति देता है कि अस्थायी फ़ाइल का उपयोग करने से पहले यह मेमोरी में कितना बफर करेगा, और आपके लिए बफर की एक समग्र सीमा भी है। एनबी अगर एक अनुरोध इस सीमा से अधिक है तो एक अपवाद फेंक दिया जाएगा और अनुरोध आपके हैंडलर तक कभी नहीं पहुंचेगा।


इसने मेरे (3.1) शानदार प्रदर्शन किया। आपको एक अलग प्रश्न पर उद्धृत किया गया: stackoverflow.com/a/63525694/6210068
लांस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.