Web API [FromBody] always null - c#

Im currently creating a Web API that writes into a table. Im using [FromBody] tag to pass the values for the table.
The problem is that the [FromBody] value is always null. Im using Advanced Rest Client to test my API.
public HttpResponseMessage Post(int id, [FromBody]string value)
{
//DO Something
}

The problem is in the type conversion. You are sending an array with one value containg a dictionary and trying to recieve a string in the method. ASP.NET can't cast your structure to string and use null as default value.
So, the simple way to test method is to pass a simple string in body. But the right way is to change the type of object passing into action method:
public HttpResponseMessage Post(int id, [FromBody]List<Dictionary<string,string>> value)
{
//DO Something
}
It’s strange to parse JSON manually when the system does it, but then you should pass string to the method. Just wrap your body to "" and you'll get a plain JSON in the method. Also you can read body manually via StreamReader:
public HttpResponseMessage Post(int id)
{
using (StreamReader reader = new StreamReader(Request.Body, Encoding.UTF8))
{
var plainBody = reader.ReadToEnd();
}
}

If you don't want the body deserialized, you can just read the string from the Request.Body property.
public Task<HttpResponseMessage> Post(int id)
{
var reader = new StreamReader(Request.Body);
var bodyString = await reader.ReadToEndAsync();
...
}

Related

how to consume post data when content type isapplication/x-www-form-urlencoded .net core

I have a use case where i need to accept application/x-www-form-urlencoded post data and also consume querystring
[httpPost]
public void GetDetails([FromQuery] username)
{
using (var reader = new StreamReader(Request.Body))
{
try
{
var line = await reader.ReadToEndAsync();
}
catch(exception ex)
{
//Do something
}
}
}
For that when i try above Request.Body stream is null,
I have a solution to remove [FromQuery] and read querystring via Reqeust.QueryString but do we have any other options
[FromQuery] and [FromForm] can be used in conjunction with each other to bind parameters.
[HttpPost]
public IActionResult GetDetails([FromQuery] string username, [FromForm] string formData) {
//...Do something
return Ok();
}
While the above example is taking the form data in a string, it can also be used to bind to more complex objects if needed.
Reference Model Binding in ASP.NET Core

ASP.NET - Call and handle Web API with multiple different parameters

