how do i pass two complex parameters, say two class objects, when i call HttpClient.GetAsync ?
I understand we could add it along the url if its simple parameters like string. But when it is complex ones such as class, how do we do it ?
use HttpClient.PostAsync
if you want to send complex data, and not just simple string
also on the server side, check if the api accepts post requests
you can test requests using http://Hurl.it
Related
I have an angular client and want to execute a get request to my web api backend to get a list of items from the underlying Dapper Db Wrapper. Dapper allows me to pass in parameters as an anonymous object which would in csharp look like this:
connection.GetList<T>(new {myParam1:"a", myParam2: true});
What I want to achieve is, to create this parameter object in my angular frontend and pass it in a post request to the server which would then pass it on to the GetList function. The problem here is that the web api does not deserialize it as an (anonymous) object, but rather and IEnumerable of JTokens?
My web api signature is this:
public async Task<IHttpActionResult> MyFunction([FromBody]dynamic whereCond)
I have also tried to pass the object as string wrapped in an outer object like so (angular client):
this.migController.MigrationGetMigrationReports({whereCond: JSON.stringify({NotMigrated: true, MissingTargetFiles: 0})})
and then on the server I manually deserialize it as JObject:
string obj = whereCond.whereCond;
dynamic pObj = JObject.Parse(obj);
But this results in the exact same result: pObj is an IEnumerable and therefore I get an error message from the GetList call:
An enumerable sequence of parameters (arrays, lists, etc) is not allowed in this context
can anybody help?
The answer to my question turned out rather simple:
dynamic pObj = JObject.Parse(obj).ToObject<ExpandoObject>();
I had to cast it as ExpandoObject not just dynamic.
#Tsahi: this is not a design problem. My intention was to provide the server with parameters (filter) which is a quite common task for a client to reduce the dataset to be transferred. We could debate a standard way how to provide these parameters, however. In my special case the most practical way is the anonymous object.
I've been trying to figure this out for about a week now. It's time to ask S.O.
I have 4 overall goals here:
The controller code needs to use ViewModel request inputs for validation reasons. (Controller Snippet)
Client code for my API should use a nice model syntax. (Client Code Snippet)
For the swagger UI page, I would like the "Try me" interface to be usable. Either a bunch of text boxes, or a text area for a json blob to serialize and send over.
GET request
Client Code Snippet:
var response = client.GetUserProductHistory(new Models.UserProductHistoryRequest() {
Locale = "en-US",
UserPuid = "FooBar"
});
Controller Snippet
[HttpGet]
[HasPermission(Permissions.CanViewUserProductHistory)]
public JsonPayload<UserProductHistoryResponse> GetUserProductHistory([FromUri]UserProductHistoryRequest model)
{
JsonPayload<UserProductHistoryResponse> output = new JsonPayload<UserProductHistoryResponse>();
return output;
}
I have tried using [FromBody]. It looks great, but I get an error that says 'GET requests do not support FromBody'.
I tried using [FromUri], but then the generated client gives me like 15 method parameters per call in the generated client.
I tried using [FromUri], and operation filters so that the parameters would be condensed into Ref parameters (complex objects as defined by the spec). This actually worked decently for the client generation and the server side. Problem is, the UI for swagger looks really lame. A single TEXT box that you can't actually use very well. If I can figure out how to get the Swagger UI to change the appearance of the [FromUri] request to more closely match the [FromBody] UI, I will be in good shape here. Any ideas or pre-existing content that would point me in the right direction here?
Swagger is not the limitation - REST itself is. By definition of REST, web servers should ignore the incoming request body on all HTTP GET methods. ASP.NET enforces this convention, which is why you it doesn't allow you to use [FromBody] on the GET method.
When designing a REST API, the better practice is to use POST methods for an actual search. This will allow to use [FromBody], and as a bonus, Swagger will behave the way you want it to. See here for a supporting opinion: https://stackoverflow.com/a/18933902/66101
I'm currently in the process of designing as RESTful of an API as I can using Microsoft's Web API 2 in C#. What I'm struggling on is how best to represent resources or the proper way to do it where the GET call and POST/PUT are very different.
For example say I have something calls states that have an id, name, status, etc., these can be assigned to a document. So I have a route like this /documents/{id}/states/ . If I call a GET here I need to get the full list of all assigned states including their id, name, etc.
However, in order to change which states are assigned to the document I simply need to pass the id. I cannot do this individually, it must be an array that gets sent up since users may be interacting with hundreds or thousands at a time.
So in this case I have a few issues. I don't even know if POST or PUT is correct here, and second whichever one it is can I just take in an array of integers?
In your case, I would suggest PUT is the method you would be wanting to use, as you know the location of the resource that you are updating. For more info, see here: http://restcookbook.com/HTTP%20Methods/put-vs-post/
In ASP.NET Web API 2 you can use the [FromBody] parameter attribute, so that your method signature would be:
public void UpdateStates(int id, [FromBody]List<int> states) {}
More info on parameter attributes can be found here: http://www.asp.net/web-api/overview/formats-and-model-binding/parameter-binding-in-aspnet-web-api
I am unfortunately at the mercy of an API that forces the reuse of parameter names in a POST call.
The end result POST params look like this:
ArgNameA: xyz
ArgNameB: abc
ArgNameC: 123
ArgNameD: LMN
ArgNameC: 789
ArgNameD: JKL
ArgNameC: ...
ArgNameD: ...
You get the idea.
I'm currently using a NamedValueCollection and sending that to a WebClient to do the POST call. That works fine but when I try to reuse ArgNameC and ArgNameD over and over, it appears to recognize the names as already existing in the collection and therefor won't add them (or maybe it updates them, I'm not sure).
How do I make a POST using a WebClient which allows me to reuse POST argument names?
I was actually able to use the UploadString() method on the webclient and build the POST data string manually using HttpUtility.UrlEncode.
I have a REST method for search users. Right now I am having following signature for the REST method:
MyResponse GetUsers(UserSearchDTO search, int pageno, int totalrecords);
i.e it is accepting one object of UserSearchDTO, pageno and totalrecords param. The URL will look like
myapp/users?pageno={pageno}&totalrecords={totalrecords}
The end client will send "PUT" request for this service like:
myapp/users?pageno=1&totalrecords=10 and along with it it will pass xml data posted of UserSearchDTO like
<UserSearchDTO><Department>d</Department><Name>abc</Name></UserSearchDTO>
Is this a good architecture i.e in order to get users I am using "PUT" request type. The reason for doing this is because end client has to pass UserSearchDTO in xml form?
The other approach which I'm thinking is pure "GET" i.e instead of using UserSearchDTO I should have the following signature:
MyResponse GetUsers(string department,string name,...., int pageno, int totalrecords);
and the end client will call it like:
myapp/users?department=d&name=abc&......&pageno=1&totalrecords=10
I am in the process of writing my first REST service, so I am no expert, but in my opinion, I think it would be best to use a GET request, since that is exactly what you are doing -- getting data from the server. This will make it easier for other developers to support the app, instead of trying to figure out why you used PUT for a basic data retrieval.
If possible, I suggest that you try casting the UserSearchDTO XML as a string on the client and passing it to the GetUsers method as a string, then load the string into an XmlDocument() on the server and parse it into the DTO. Then your method signature would look like:
MyResponse GetUsers(string userSearchXmlString, int pageno, int totalrecords);
It looks like you're using WCF REST. With WCF REST, you have to implement the query mechanisms yourself as you are attempting to do. Have you considered using ASP.NET Web API? In Web API, your GetUsers() method simply needs to return an IQueryable<User> and Web API wraps that with OData querying capability which handles projection, filtering, sorting, aggregating and paging for you.