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#)
Related
I am calling an external API from my Asp.Net Web Api.. I am testing it using swagger and from swagger i am passing array of DepartmentCodes as ["IT","HR"] , when i am testing it using swagger the API is failing because of the DepartmenCodes array.
I am posting only partial code here as the issue is only with the string[] values being passed from swagger.
public async Task<IHttpActionResult> GetUsers([FromUri] GetUserRequest getUserRequest)
{
UserRequest userRequest = new UserRequest();
userRequest.DepartmentCodes = getUserRequest.DepartmentCodes;
using (var Client = new HttpClient())
{
//code to call external api
}
}
Public Class UserRequest
{
Public string[] DepartmentCodes {get;set;}
}
Public Class GetUserRequest
{
Public string[] DepartmentCodes {get;set;}
}
When i am hardcoding the DepartmentCodes array in the code, the API is working as expected and i am getting the result.
public async Task<IHttpActionResult> GetUsers([FromUri] GetUserRequest getUserRequest)
{
UserRequest userRequest = new UserRequest();
userRequest.DepartmentCodes = new string[] {"IT", "HR"};
//userRequest.DepartmentCodes = getUserRequest.DepartmentCodes;
using (var Client = new HttpClient())
{
//code to call external api
}
}
In order for the API to work with swagger, do we have to make any change in the code or do i need to change the way i am passing string array from swagger.. currently from swagger i am passing the string array as ["IT, HR"]
I figured it out, It worked when i tried posting the string array values from swagger in the below way
IT
HR
There shouldn't be any double quotes, commas or any other special characters...
i have this order controller and the method below.
how can i call this method from java?
the link is also available online under: http://www.life-projects.com/api/orders
public class OrdersController : ApiController
{
[HttpPost]
public String Add(String order)
{
return "test string";
}
}
this is the code that tries to access the method
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://www.life-projects.com/api/orders");
httppost.setEntity(new StringEntity(Order_Data));
HttpResponse resp = httpclient.execute(httppost);
HttpEntity ent = resp.getEntity();
someone tries to call the post method and it doesn't work.
why?
thanks,
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());
}
I'm new to MVC Web Api but I have some experience working with ServiceStack framework. Some of the web api examples look a lot like RPC with more action methods and less parameters. In fact most examples seem to limit the request parameter to an id. I would like to create some reporting services using request/response because the request gets quite complex with all the reporting criteria.
Here's my simplified request / response types:
public class PendingRequest
{
public string Id { get; set; }
public int AccountId { get; set; }
public DateTime? FromDate { get; set; }
public DateTime? ToDate { get; set; }
}
public class PendingResponse
{
public string Id { get; set; }
public IEnumerable<Pending> Data { get; set; }
}
And my outline reports controller:
public class ReportsController : ApiController
{
public async Task<PendingResponse> GetPending(PendingRequest request)
{
return new PendingResponse
{
Id = request.Id,
// Data = await Repo.GetPending()
};
}
public async Task<ShippedResponse> GetShipped(ShippedRequest request)
{
return new ShippedResponse
{
Id = request.Id,
// Data = await Repo.GetShipped()
};
}
public async Task<ProductsResponse> GetProducts(ProductsRequest request)
{
return new ProductsResponse
{
Id = request.Id,
// Data = await Repo.GetProducts()
};
}
}
And my routing and config for a self-hosting app:
class Program
{
static void Main()
{
var config = new HttpSelfHostConfiguration("http://localhost:8080");
config.Routes.MapHttpRoute(
name: "Reports",
routeTemplate: "api/reports/{action}",
defaults: new
{
controller = "Reports"
});
using (var server = new HttpSelfHostServer(config))
{
server.OpenAsync().Wait();
Console.WriteLine("Press Enter to quit.");
Console.ReadLine();
}
}
}
So with this routing I intend the action to be the name of the report. Note i've not included the request parameter here. Not sure if I should or not.
The problem is actually on the client side. With the HttpClient the GetAsync method does not allow me to include the JSON request object. I see an extension method PostAsJsonAsync but surely this shouldn't be a POST? Without a GetAsJsonAsync or similar then I can't see a way of including a request with a GET?
To be honest I prefer ServiceStack but there appears to be no async support yet. I need to develop some high performance services which are I/O intensive and I want to reduce the blocking as much as possible.
UPDATE:
It seems Web Api will perform the model binding if, rather than using the request body, I include the model's parameters as part of the query string. In order for this to work, the Get method needs to prefix the model type with the [FromUri] attribute, which informs the model binder that the model should be constructed from the request query string. Messy, but works.
[ActionName("Pending")]
public async Task<PendingResponse> GetPending([FromUri] PendingRequest request)
{
return new PendingResponse
{
Id = request.Id,
// query = ...build from request params
// Data = await Repo.GetPending(query)
};
}
And now on the client side I perform the following:
var result = await _httpClient.GetAsync("api/reports/pending?Id=123&AccountId=456");
result.EnsureSuccessStatusCode();
var response = await result.Content.ReadAsAsync<PendingResponse>();
A call to the service results in the GetPending method being called with a copy of the PendingRequest object materialised from the supplied query string parameters.
The fundamental problem here is you are trying to provide a request body to HTTP GET, which is not allowed. Well, you can still go ahead and format a GET with request body and submit it but that is not according to the spec. Strictly speaking, HTTP spec does not forbid GET requests from having a body but the response for a GET request must not change based on the request body, which basically means you cannot use search criteria in the GET request body. You can use the URI path and query string to specify the search criteria and if you want to bind them into a complex type parameter, you will need to use [FromUri] like this: public async Task<PendingResponse> GetPending([FromUri]PendingRequest request).
Bit of a guess, but what about just URL encoding the JSON request object and putting it in the query string segment of the GET URI?
Also, you might need [FromUri] attribute on your request method parameter in the action as it is a complex type. I may have missed something, but this article on parameter binding doesn't mention anything about GET being a special case for complex types, hence I think they will always try and read from the POST body.
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>();