I am new to Web API and I have question that can not resolve.
This is my question: how call a Web API that need multiple parameters (stream or object and two or three string)? And how handle this parameters inside Web API?
For example, I have this method in my Web API:
public class MyController : ApiController
{
[HttpPost]
public MyObject Method(Stream s, string first, string second)
{
// take the parameters and do something
}
}
Where Stream is a stream of file (or an object in other cases).
How can add all these parameters to client request body? And how take them from there and use in the method?
EDIT:
this solution is good?
Here the client:
{
var client = new HttpClient();
var queryString = HttpUtility.ParseQueryString(string.Empty);
queryString["first"] = "true";
queryString["second"] = "false";
var uri = "https://myapi.com/api/mycontroller/method?" + queryString;
HttpResponseMessage response;
byte[] byteData = Encoding.UTF8.GetBytes(myFile);
using (var content = new ByteArrayContent(byteData))
{
content.Headers.ContentType = new MediaTypeHeaderValue("<application/json >");
response = await client.PostAsync(uri, content);
}
}
And here the Web API:
[HttpPost]
public MyObject Method([FromBody]Stream s, [FromUri]string first, [FromUri]string second)
{
//do something
}
WebApi does not support to passing multiple parameter in this way, simply you can create a dto/model class and pass that class from body to the method.
public class Foo
{
public Byte[] s {get;set;}
public string first {get;set;}
public string second {get;set;}
}
WepApi controller:
public HttpResponseMessage Register([FromBody] Foo foo)
{
//do something
return Ok();
}
Update:
If you don't want to create classes for your each methods. Then you can use like following one, but recommend to use first one.
public HttpResponseMessage Register([FromBody]dynamic value)
{
//convert to attribute
string first = value.first.ToString();
string second = value.second.ToString();
}
Here is good read: Getting Started with ASP.NET Web API 2 (C#)

Trying to read querystring in C#

I am a newbie when it comes to C#, but I need to use it for a project at work.
I am building a web page that is using jQuery to call a C# program. The C# program will connect to a SQL server, retrieve data for agencies and return it to the calling webpage as JSON.
I have all that working, I can get both a single agency and a collection of agencies and return it properly. Below is the code:
public class AgencyController : ApiController
{
// GET: api/Agency
public List<AgencyData> Get()
{
//var queryValues = Request.RequestUri.ParseQueryString();
//string filter = queryValues.Get("filter").ToString();
List<AgencyData> json;
json = SQLAllAgencyData("");
return json;
}
// GET: api/Agency/5
public List<AgencyData> Get(string id)
{
List<AgencyData> json;
json = SQLAgencyData(id);
return json;
}
What I want to do now is to be able to pass additional information to the C# program. Something like this:
www.domain.com/api/Agency?state=TX&city=Dallas
I can not figure out how to do that. All the examples I found result in build errors.
Here are a couple of links I tried:
http://forums.asp.net/t/1072321.aspx?How+to+get+parameter+in+url+by+C+for+net
Is there a way to get all the querystring name/value pairs into a collection?
You can also see the two commented out line in my code, they also don't work.
I figure that Request is never set to anything, or defined/declared, but I haven't been able to find an example of how to do that.
Suggestions?
There is no need to read the query string, the WEB API model binder will bind any query string parameters to parameters of your action method... I have never known a scenario where I needed to manually parse the query string
With Attribute Routing:
Attribute routing allows you to specifiy nullable parameters, you will need to enable attribute routing which you can find hundreds of tutorials on.
[Route("Agency/{state?}/{city?}")
public List<AgencyData> Get(string state = null, string city = null)
{
List<AgencyData> json;
json = SQLAllAgencyData("");
return json;
}
This would make the url look like this...
http://xxxxxx.com/api/Agency/Texas/Dallas
I am however almost sure your query string syntax would work too however you will need to try that.
Without Attribute Routing:
If you do not want to add attribute routing to Web API you can also add overloaded action methods to the controller..
// /api/Agency
public List<AgencyData> Get()
{
var json = SQLAllAgencyData("");
return json;
}
// /api/Agency?state=texas&city=dallas
public List<AgencyData> Get(string state, string city)
{
// Params will be equal to your values...
var json = SQLAllAgencyData("");
return json;
}
EDIT: Turns out there is no need to overload the action method... simply set the parameter defaults to null... (overload seems cleaner though)
// /Agency/
// /Agency?state=Texas&city=Dallas
public List<AgencyData> Get(string state = null, string city = null)
{
// Check for null.. etc.
}
Edit: To make this work I have used the default routing config...
public static void Register(HttpConfiguration config)
{
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
if you want state and city as parameter of method than just add that to parameter of your method and parameters name should match with query string parameter names
Get(String state, String city)
You can directly accept the query parameters as method parameters and the query string values can be used in your method.
public List<AgencyData> Get(String state, String city)
{
//var queryValues = Request.RequestUri.ParseQueryString();
//string filter = queryValues.Get("filter").ToString();
List<AgencyData> json;
json = SQLAllAgencyData("");
return json;
}

How to get HttpRequestMessage data

I have an MVC API controller with the following action.
I don't understand how to read the actual data/body of the Message?
[HttpPost]
public void Confirmation(HttpRequestMessage request)
{
var content = request.Content;
}
From this answer:
[HttpPost]
public void Confirmation(HttpRequestMessage request)
{
var content = request.Content;
string jsonContent = content.ReadAsStringAsync().Result;
}
Note: As seen in the comments, this code could cause a deadlock and should not be used. See this blog post for more detail.
using System.IO;
string requestFromPost;
using( StreamReader reader = new StreamReader(HttpContext.Current.Request.InputStream) )
{
reader.BaseStream.Position = 0;
requestFromPost = reader.ReadToEnd();
}
I suggest that you should not do it like this.
Action methods should be designed to be easily unit-tested. In this case, you should not access data directly from the request, because if you do it like this, when you want to unit test this code you have to construct a HttpRequestMessage.
You should do it like this to let MVC do all the model binding for you:
[HttpPost]
public void Confirmation(YOURDTO yourobj)//assume that you define YOURDTO elsewhere
{
//your logic to process input parameters.
}
In case you do want to access the request. You just access the Request property of the controller (not through parameters). Like this:
[HttpPost]
public void Confirmation()
{
var content = Request.Content.ReadAsStringAsync().Result;
}
In MVC, the Request property is actually a wrapper around .NET HttpRequest and inherit from a base class. When you need to unit test, you could also mock this object.
In case you want to cast to a class and not just a string:
YourClass model = await request.Content.ReadAsAsync<YourClass>();

ASP.NET WebApi not receiving post data

I need to receive some string and binary data using WebApi. I have created a controller this way:
[HttpPost]
public void Post(byte[] buffer)
{
// Some code goes here
}
Here's the routtings:
routes.MapHttpRoute(
name: "CuscarD95B",
routeTemplate: "D95B/{controller}",
defaults: new { buffer = RouteParameter.Optional },
constraints: new { controller = #"Cuscar" }
Now when I try to post some data, buffer is always byte[0] (zero length array). No data is being passed to the controller.
Any help would be appreciated.
Thanks.
If you are ever struggling with deserializing a body, try and do it manually to see if you are actually sending it correctly.
[HttpPost]
public void Post()
{
string body = Request.Content.ReadAsStringAsync().Result;
}
We passed Json object by HttpPost method, and parse it in dynamic object. it works fine. this is sample code:
ajaxPost:
...
Content-Type: application/json,
data: {"name": "Jack", "age": "12"}
...
Web API:
[HttpPost]
public string DoJson2(dynamic data)
{
string name = data.name;
int age = data.age;
return name;
}
If there is complext object type, you need to parse the dynamic type by using:
JsonConvert.DeserializeObject< YourObjectType >(data.ToString());
A complex data content sample is here, it includes array and dictionary object:
{"AppName":"SamplePrice","AppInstanceID":"100","ProcessGUID":"072af8c3-482a-4b1c‌​-890b-685ce2fcc75d","UserID":"20","UserName":"Jack","NextActivityPerformers":{"39‌​c71004-d822-4c15-9ff2-94ca1068d745":[{"UserID":10,"UserName":"Smith"}]}}
I was able to post a byte[] in my request body, and the value was successfully model bound. Was the content-type set? Note that simple string is considered to be valid JSON here, and so it should work if your request's content-type is set to application/json...
Having said that, you can simply have your POST method that expects a string from the body instead of a byte[] and set the content-type to be application/json:
[HttpPost]
public void Post([FromBody]string buffer)
{
// Some code goes here
}
I am not sure how to send byte[] to webApi, but what you can do is to pass the binary data as Base64 string to your controller and then convert the base64 string to the byte[].
I found the solution here.
Looks like we need to create custom MediaTypeFormatter to achieve primitive type deserialization.
Did you try to use the HttpPostedFileBase without [FromBody] ?
public void Post(HttpPostedFileBase buffer)
I had a similar situation where I was using a string array and it would always come through null or I would get an exception about an improperly formatted request. I added the annotation [FromUri] in my method parameters then it worked. To give a little more context, my controller method looked like this before:
public async Task<IHttpActionResult> MyControllerName(List<string> id)
After:
public async Task<IHttpActionResult> MyControllerName([FromUri] List<string> id)

Categories

Resources