কীভাবে একটি এএসপিএন কোর ওয়েবপিআই নিয়ামকটিতে অনুরোধ বডি পড়বেন?


113

আমি OnActionExecutingপদ্ধতিতে অনুরোধ বডিটি পড়ার চেষ্টা করছি , তবে আমি সর্বদা nullশরীরের জন্য পাই ।

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

আমি স্পষ্টভাবে স্ট্রিমের অবস্থানটি 0 তে সেট করার চেষ্টা করেছি, তবে এটি কার্যকর হয়নি। যেহেতু এটি এএসপি.এনইটি কোর, আমার মনে হয় বিষয়গুলি একটু আলাদা। আমি এখানে পুরানো ওয়েব এপিআই সংস্করণ উল্লেখ করে সমস্ত নমুনা দেখতে পাচ্ছি।

এটি করার অন্য কোনও উপায় আছে?


4
সতর্কতা অবলম্বন করুন, যদি অনুরোধ পাইপলাইন চলাকালীন অনুরোধের বডিটি আগেই পড়ে নেওয়া হয়, তবে আপনি যখন এটি দ্বিতীয়বার পড়ার চেষ্টা করবেন তখন তা খালি হবে
ফ্যাবিও


@ ফ্যাবিও তথ্যের জন্য ধন্যবাদ, আমরা কি অবস্থানটি সেট করে আবার পড়তে পারি?
কাসুন কোসওয়াথা

@ কাসুনকোস্বথা - ডিজাইনের মাধ্যমে দেহের সামগ্রীগুলি কেবলমাত্র একবার পড়া যায় এমন ফরোয়ার্ড-স্ট্রিম হিসাবে বিবেচিত হয়।
ব্যবহারকারী270576

আমি মনে করি প্রশ্নটি বরং নিয়ন্ত্রকদের চেয়ে ফিল্টার বা মিডলওয়্যারকে লক্ষ্য করে।
জিম আহো

উত্তর:


115

এএসপি.নেট কোরে বডি রিকোয়েস্টটি কয়েকবার পড়া জটিল মনে হয়, তবে আপনার প্রথম প্রয়াসটি যদি সঠিকভাবে এটি করে তবে আপনার পরবর্তী প্রচেষ্টাগুলির জন্য ভাল হওয়া উচিত।

আমি উদাহরণস্বরূপ বডি স্ট্রিমটি প্রতিস্থাপনের মাধ্যমে কয়েকটি টার্নআরন্ড পড়ি, তবে আমি মনে করি নিম্নলিখিতটি সবচেয়ে পরিষ্কার:

সবচেয়ে গুরুত্বপূর্ণ পয়েন্ট হচ্ছে

  1. অনুরোধটি জানাতে যে আপনি তার শরীরটি দু'বার বা আরও বেশি বার পড়বেন,
  2. শরীরের প্রবাহ বন্ধ না, এবং
  3. এটিকে তার প্রাথমিক অবস্থানে রিওয়াইন্ড করতে যাতে অভ্যন্তরীণ প্রক্রিয়াটি হারাতে না পারে।

[সম্পাদনা]

মুরাদের নির্দেশ অনুসারে, আপনি। নেট কোর ২.১ এক্সটেনশনের সুবিধাও নিতে পারেন: 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>();
    }

}

আমি অবস্থান ০. এ ফিরে গেলেও স্ট্রিমটি এখনও খালি রয়েছে
অ্যাড্রিয়ান ন্যাসুই

4
আপনি ব্যবহার করেছেন req.EnableRewind();? আমি উপরের কোডটি ব্যবহার করি এবং এটি ভালভাবে কাজ করে।
জিন

4
Req.EnableRewind () ব্যবহার করেছেন; কাজ করে না. আমি পজিশন = 0, শরীরের দৈর্ঘ্য = 26 পেয়েছি তবে 'বডি' স্ট্রিমটি পড়ে খালি স্ট্রিং আসে with
অ্যাড্রিয়ান নাসুই

এটি নিখুঁত উত্তর
গায়ান

4
এটি ব্যবহার করাও সম্ভব request.EnableBuffering()(মোড়ক ওভার EnableRewind()) এটি এএসপি.নেট
মুরাদ

29

একটি পরিষ্কার সমাধান, এএসপি.নেট কোর 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"
    }
}

4
নেটকোয়ার.৩.০ এর জন্য এটি হবে.EnableRewind()
এমআর 5 এর

ধন্যবাদ @ mr5 - Updated আমার উত্তর
Andriod

