Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I retrieve body values from an HTTP POST request in an ASP.NET Web API ValueProvider?

I want to send a HTTP POST request with the body containing information that makes up a simple blog post, nothing fancy.

I've read here that when you want to bind a complex type (i.e. a type that is not string, int etc) in Web API, a good approach is to create a custom model binder.

I have a custom model binder (BlogPostModelBinder) that in turn uses a custom Value Provider (BlogPostValueProvider). What I don't understand is that how and where shall I be able to retrieve the data from the request body in the BlogPostValueProvider?

Inside the model binder this is what I thought would be the right way to for example retrieve the title.

public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
{
   ...
   var title= bindingContext.ValueProvider.GetValue("Title");
   ...
}

while the BlogPostValueProvider looks like this:

 public class BlogPostValueProvider : IValueProvider
 {
    public BlogPostValueProvider(HttpActionContext actionContext)
    {
       // I can find request header information in the actionContext, but not the body.
    }

    public ValueProviderResult GetValue(string key)
    {
       // In some way return the value from the body with the given key.
    }
 }

This might be solvable in an easier way, but since i'm exploring Web API it would be nice to get it to work.

My problem is simply that I cannot find where the request body is stored.

Thanks for any guidance!

like image 505
Jim Aho Avatar asked Apr 05 '14 17:04

Jim Aho


People also ask

How do I get a value from the body of a Web API post?

If the parameter is a "simple" type, Web API tries to get the value from the URI. Simple types include the . NET primitive types (int, bool, double, and so forth), plus TimeSpan, DateTime, Guid, decimal, and string, plus any type with a type converter that can convert from a string.

What is FromBody and FromUri in Web API?

The [FromUri] attribute is prefixed to the parameter to specify that the value should be read from the URI of the request, and the [FromBody] attribute is used to specify that the value should be read from the body of the request.

Can we use FromBody in HTTP GET?

Please note that we are able to send [FromBody] parameter in HTTP GET Request input. Let's execute the method from Fiddler UI.


3 Answers

Here's a blog post about this from Rick Strahl. His post almost answers your question. To adapt his code to your needs, you would do the following.

Within your value provider's constructor, read the request body like this.

Task<string> content = actionContext.Request.Content.ReadAsStringAsync();
string body = content.Result;
like image 69
Alex Avatar answered Oct 25 '22 21:10

Alex


I needed to do this in an ActionFilterAttribute for logging, and the solution I found was to use the ActionArguments in the actionContext as in

public class ExternalApiTraceAttribute : ActionFilterAttribute
{


    public override void OnActionExecuting(HttpActionContext actionContext)
    {
       ...

        var externalApiAudit = new ExternalApiAudit()
        {

            Method = actionContext.Request.Method.ToString(),
            RequestPath = actionContext.Request.RequestUri.AbsolutePath,
            IpAddresss = ((HttpContextWrapper)actionContext.Request.Properties["MS_HttpContext"]).Request.UserHostAddress,
            DateOccurred = DateTime.UtcNow,
            Arguments = Serialize(actionContext.ActionArguments)
        };
like image 30
ColinM Avatar answered Oct 25 '22 19:10

ColinM


To build on Alex's answer, after you get the Raw body, you can then use Newtonsoft to deserealize it (without doing any of that complicated stuff in the blog post):

 Task<string> content = actionContext.Request.Content.ReadAsStringAsync();
 string body = content.Result;
 var deserializedObject = JsonConvert.DeserializeObject<YourClassHere>(body.ToString());

https://www.newtonsoft.com/json/help/html/deserializeobject.htm

like image 1
DReact Avatar answered Oct 25 '22 19:10

DReact