61

I'm sending a request to server in the following form:

http://localhost:12345/api/controller/par1/par2

The request is correctly resolved to a method like:

[HttpPost]
public void object Post(string par1, string par2)

However, I pass additional data through the request content. How can I retrieve these data?

For the sake of example, let's say, that the request is sent from the form:

<form action="http://localhost:12345/api/controller/par1/par2" method="post">
    <input type="hidden" name="data" value="value" />
    <input type="submit" name="submit" value="Submit" />
</form>
5
  • 3
    @JonnyS It did. It's a shame though, that you, in turn, did not, because otherwise I could have accepted your answer :) Commented Jul 24, 2013 at 12:23
  • 2
    duplicate of stackoverflow.com/questions/13120971/… Commented Sep 27, 2013 at 14:11
  • 1
    @drzaus - This appears to have multiple possible duplicates, including the one you mentioned as well as this one: stackoverflow.com/questions/11593595/… Commented Oct 16, 2014 at 0:58
  • @ArtOfWarfare yeah I try to get share the earliest "original" I can find Commented Oct 16, 2014 at 14:32
  • 1
    Possible duplicate of How to get Json Post Values with asp.net webapi Commented Jan 8, 2019 at 10:06

9 Answers 9

71

From answer in this question: How to get Json Post Values with asp.net webapi

  1. Autoparse using parameter binding; note that the dynamic is made up of JToken, hence the .Value accessor.

    public void Post([FromBody]dynamic value) {
        var x = value.var1.Value; // JToken
    }
    
  2. Read just like Request.RequestUri.ParseQueryString()[key]

    public async Task Post() {        
       dynamic obj = await Request.Content.ReadAsAsync<JObject>();
       var y = obj.var1;
    }
    
  3. Same as #2, just not asynchronously (?) so you can use it in a helper method

    private T GetPostParam<T>(string key) {
        var p = Request.Content.ReadAsAsync<JObject>();
        return (T)Convert.ChangeType(p.Result[key], typeof(T)); // example conversion, could be null...
    }
    

Caveat -- expects media-type application/json in order to trigger JsonMediaTypeFormatter handling.

Sign up to request clarification or add additional context in comments.

2 Comments

in the 3rd sample you can also use return p.Result[key].Value<T>();
@ManuelKoch Thanks. I'd like to think they added that convenience within the last 4 years ;)
22

After spending a good bit of time today trying to wrap my brain around the (significant but powerful) paradigm shift between old ways of processing web form data and how it is done with WebAPI, I thought I'd add my 2 cents to this discussion.

What I wanted to do (which is pretty common for web form processing of a POST) is to be able to grab any of the form values I want, in any order. Say like you can do if you have your data in a System.Collections.Specialized.NameValueCollection. But turns out, in WebAPI, the data from a POST comes back at you as a stream. So you can't directly do that.

But there is a cool little class named FormDataCollection (in System.Net.Http.Formatting) and what it will let you do is iterate through your collection once.

So I wrote a simple utility method that will run through the FormDataCollection once and stick all the values into a NameValueCollection. Once this is done, you can jump all around the data to your hearts content.

So in my ApiController derived class, I have a post method like this:

    public void Post(FormDataCollection formData)
    {
        NameValueCollection valueMap = WebAPIUtils.Convert(formData);

        ... my code that uses the data in the NameValueCollection
    }

The Convert method in my static WebAPIUtils class looks like this:

    /// <summary>
    /// Copy the values contained in the given FormDataCollection into 
    /// a NameValueCollection instance.
    /// </summary>
    /// <param name="formDataCollection">The FormDataCollection instance. (required, but can be empty)</param>
    /// <returns>The NameValueCollection. Never returned null, but may be empty.</returns>
    public static NameValueCollection Convert(FormDataCollection formDataCollection)
    {
        Validate.IsNotNull("formDataCollection", formDataCollection);

        IEnumerator<KeyValuePair<string, string>> pairs = formDataCollection.GetEnumerator();

        NameValueCollection collection = new NameValueCollection();

        while (pairs.MoveNext())
        {
            KeyValuePair<string, string> pair = pairs.Current;

            collection.Add(pair.Key, pair.Value);
        }

        return collection;
     }

Hope this helps!

4 Comments

A variant on this is public void Post(Dictionary<string,string> formData) which also works
@LeandroTupone This is not a copy of Brandon Bearden's Answer: stackoverflow.com/a/23943276/555798 However, Brad did base his answer off of Scott Stone's (without reference to him or a link to the duplicate question): stackoverflow.com/a/26393562/555798 I am happy for the answer though, because it was here that I found I needed to use FormDataCollection for my WebHook to work with another vendor.
FormDataCollection seems to be for WebApi as FormCollection is for mvc controllers! This worked for me!
This seems like the right answer but didn't work for me.
13

I had a problem with sending a request with multiple parameters.

I've solved it by sending a class, with the old parameters as properties.