আমি কিছু নেট নেট 2.2 -> কোর 3.1 আপগ্রেডগুলি ফিক্স করার সময় এটিটি পেয়েছি যা সক্ষম্যরউইন্ড () উপায়টি ভেঙে ফেলেছে। আমি মনে করি এটির জন্য আরও একটি লাইন কোডের প্রয়োজন, যা ছাড়া আমি বডিটি পুনরায় পড়তে পারি না: HttpContext.Request.Body.Seek (0, SeekOrigin.Begin);
ল্যারি স্মিথ

4
এটি কেবলমাত্র পরিবর্তন করার পর আমার জন্য কাজ AuthorizeAttributeকরতে Attribute(3.1 মধ্যে ASP.Net কোর)।
সিগমুন্ড

ছেলেরা উল্লিখিত গ্রন্থাগারগুলি যুক্ত করার বিষয়ে নিশ্চিত হন। আমার কাছে ইতিমধ্যে কোড ছিল তবে মাইক্রোসফ্ট বুঝতে না পারা পর্যন্ত অ্যাফলেবলিং লোহিত স্কুইগ্লি রেখাটি প্রদর্শন করছিল spএসপ নেটকোর.এইচটিপি রেফারেন্স অনুপস্থিত ছিল। অ্যান্ড্রয়েডকে ধন্যবাদ!
কার্তিক রমন

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

এই পদ্ধতির ব্যবহার করে, আমি অনুরোধের মূলধারাকে সাফল্যের সাথে রিভাইন্ড করতে সক্ষম হয়েছি।


4
এটি আমার জন্য দুর্দান্ত কাজ করেছে @ সাওবিজ আপনাকে ধন্যবাদ! এক টাইপো, পরিবর্তন 2nd এই জন্য রচয়িতা মধ্যে UseEnableRequestRewind(this IApplicationBuilder builder)
রিচার্ড লগউড

পছন্দ করেছেন টাইপোর সন্ধানের জন্য ধন্যবাদ! স্থির। :)
সাওবিজ 23

7

এটি কিছুটা পুরানো থ্রেড, তবে যেহেতু আমি এখানে এসেছি, আমি অনুভব করেছি যে আমি আমার অনুসন্ধানগুলি পোস্ট করেছি যাতে তারা অন্যদের সহায়তা করতে পারে।

প্রথমত, আমার একই সমস্যা ছিল, যেখানে আমি অনুরোধ.বাডি পেতে এবং এটি (লগিং / অডিটিং) দিয়ে কিছু করতে চাই। তবে অন্যথায় আমি শেষ পয়েন্টটি দেখতে একই রকম দেখতে চাই।

সুতরাং, দেখে মনে হচ্ছিল সক্ষমযোগ্য বাফারিং () কলটি কৌশলটি করতে পারে। তারপরে আপনি শরীরে সিক (0, এক্সএক্সএক্সএক্স) করতে পারেন এবং সামগ্রীগুলি পুনরায় পড়তে পারেন

যাইহোক, এটি আমার পরবর্তী সমস্যার দিকে পরিচালিত করেছিল। আমি শেষ পয়েন্টে অ্যাক্সেস করার সময় ব্যতিক্রমগুলি "সিনক্রোনাস অপারেশনগুলি নিষিদ্ধ করা হয়" পেতে চাই। সুতরাং, বিকল্পটির মধ্যে সম্পত্তিটিকে AllowSynchronousIO = সত্য সেট করতে হবে। এটি সম্পাদন করার বিভিন্ন উপায় রয়েছে (তবে এখানে বিশদটি গুরুত্বপূর্ণ নয়)

তারপরে, পরবর্তী সমস্যাটি হ'ল আমি যখন অনুরোধটি পড়তে যাই ody রক্তাক্ত এটি ইতিমধ্যে নিষ্পত্তি হয়ে গেছে। উঃ তো, কি দেয়?

আমি এন্ডপায়ান্ট কলটিতে নিউটনসফট.জসনকে আমার [ফ্রমবডি] পার্সার হিসাবে ব্যবহার করছি। সিঙ্ক্রোনাস রিডের জন্য এটিই দায়ী এবং এটি হয়ে গেলে স্ট্রিমটিও বন্ধ করে দেয়। সমাধান? 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);
            }
        }
    }
}

