Home > Mobile >  How to read POST parameters in Minimal API, in C# posted by desktop app, .NET 6.0?
How to read POST parameters in Minimal API, in C# posted by desktop app, .NET 6.0?

Time:10-14

I am trying to build a small desktop app (.NET 6.0) that gets data from .NET 6.0 minimal API server.

The API server code is:

//app.MapPost("/show/", async Task<string> (string myName) =>
app.MapPost("/show/", async Task<string> (HttpRequest request) =>
{
    //return await Task.FromResult(myName);
    return await Task.FromResult(request.Query["myName"]);
});

The postman is able to post to

http://127.0.0.1:5400/show?myName=Srikanth S

and gets a reply in the uncommented as well as commented version.

The desktop app's response object has

StatusCode: 500, ReasonPhrase: 'Internal Server Error'

after the call to

app.MapPost("/show/", async Task<string> (string myName)

version while it responds with

StatusCode: 400, ReasonPhrase: 'Bad Request'

in the response object and

Required parameter "string myName" was not provided from query string

on result object.

My desktop app has this simple code only

    private async void button1_Click(object sender, EventArgs e)
    {
        Dictionary<string, string> content = new Dictionary<string, string>();
        content.Add("myName", "Srikanth S");

        using (HttpClient client = new HttpClient())
        {
            HttpResponseMessage response = await client.PostAsync("http://127.0.0.1:5400/show", new FormUrlEncodedContent(content));
            string result = await response.Content.ReadAsStringAsync();
            Debug.WriteLine(result);
        }
    }

I tried the permutation, combinations of StringContent, FormUrlEncodedContent, Dictionary, KeyvaluePair ...;

It looks like it is not capturing 'myName' in the HttpRequest version.

Any guidance or solution please?

update: created new .net core web api project (weatherforecast sample), added

app.MapPost("/show/", (string myName) =>
{
    return myName;
});

as well as tried

app.MapPost("/show/", async (string myName) =>
{
    return await Task.FromResult(myName);
});

No changes in Desktop App, I get this in debug output as below

Microsoft.AspNetCore.Http.BadHttpRequestException: Required parameter "string myName" was not provided from query string.
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.Log.RequiredParameterNotProvided(HttpContext httpContext, String parameterTypeName, String parameterName, String source, Boolean shouldThrow)
   at lambda_method2(Closure , Object , HttpContext )
   at Microsoft.AspNetCore.Http.RequestDelegateFactory.<>c__DisplayClass36_0.<Create>b__0(HttpContext httpContext)
   at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
--- End of stack trace from previous location ---
   at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
   at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
   at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

HEADERS
=======
Host: 127.0.0.1:5145
Content-Type: application/x-www-form-urlencoded
Content-Length: 17

any help is highly appreciated. For background, i am using visual studio 2022 community edition Version 17.3.6 , dotnet 6.0.402

SOS

CodePudding user response:

enter image description here

When using Postman to check the API method, you can see the parameter is added to the request URL.

Dictionary<string, string> content = new Dictionary<string, string>();
content.Add("myName", "Srikanth S");

using (HttpClient client = new HttpClient())
{
    HttpResponseMessage response = await client.PostAsync("http://127.0.0.1:5400/show", new  FormUrlEncodedContent(content));
    string result = await response.Content.ReadAsStringAsync();
    Debug.WriteLine(result);
}

But in the desktop app, the parameter is added to the request body, so in this scenario, the API method can't find the value from the request URL, so the value is null and will throw an exception.

To solve this issue, you can try to send the parameter via the Query String: add the parameter at the end of the request URL, like this:

    var name = "Srikanth S";
    using (HttpClient client = new HttpClient())
    {
        HttpResponseMessage response = await client.PostAsync($"http://127.0.0.1:5400?myName={name}", null);
        string result = await response.Content.ReadAsStringAsync();
        Debug.WriteLine(result);
    }

the API method:

app.MapPost("/show/", async Task<string> (HttpRequest request) =>
{
    //return await Task.FromResult(myName);
    return await Task.FromResult(request.Query["myName"]);
});

Or you can send the parameter from request body: in the API method, you can get the parameter from the Form. Modify the API method as below:

app.MapPost("/show/", async Task<string> (HttpRequest request) =>
{
    //return await Task.FromResult(myName);
    return await Task.FromResult(request.Form["myName"]); //get value from form.
});

In this time, the HttpClient method like this:

   Dictionary<string, string> content = new Dictionary<string, string>();
    content.Add("myName", "Srikanth S");

    using (HttpClient client = new HttpClient())
    {
        HttpResponseMessage response = await client.PostAsync("http://127.0.0.1:5400/show", new FormUrlEncodedContent(content));
        string result = await response.Content.ReadAsStringAsync();
        Debug.WriteLine(result);
    }

Refer to the following screenshot:

enter image description here

CodePudding user response:

The second parameter of PostAsync is meant for the body, not query string data. Just add the myName query parameter to the URL.

HttpResponseMessage response = await Client.PostAsync(
    "http://127.0.0.1:5400/show?myName=Jose", // <----- Like this
    new FormUrlEncodedContent(content)
);

CodePudding user response:

Thank you all for the guidance and help. Finally I cracked it :) Hope this will be useful to everyone. The key is post data is to be read from the request body on the api server. Here is how I did it

app.MapPost("/show/", async (HttpRequest request) =>
{
    var body = new StreamReader(request.Body);
    string postData = await body.ReadToEndAsync();
    Dictionary<string, dynamic> keyValuePairs = JsonSerializer.Deserialize<Dictionary<string, dynamic>>(postData) ?? new Dictionary<string, dynamic>();
    // here after you can play as you like :)
    return await Task.FromResult<string>(postData);
});

My desktop app code

        private async void button1_Click(object sender, EventArgs e)
        {
            var client = new HttpClient();

            using StringContent jsonContent = new(
            JsonSerializer.Serialize(new {myName = "Srikanth S"}), Encoding.UTF8, "application/json");

            using HttpResponseMessage response = await client.PostAsync("http://127.0.0.1:5145/show", jsonContent);

            response.EnsureSuccessStatusCode();
            var jsonResponse = await response.Content.ReadAsStringAsync();
            // here after you can play as you like :)
            Debug.WriteLine(jsonResponse);
        }

UPDATE: Thank you Zhi. request.Form approach is way better than mine; It works with postdata as url parameter also :) Here is server side.

app.MapPost("/show/", async (HttpRequest request) =>
{
    var body = new StreamReader(request.Body);
    string myName = request.Form["myName"].ToString();
    return await Task.FromResult<string>(myName);
});

On Desktop side

        private async void button1_Click(object sender, EventArgs e)
        {
            var client = new HttpClient();
            Dictionary<string, string> postParams = new Dictionary<string, string>();
            postParams.Add("myName", "Srikanth S");

            FormUrlEncodedContent content = new FormUrlEncodedContent(postParams);
            using HttpResponseMessage response = await client.PostAsync("http://127.0.0.1:5145/show", content);
            response.EnsureSuccessStatusCode();
            var jsonResponse = await response.Content.ReadAsStringAsync();
            Debug.WriteLine(jsonResponse);
        }
  • Related