How to submit MultipartFormDataContent from Blazor Client Project to a minimal API in Server Project in .net 8?

48 views Asked by At

I have created new project with Auto Render Mode using .net 8. There I have added an End point in the server project like bellow:

    public static void RegisterUserEndpoints(this WebApplication app)
{
    var userGroup = app.MapGroup("/api/users");

    userGroup.MapPost("/changepersonalInfo", ([FromForm] string name) =>
    {
        Results.Ok(name);
    }).RequireAuthorization();
}

Added this route in Program.cs

app.RegisterUserEndpoints();
app.UseAntiforgery();

From a component in the client project I plan to submit a form which will contain an image file along with other fields. However, when I try to simply post the form with simple string "name" like bellow, I get 400 Bad Request.

var formContent = new MultipartFormDataContent();
formContent.Add(new StringContent("Sample Name"), "name");
var response = await httpClient.PostAsync("/api/users/changepersonalInfo", formContent);

Here I get 400 as the response status code. What am I missing here?

Note: The routes are working if I receive data [FromBody] and send json from client.

Additional Information (Optional): My final api will be like bellow:

userGroup.MapPost("/changepersonalInfo", ([FromForm] UserViewmodel model) =>
{
    //save image and other info
}).RequireAuthorization();

and the form content will have other information like bellow:

var formContent = new MultipartFormDataContent();
formContent.Add(new StringContent(myProfile!.FirstName!), "firstName");
formContent.Add(new StringContent(myProfile!.LastName!), "lastName");
formContent.Add(new StringContent(myProfile!.PhoneNumber!), "phoneNumber");

// Add the image file
if (ImageFile != null)
{
    var imageContent = new ByteArrayContent(ImageBuffer);
    imageContent.Headers.ContentType = new MediaTypeHeaderValue(ImageFile.ContentType);
    imageContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("form-data")
        {
            Name = "profilePicture",
            FileName = ImageFile.Name
        };
    formContent.Add(imageContent);
}

var response = await httpClient.PostAsync("/api/users/changepersonalInfo", formContent);
1

There are 1 answers

0
Robin Khan On

I had to add <AntiforgeryToken /> inside my form. Then I read the value using JsRuntime and add it to the form before posting it in the server like bellow:

    var token = await JSRuntime.InvokeAsync<object>("getClosestAntiforgeryToken", "myFormId");

    if (token != null)
    {
        var tokValue = token.ToString();
        formContent.Add(new StringContent(token.ToString() ?? ""), "__RequestVerificationToken");
    }
    
    var response = await httpClient.PostAsync("/api/users/changepersonalInfo", formContent);

Here is my js function for getting the token:

function getClosestAntiforgeryToken(elementId) {
    var formElement = document.getElementById(elementId);
    console.log("form:", formElement);
    if (formElement) {
        var verificationTokenInput = formElement.querySelector('input[name="__RequestVerificationToken"]');
        console.log("field:", verificationTokenInput);
        if (verificationTokenInput) {
            var verificationTokenValue = verificationTokenInput.value;
            console.log("value:", verificationTokenValue);

            return verificationTokenValue;
        }
    }
    return null;
}