সুতরাং এখন, আমি এইচটিপিঙ্কটেক্সট.আইটেমগুলি ব্যবহার করে শরীরে প্রবেশ করতে পারি] আইটেমগুলি ["রিকোয়েস্টবিডিআইন্টো আইটেম] বৈশিষ্ট্যযুক্ত শেষ পয়েন্টগুলিতে [" অনুরোধ_বডি "]।

কিন্তু মানুষ, এটি অনেকগুলি হুপের মধ্য দিয়ে যেতে পারে। সুতরাং এখানেই আমি শেষ করেছি এবং আমি এতে সত্যই খুশি।

আমার শেষ পয়েন্টটি এমন কিছু হিসাবে শুরু হয়েছিল:

[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...
}

তবে কেবল স্বাক্ষরটি পরিবর্তন করা আরও সহজ straight

[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...
    }
}

আমি সত্যিই এটি পছন্দ করেছি কারণ এটি একবারে কেবলমাত্র দেহের স্ট্রিমটি পড়ে এবং ডেসরিয়ালাইজেশন করার নিয়ন্ত্রণ আমার আছে। অবশ্যই, এএসপি.নেট কোর যদি আমার জন্য এই যাদুটি করে তবে এটি দুর্দান্ত তবে এখানে আমি দুবার স্ট্রিমটি পড়ার সময় নষ্ট করি না (সম্ভবত প্রতিবারের জন্য বাফারিং করা), এবং কোডটি বেশ পরিষ্কার এবং পরিষ্কার।

আপনার যদি প্রচুর এন্ডপয়েন্টগুলিতে এই কার্যকারিতাটির প্রয়োজন হয় তবে মিডলওয়্যারগুলির পন্থাগুলি পরিষ্কার হতে পারে, বা কোডটি আরও সংক্ষিপ্ত করে তুলতে আপনি কমপক্ষে শরীরের নিষ্কাশনকে কোনও এক্সটেনশন ফাংশনে আবদ্ধ করতে পারেন।

যাইহোক, আমি এই উত্সের সমস্ত 3 দিকগুলিকে স্পর্শ করে এমন কোনও উত্স পাই না, সুতরাং এই পোস্টটি। আশা করি এটি কাউকে সাহায্য করবে!

বিটিডব্লিউ: এটি এএসপি। নেট কোর 3.1 ব্যবহার করছিল।


যদি প্রোগ্রামটি JSON স্ট্রিংটিকে NyObjectType- এ পার্স করতে না পারে, তবে আমি "অনুরোধ_বডি" থেকে মানটি পড়তে পারি না
এরিক্য 6767

3

সম্প্রতি আমি একটি খুব মার্জিত সমাধান পেয়েছি যা এলোমেলো JSON এ নিয়েছে যে আপনার কাঠামোর কোনও ধারণা নেই:

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

শুধু যে সহজ।


আপনাকে ধন্যবাদ, এটি সত্যিই কাজ করে। আমি GetRawText()জসনএলেটমেন্টের পদ্ধতি ব্যবহার করেছি এবং আমার জেএসএন পাঠ্য পেয়েছি।
mrNone

ডিটিও যখন এটি তৈরির সময় কিছু প্রক্রিয়াকরণ করে, যেমন ডিফল্ট মান বা কিছু সেট করা, এটি আপনাকে প্রকৃত অনুরোধের দেহটি দেবে না।
এবরাম শেহাতা

3

.NET কোর 3.1 এ প্রতিক্রিয়া বাফার করার একটি দ্রুত উপায় is

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

প্রারম্ভকালে। আমি এটির গ্যারান্টিও পেয়েছি যে স্ট্রিমটি পড়ার আগে বাফারিং সক্ষম করা হবে যা আমি দেখেছি এমন অন্যান্য মিডলওয়্যার / অনুমোদনের ফিল্টার উত্তরগুলির সাথে নেট নেট 3.1 এর জন্য একটি সমস্যা ছিল।

তারপরে আপনি HttpContext.Request.Bodyঅন্যদের পরামর্শ মতো আপনার হ্যান্ডলারের মাধ্যমে আপনার অনুরোধের বডিটি পড়তে পারেন ।

এছাড়াও বিবেচনা করার মতো বিষয় হ'ল EnableBufferingওভারলোডগুলি এটি অস্থায়ী ফাইল ব্যবহারের আগে আপনাকে মেমরিতে কতটা বাফার করবে এবং আপনার বাফার সামগ্রিক সীমাও সীমাবদ্ধ করতে দেয়। এনবি যদি কোনও অনুরোধ এই সীমা অতিক্রম করে তবে একটি ব্যতিক্রম ছুঁড়ে দেওয়া হবে এবং অনুরোধটি কখনই আপনার হ্যান্ডলারের কাছে পৌঁছাবে না।


