How to get HttpRequestMessage data - c#

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>();

Related

Web API [FromBody] always null

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();
...
}

WebAPI - Using a POST to do a GET's job when passing array parameters. What could go wrong?

I am new to ASP.Net WebAPI and I'm trying to use the NorthWind database to practice.
Now, I have a ProductsController which contains a GetAllProducts and a GetAllProductsById actions.
On the client-side, I have a multiselect dropdown control which is been populated with the categories of products from the CategoriesController class.
I want to populate a second dropdown control (not a multiselect) with the Products from the Categories that was selected in the category dropdown list.
My GetAllProductsById controller looks like this:
public IHttpActionResult GetAllProductsById([FromUri]int[] id)
{
using (var ctx = new NorthwindEntities())
{
<some codes...>
}
return Ok(productList);
}
Calling this service from the client, the URL look like this: http://localhost:1234/api/Products/GetAllProductsById?id=1&id=2&id=3
This is looks good with few parameters but what if the User selects more categories (let's say 30 out of 40 categories)? This means the URL would be so long.
So, I decide to use a POST to do a GET's job by decorating my action with HttpPost:
[HttpPost]
public IHttpActionResult GetAllProductsById([FromBody]int[] id)
This allows me to send the id parameters from the Body of my request.
Now, I am wondering if this style is correct or if someone can point me to a much cleaner way of passing a long list of parameters from a client to my webservice.
Thanks in advance.
NB:
Using Elasticsearch is not an option at the as suggested in the link below:
HTTP GET with request body
I tried using a modal class but it also has the same effect
http://localhost:1234/api/Products/GetAllProductsById?input.id=1&input.id=2
You could do something a bit hacky: use HTTP headers.
First the client should add the ID list as a header to its HTTP request (C# example follows):
var webRequest = System.Net.WebRequest.Create(your_api_url);
webRequest.Headers.Add("X-Hidden-List", serialized_list_of_ids);
And then on the API side:
[HttpGet]
public IHttpActionResult GetAllProductsById()
{
string headerValue = Request.Headers.GetValues("X-Hidden-List").FirstOrDefault();
if (!string.IsNullOrEmpty(headerValue))
{
var results = DeserializeListAndFetch(headerValue);
return Ok(results);
}
else
{
var results = ReturnEverything();
return Ok(results);
// or if you don't want to return everything:
// return BadRequest("Oops!");
}
}
DeserializeListAndFetch(...) and ReturnEverything() would do the actual database querying.
You can have the array of Id in a model class and in the method parameters just accept type of that class. Like
Modal Class
Public class modal
{
Public int[] Ids {get;set;}
}
Your Contoller
public IHttpActionResult GetAllProductsById([FromBody] modal m)
{
//Some logic with m.Ids
}
Your JSON if you are using any UI to consume this API
{"Ids" :[1,2,3,4,5,6]}
Hope this Helps,

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#)

ASP.net WebAPI controller directory/ routing

I am trying to do something similar to what is suggested on this site
https://mathieu.fenniak.net/stop-designing-fragile-web-apis/
It suggested that this is a better url
http://api.fbi.gov/wanted/most
My question is how do I do something like that in ASP.NET WEBAPI. For example, if I want to return a specific query of joining some data with another table, instead of passing in a parameter I just want a method url call that just does the one query I want. What is the easiest way to accomplish this task?
example url call:
api/controller/joinresultwithtable2
It's not exactly pretty but you can setup routing so a specific path maps to a specific controller and action.
config.Routes.MapHttpRoute("query1", "query/query1", new {controller="StockQueries", action="query1"});
config.Routes.MapHttpRoute("query2", "query/query2", new { controller = "StockQueries", action = "query2" });
config.Routes.MapHttpRoute("query3", "query/query3", new { controller = "StockQueries", action = "query3" });
And then have a controller that looks like this,
public class StockQueriesController : ApiController
{
[ActionName("query1")]
public HttpResponseMessage GetQuery1()
{
return new HttpResponseMessage() {Content = new StringContent("Query1")};
}
[ActionName("query2")]
public HttpResponseMessage GetQuery2()
{
return new HttpResponseMessage() { Content = new StringContent("Query1") };
}
[ActionName("query3")]
public HttpResponseMessage GetQuery3()
{
return new HttpResponseMessage() { Content = new StringContent("Query1") };
}
[ActionName("query4")]
public HttpResponseMessage GetQuery4()
{
return new HttpResponseMessage() { Content = new StringContent("Query1") };
}
}
The easiest way to go is probably attribute routing.
You can find more information here: http://attributerouting.net/
It allows you to declare any route right (with parameters) directly on an action method. That way you can control quite easily how you make your resources available.
In case you want to version your API, it's also quite easy, because you can just include the version in your attribute
If you are using ASP.NET Web API 2, you can do the following:
[Route("customers/{customerId}/orders")]
public IEnumerable<Order> GetOrdersByCustomer(int customerId) { ... }
Source: http://www.asp.net/web-api/overview/web-api-routing-and-actions/attribute-routing-in-web-api-2
You can also use following method:
[ActionName("DefaultApi")]
[Route("Api/UserLogin/DefaultApi/UserDetails")]
public IHttpActionResult UserDetails(){
return Ok(db.UserLogins.ToList());
}

Calling another controller action after the current controller action has finished executing

What I am trying to achieve:
After each view has finished executing I would like to make a separate http call to an external partner.
I need to pass one of the view's content as body of that http call.
What I have so far:
I have a base controller from which all of my controllers inherit from.
I have found that i can override the onActionExecuted() method of the base controller and write my partner http call code there so that it will be executed after each action.
I have written a custom result after reading the article at Send asp.net mvc action result inside email. which enables me to grab the content of the view. (which is part of another controller that also inherits from base controller).
What I can't figure out:
How do I make a call to the controller action (the one that will render the content for the http calls body) to get the content in my base controller onActionExecuted() method?
anil
This will call a second controller action from the first controller action within the same controller:
public ActionResult FirstAction()
{
// Do FirstAction stuff here.
return this.SecondAction(ArgumentsIfAny);
}
public ActionResult SecondAction()
{
// Do SecondAction stuff here.
return View();
}
Doesn't need to be too complicated. :-)
The idea of most MVC frameworks it to make things more simple. Everything breaks down into a call to a method with certain inputs and with certain return values. In a way, you can accomplish what you want by doing something like this:
class MyController {
public ActionResult Action1() {
// Do stuff 1
}
public ActionResult Action2() {
// Do stuff 2
}
}
You can then refactor a bit:
class MyController {
public ActionResult Action1() {
// Pull stuff out of ViewData
DoStuff1(param1, param2, ...);
}
public ActionResult Action2() {
DoStuff2(param1, param2, ...);
}
public void DoStuff1(/* parameters */) {
// Do stuff 1
}
public void DoStuff2(/* parameters */) {
// Do stuff 2
}
}
Now you can just call DoStuff1() and DoStuff2() directly because they're just methods. You can make them static if possible. Don't forget that you'll likely need to do something about error checking and return types.
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
base.OnActionExecuted(filterContext);
this.ViewData.Model = GLB_MODEL;
Stream filter = null;
ViewPage viewPage = new ViewPage();
viewPage.ViewContext = new ViewContext(filterContext.Controller.ControllerContext, new WebFormView("~/Views/Customer/EmailView.aspx", ""), this.ViewData, this.TempData);
var response = viewPage.ViewContext.HttpContext.Response;
response.Clear();
var oldFilter = response.Filter;
try
{
filter = new MemoryStream();
response.Filter = filter;
viewPage.ViewContext.View.Render(viewPage.ViewContext, viewPage.ViewContext.HttpContext.Response.Output);
response.Flush();
filter.Position = 0;
var reader = new StreamReader(filter, response.ContentEncoding);
string html = reader.ReadToEnd();
}
finally
{
if (filter != null)
{
filter.Dispose();
}
response.Filter = oldFilter;
}
}
This is modified version of code from Render a view as a string. I didn't want to render the result of the view to the httpcontext response stream.

Categories

Resources