Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Support Form binding for Minimal endpoints #39430

Closed
2 of 3 tasks
rafikiassumani-msft opened this issue Jan 11, 2022 · 27 comments
Closed
2 of 3 tasks

Support Form binding for Minimal endpoints #39430

rafikiassumani-msft opened this issue Jan 11, 2022 · 27 comments
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-minimal-actions Controller-like actions for endpoint routing Needs: Design This issue requires design work before implementating. needs-user-research triage-focus Add this label to flag the issue for focus at triage
Milestone

Comments

@rafikiassumani-msft
Copy link
Contributor

rafikiassumani-msft commented Jan 11, 2022

@ghost
Copy link

ghost commented Jan 11, 2022

Thanks for contacting us.

We're moving this issue to the .NET 7 Planning milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.

@rafikiassumani-msft rafikiassumani-msft added feature-minimal-actions Controller-like actions for endpoint routing triage-focus Add this label to flag the issue for focus at triage labels Jan 11, 2022
@rafikiassumani-msft rafikiassumani-msft changed the title Form parameter binding Support Form binding for Minimal endpoints Jan 11, 2022
@rafikiassumani-msft rafikiassumani-msft added the old-area-web-frameworks-do-not-use *DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels label Jan 11, 2022
@blowdart
Copy link
Contributor

As a reminder this will require CSRF supoprt.

@rafikiassumani-msft rafikiassumani-msft added Needs: Design This issue requires design work before implementating. Priority:2 Work that is important, but not critical for the release Priority:3 Work that is nice to have needs-user-research and removed Priority:2 Work that is important, but not critical for the release labels Jan 11, 2022
@devjuanca
Copy link

I strongly belive this should be a priority!!

@CarlEdZa
Copy link

This has many uses and isn't what I would call a frivolous request.
Many people have smashed their heads into this issue upgrading older code.
The workaround is not pretty and can introduce confusion.

@martincostello
Copy link
Member

This is waiting on #38630.

@ghost
Copy link

ghost commented Jun 14, 2022

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

@ak-hasanuzzaman
Copy link

This is a show-stopper for us. We have got objects with plenty of properties (web pages with a long list of fields) in them that too with files (i.e. text, pdf, etc.). So, if there is no support for [FromForm], we have to go back to the controllers which we desperately would like to avoid. @DamianEdwards and @davidfowl please consider adding the in the next release. 🙏🙏🙏

@davidfowl
Copy link
Member

What's the API scenario for form posts?

@martincostello
Copy link
Member

Isn't this "done" now as of 7.0 preview 7?

@ak-hasanuzzaman
Copy link

ak-hasanuzzaman commented Aug 10, 2022

What's the API scenario for form posts?

@davidfowl , Thanks for your quick reply. Let's assume there is a product registration page where the product (class) has a bunch of properties, which has got some complex objects in it as well. In addition, each of the complex objects along with the product has a property to receive files (List<IFormFile> Files { get; set; } ). So it would be really helpful to have an option to receive it all via [FromForm] instead of finding everything from the HttpContext and applying some mapping. Mapping from the HttpContext can be tedious, and error-prone, which can easily be avoided with [FromForm], the way it works for the controller.

@davidfowl
Copy link
Member

Isn't this "done" now as of 7.0 preview 7?

Files are supported but we have no intention of supporting forms for APIs.

@ak-hasanuzzaman Thanks for that. Can you elaborate more about the client, what sort of client is this and what does that code look like that produced the form and what is making the post and what does that code look like?

@ak-hasanuzzaman
Copy link

ak-hasanuzzaman commented Aug 10, 2022

@davidfowl, The client is a react application, where we use axios to post data to the backend. The following is an example where an object and other complex objects in it, they do have the option to attach files. Eventually, we need to construct a big object and post it to the backend.

For example, the post method looks like somewhat similar to the one below (contrived example):

The point I am trying to make is to have the option to post data in one stroke. If you are not willing to support forms what are the alternatives when it comes to, posting data with everything in one go?

If you want me to clarify even more, please let me know. Thanks again.

@davidfowl
Copy link
Member

davidfowl commented Aug 10, 2022

Where's the form? I'd like to see the syntax of the form and how it was created (the syntax used for the fields). The thing I'm trying to understand the serialization format of your fields. Are you using the html helpers from mvc?

@brockallen
Copy link

What's the API scenario for form posts?

FWIW the OAuth and OIDC specs require form-url-encoded requests payloads for all its programmatic endpoints. So there's an example for you.

https://www.rfc-editor.org/rfc/rfc6749.html#section-3.2

@davidfowl
Copy link
Member

I'm actually OK with very simple form binding. I am not ok with lists, dictionaries, and the custom serialization format the MVC currently supports.

@thesn10
Copy link

thesn10 commented Aug 16, 2022

This is a major problem.

I have to transmit BOTH files AND parameters in the same request, which is ONLY possible using FormData!

Example:

POST /user/edit

- user id (request parameter)
- user name (request parameter)
- profile picture (file)

The profile picture file already uses the body so how should i transmit the request parameters? Only FormData can transmit both at the same time!

Other methods don't work:

  • query string
    DOESNT WORK: should only be used in a GET request because it is against the spec to use query sting in a POST request, and is a security risk.
  • json
    DOESNT WORK: can't use body because body is already used to transmit the file
  • raw data
    DOESNT WORK: can't use body because body is already used to transmit the file
  • encoded data
    DOESNT WORK: can't use body because body is already used to transmit the file
  • file
    DOESNT WORK: can't use body because body is already used to transmit the file
  • formdata
    WORKS! FormData serializes BOTH files AND parameters inside the body

The only option is FORM DATA !