এটি আমার পক্ষে উজ্জ্বলতার সাথে কাজ করেছে (৩.১) আপনাকে একটি পৃথক প্রশ্নের উদ্ধৃতি দিয়েছি
ল্যান্স

3.1 এ কাজ করেছেন। এছাড়াও, ব্যবহারকারীরা যারা এটি ব্যবহার করবেন তাদের জন্য কেবলমাত্র একটি অনুস্মারক: এটি স্টার্টআপ.সিগুলিতে সঠিক ক্রমে রাখার বিষয়টি নিশ্চিত করুন।
এব্রাম শেহাতা

2

এএসপি.নেট কোর ২.১ ব্যবহার করার সময় আমার একই সমস্যা ছিল:

  • পোষ্টড ডেটা পড়তে এবং এর বিরুদ্ধে কিছু সুরক্ষা চেক করার জন্য আমার একটি কাস্টম মিডলওয়্যার দরকার
  • বিপুল সংখ্যক ক্রিয়া প্রভাবিত হওয়ার কারণে কোনও অনুমোদনের ফিল্টার ব্যবহার করা ব্যবহারিক নয় practical
  • আমাকে ক্রিয়াকলাপগুলিতে আবদ্ধকরণগুলিকে অনুমতি দিতে হবে ([fromBody] সামান্য অবজেক্ট)। SaoBizএই সমাধানটি নির্দেশ করার জন্য ধন্যবাদ ।

সুতরাং, সুস্পষ্ট সমাধানটি হ'ল অনুরোধটি পুনর্গ্রহণযোগ্য হওয়ার অনুমতি দেওয়া, তবে নিশ্চিত হয়ে নিন যে শরীরটি পড়ার পরে, বাঁধাই এখনও কাজ করে।

সক্ষম করুনআরউইউন্ডমিডলওয়ার

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

স্টার্টআপ.সি

(এটি কনফিগার পদ্ধতির শুরুতে রাখুন)

app.UseMiddleware<EnableRequestRewindMiddleware>();

কিছু অন্য মিডলওয়্যার

এটি মিডলওয়্যারের একটি অংশ যা স্টাফ চেক করার জন্য পোস্ট করা তথ্যকে প্যাক করা প্রয়োজন।

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

পড়ার জন্য 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

আমি আশা করি দরকারী।


1

IHttpContextAccessorযদি এই রুট যেতে ইচ্ছুক পদ্ধতি কাজ করে।

টিএলডিআর;

  • ইনজেকশন 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

আমি এই জাতীয় অ্যাপ্লিকেশন কোর ৩.১ অ্যাপ্লিকেশনটিতে অনুরোধ বডিটি পড়তে সক্ষম হয়েছি (একসাথে একটি সাধারণ মিডলওয়্যারের সাথে যা বাফারিং-সক্ষমযোগ্য রিওয়ন্ডিং সক্ষম করে তোলে মনে হয় আগের নেট নেট সংস্করণগুলির জন্য কাজ করছে):

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

আমি অনুরোধটিও পড়তে চেয়েছিলাম ody রক্তটি কোনও অ্যাকশন প্যারামিটার মডেলটিতে স্বয়ংক্রিয়ভাবে ম্যাপ না করে। এটি সমাধানের আগে অনেকগুলি বিভিন্ন উপায়ে পরীক্ষিত। এবং আমি এখানে বর্ণিত কোনও কার্যনির্বাহী সমাধান খুঁজে পাইনি। এই সমাধানটি বর্তমানে .NET কোর 3.0 ফ্রেমওয়ার্কের উপর ভিত্তি করে।

রিডার.ড্রেডওএন্ড () একটি সহজ উপায়ে মতন মতামত নিয়েছে, যদিও এটি সংকলিত হয়েছে, এটি রানটাইম ব্যতিক্রম ছুঁড়েছে আমাকে এসিঙ্ক কলটি ব্যবহার করতে হবে। সুতরাং পরিবর্তে আমি 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] সামারক্লাস মান

  2. "সামারক্লাস" কে এই হিসাবে ঘোষণা করুন: শ্রেণি সোমারক্লাস {পাবলিক স্ট্রিং সোমপ্যারামিটার {পান; সেট }}

যখন কাঁচা দেহটি জসন হিসাবে প্রেরণ করা হয় তখন। নেট কোর এটি সহজেই কীভাবে পড়তে হয় তা জানে।


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
    }
}

যেমন ডক বলেছেন: এই বৈশিষ্ট্যটি নির্দিষ্ট করে যে অনুরোধের বডি ব্যবহার করে কোনও প্যারামিটার বা সম্পত্তি আবদ্ধ করা উচিত।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.