<form action="http://localhost:12345/api/controller/method" method="post">
    <input type="hidden" name="name1" value="value1" />
    <input type="hidden" name="name2" value="value2" />
    <input type="submit" name="submit" value="Submit" />
</form>

Model class:

public class Model {
    public string Name1 { get; set; }
    public string Name2 { get; set; }
}

Controller:

public void method(Model m) {
    string name = m.Name1;
}

Comments

9

It is hard to handle multiple parameters on the action directly. The better way to do it is to create a view model class. Then you have a single parameter but the parameter contains multiple data properties.

public class MyParameters
{
    public string a { get; set; } 
    public string b { get; set; }
}

public MyController : ApiController
{
    public HttpResponseMessage Get([FromUri] MyParameters parameters) { ... }
}

Then you go to:

http://localhost:12345/api/MyController?a=par1&b=par2

Reference: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api

If you want to use "/par1/par2", you can register an asp routing rule. eg routeTemplate: "API/{controller}/{action}/{a}/{b}".

See http://www.asp.net/web-api/overview/web-api-routing-and-actions/routing-in-aspnet-web-api

Comments

6

Try this.

public string Post(FormDataCollection form) {
    string par1 = form.Get("par1");

    // ...
}

It works for me with webapi 2

Comments

4

I found for my use case this was much more useful, hopefully it helps someone else that spent time on this answer applying it

public IDictionary<string, object> GetBodyPropsList()
        {
            var contentType = Request.Content.Headers.ContentType.MediaType;
            var requestParams = Request.Content.ReadAsStringAsync().Result;

            if (contentType == "application/json")
            {
                return Newtonsoft.Json.JsonConvert.DeserializeObject<IDictionary<string, object>>(requestParams);
            }
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
        }

Comments

4

None of the answers here worked for me. Using FormDataCollection in the post method seems like the right answer but something about my post request was causing webapi to choke. eventually I made it work by including no parameters in the method call and just manually parsing out the form parameters like this.

public HttpResponseMessage FileUpload() {
    System.Web.HttpRequest httpRequest = System.Web.HttpContext.Current.Request;
    System.Collections.Specialized.NameValueCollection formData = httpRequest.Form;
    int ID = Convert.ToInt32(formData["ID"]);
    etc

Comments

2

Is there a way to handle form post data in a Web Api controller?

The normal approach in ASP.NET Web API is to represent the form as a model so the media type formatter deserializes it. Alternative is to define the actions's parameter as NameValueCollection:

public void Post(NameValueCollection formData)
{
  var value = formData["key"];
}

1 Comment

This works very well for quick testing but as we are using a strict language a class model should be created like the answer by @Corné Strijkert
0
    ON WEB API.


    [HttpGet]
    [Route("api/Get_EXCUTA_PROCEDURE_IBESVNDACMVDD")]
    public IHttpActionResult Get(int CodigoPuxada...)
    {
        string retornoErro = string.Empty;
        try
        {
            //int codigoPuxada = entrada.CodigoPuxada;

            SetKeyAtual(CodigoPuxada);

            var repo = new ItemBroker_Dim_Canal_BookRepositorio(ConnectionString);

            try
            {
                var dadosRetorno = repo.ExcuteProcedure_Busca_vbc_(CodigoPuxada,...); //  method return object  (dataset)
                return Ok(dadosRetorno);
            }
            catch
            {
                throw;
            }
        }
        catch (Exception ex)
        {
            retornoErro = ex.Message;
            if (ex.InnerException != null)
                retornoErro = ex.InnerException.ToString();
        }

        return Ok(retornoErro); 
    }


    Other projet invoke web api...
    (USING RESTSHARP DLL)

    RestClient clientHttpPost1 = null;
    string dadosVbc123 = string.empty;
                
    clientHttpPost1 = new RestSharp.RestClient($"{urlWebApiAvante}Get_EXCUTA_PROCEDURE_IBESVNDACMVDD?CodigoPuxada=...");

    RestSharp.RestRequest request2 = new RestSharp.RestRequest(RestSharp.Method.GET);
    request2.RequestFormat = RestSharp.DataFormat.Json;
    request2.AddHeader("Content-Type", "application/json;charset=utf-8");
    string strAux1 = string.Empty;
    request2.Timeout = 180000;
    RestSharp.IRestResponse response = clientHttpPost1.Execute(request2);
    if ((response != null) && response.StatusCode == System.Net.HttpStatusCode.OK)
    {
        try
        {
            var dataObjects = response.Content.ToString().Trim();
            dadosVbc123 = dataObjects.ToString().Replace("\t", "");
            if (dadosVbc123.Trim() == "{\"IBESVNDACMVDD\":[]}")
            dadosVbc123 = string.Empty;
        }
        ...
    }

    //  converting  JSON to dataset
    string val1 = dadosVbc123.Replace("{\"IBESVNDACMVDD\":", "").Replace("}]}", "}]");
    DataTable dtVBC123 = (DataTable)Newtonsoft.Json.JsonConvert.DeserializeObject(val1, (typeof(DataTable)));

1 Comment

Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.