I hope you understand the importance now.

@davidfowl
Copy link
Member

We'll investigate in .NET 8.

@ak-hasanuzzaman
Copy link

ak-hasanuzzaman commented Aug 16, 2022

@Sngmng Thanks for bringing it up mate. @davidfowl I have got something similar. I find the minimal API approach incredible for all the good reasons. But to POST other parameters with the file(s) does require [FormData]. To circumvent that issue we are using a handful of controller endpoints and the rest is minimal which was the only option we were left with.

It will be absolutely great if we could get away with the controllers completely by having the [FormData].

Thanks.

@davidfowl
Copy link
Member

Other methods don't work:

From JavaScript for sure, I looked into this last week and I couldn't find a way to do a multi part post with the fetch APIs. So FormData is the only viable approach for forms + metadata it seems.

Generally multipart posts supports sending different content types in the same request, but it's not common.

@DamianEdwards DamianEdwards removed the Priority:3 Work that is nice to have label Aug 30, 2022
@DamianEdwards DamianEdwards removed their assignment Aug 30, 2022
@waynebrantley
Copy link

@davidfowl thanks for considering.
A simple example is a form where you put two text boxes and a place to upload a file.
The user fills out those text fields, adds a file to upload and clicks 'submit'.

The only way to send the file and the simple text fields is a form. I wish there was another way, but there is not.
Always very simple form binding - just ints/strings/etc.
Hate this did not get additional consideration to be included in .NET 7 - lets cross fingers for 8.

(We have converted every endpoint to minimal APIs except for these - we have to leave as classic controllers...so not a deal breaker, just not clean)

@IeuanWalker
Copy link

IeuanWalker commented May 31, 2023

Hi, just checking if the work being done here will support a list of IFormFiles and lists of other objects as formdata?

This seams like quite a standard thing that should be built in by default.

My scenario -
Im building a centralised email system that all our system will be able to utilise. The api has the following properties -

  • body - string
  • Attachments - List<IFormFile>
  • Recipients - List<Recipient> (the recipient model contains 'name' and 'email'
    -etc

As this is a mixture of data and files formdata is the only valid option

@DamianEdwards
Copy link
Member

DamianEdwards commented May 31, 2023

Yes the below works as of 8.0.0-preview.4. Note that binding to complex objects or enumerables of complex objects is not directly supported though, so to populate your List<Recipient> you'll need to create them manually from the bound primitives, or create a custom type to bind to that implements BindAsync for the whole request body.

image

Note however that arrays of primitives are supported:

image

@IeuanWalker
Copy link

Thanks @DamianEdwards

Is there any docs or articles that demonstrate this?

Note that binding to complex objects or enumerables of complex objects is not directly supported though, so to populate your List you'll need to create them manually from the bound primitives, or create a custom type to bind to that implements BindAsync for the whole request body

@DamianEdwards
Copy link
Member

See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/minimal-apis/parameter-binding?view=aspnetcore-7.0#bindasync for docs

You could also take a look at https://github.com/DamianEdwards/MinimalApis.Extensions for some examples of implementing custom helpers/wrappers for binding.

@amcasey amcasey added the area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc label Jun 2, 2023
@captainsafia captainsafia removed the old-area-web-frameworks-do-not-use *DEPRECATED* This label is deprecated in favor of the area-mvc and area-minimal labels label Jun 6, 2023
@kzhui125
Copy link

I think we should keep the same behavior for minimal api and mvc controller (also see #49437 )

The inconsistence will make people confuse.

For example: in mvc controller:
IFormFileCollection files1 will only get those fileContents with name files1.
IFormFileCollection files2 will only get those fileContents with name files2.

But in minimal api, IFormFileCollection files1 and IFormFileCollection files2 both get all files.

app.MapPost("/MinimalApi/Upload", async (
    string testStr,
    int testInt,
    IFormFileCollection files1,
    IFormFileCollection files2,
    IFormFile file1,
    IFormFile file2) =>
{
    await Task.CompletedTask;
    return Results.Ok(files1.Count);
});

[HttpPost("Upload")]
public async Task<IActionResult> Upload(
    [FromForm] string testStr,
    [FromForm] int testInt,
    [FromForm] IFormFileCollection files1,
    [FromForm] IFormFileCollection files2,
    [FromForm] IFormFile file1,
    [FromForm] IFormFile file2)
{
    return NoContent();
}

MultipartFormDataContent content = new()
{
    // file
    { fileContent1, "files1", "Files1_1.txt" },
    { fileContent2, "files1", "Files1_2.txt" },
    { fileContent3, "files2", "Files2_1.txt" },
    { fileContent4, "files2", "Files2_2.txt" },
    { fileContent5, "file1", "File1.txt" },
    { fileContent6, "file2", "File2.txt" },

    // payload
    { new StringContent("Hello"), "testStr" },
    { new StringContent("1"), "testInt" },
};

var response = await httpClient.PostAsync(url, content);
response.EnsureSuccessStatusCode();

@davidfowl
Copy link
Member

Minimal API won’t be implementing model binding so there’s behavior inconsistency already. For this particular issue it might be worth considering a way to make the behavior consistent with MVC (maybe opt in)

@captainsafia
Copy link
Member

We've shipped support for form-binding in Minimal APIs as of .NET 8. Closing this for now. We'll track follow-up work in other issues.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
area-minimal Includes minimal APIs, endpoint filters, parameter binding, request delegate generator etc feature-minimal-actions Controller-like actions for endpoint routing Needs: Design This issue requires design work before implementating. needs-user-research triage-focus Add this label to flag the issue for focus at triage
Projects
No open projects
Status: In Progress
Development

No branches or pull requests