adding content to a getasync - c#

when using HttpClient and performing a PostAsync I am able to add a contract with HttpContent. for example
HttpContent content = new ObjectContent<myContractType>(MyContract, xmlFormatter);
var resp myClient.PostAsync(myUri,content).Result
when doing a GetAsync I am unable to pass a HttpContract object. That said do I need to just add the members of the contract in a query string or is there a better way to go about it?

The nature of GET requests does not provide a way to send large amounts of data to the server as might be done with a POST request. In practice, a limited amount of data can be sent in the form of headers or as part of a querystring.
There won't be a way to convert the XML data directly to a querystring, but this is an example of a request with a querystring:
var client = new HttpClient()
client.GetAsync(String.Format("http://service.example.com/api/{0}?foo=bar", id))

Related

Attempting to pass empty body to POST endpoint with WebClient

I currently have an endpoint in my project:
[HttpPost("process")]
public IActionResult Process (string Val1, [FromBody] object Json)
{
//processing.....
Return Ok(...);
}
And on my client side I am trying to call this endpoint with WebClient like so:
string response = null;
string body = "{}";
using (var client = new WebClient())
{
client.UserDefaultCredentials = true;
client.Headers.Add(HttpRequestHeader.ContentType, "application/json; charset=utf-8");
response = client.UploadString("localhost:55555/api/process?Val1=Param", body);
}
Here's where my concerns are:
For this endpoint, I will typically be passing a JSON object
However, I want this endpoint to also NOT require a body, I would want it to be empty, as the endpoint should not require it
If you look at my body variable - I am setting it to "{}" otherwise I've not found a different way to pass "EMPTY" body to the endpoint
Questions:
How do I properly pass an EMPTY body to this endpoint? (this endpoint will be used by different clients, and I am just looking for best practice approach to this?
In my endpoint, I have [FromBody] object Json parameter. Is it a better practice to have it be as object or can I alternatively do JObject that could still accept an Empty body
Forgive my "noobness" with these questions if they seem obvious, I'm just getting started in the API development and want to make sure I am using best practices.
You're currently using a WebClient, which is outdated in favour of HttpClient (see this answer). When using HttpClient you can post empty bodies as follows: await client.PostAsync("localhost:55555/api/process?Val1=Param", null);
As for your second question. Look into Data Transfer Objects, aka DTOs. They are in a nutshell dumb types you can use purely for passing and receiving data through your API, you can add things like validation to them as well. Using object or JObject is only needed if you're receiving dynamic data, otherwise use DTOs where possible.

RestSharp PUT request parameters

I'm having issues figuring out how to create a put request using RestSharp.
I need to pass an integer followed by a JSON body in the same request.
So far I have this:
for (var i = 0; i < ReorderedTasks.Count; i++) {
var reorderedTasksJson = new JavaScriptSerializer().Serialize(ReorderedTasks[i]);
var request = new RestRequest("api/task/5/{ID}/", Method.PUT);
request.AddParameter("ID", ReorderedTasks[i].ID.ToString(), ParameterType.UrlSegment);
request.AddParameter("application/json; charset=utf-8", reorderedTasksJson, ParameterType.RequestBody);
client.Execute(request);
}
I've tested out the JSON ad requestBody on POST and it works fine. I think my issue is with the first parameter I'm trying to pass ReorderedTasks[i].ID , I'm not sure if I'm handling the passing of this correctly.
I've initialised client at the beginning of my class.
Problem is the DB isn't updating and I need to isolate the problem. Is the above the correct way in dealing with my two parameters needing passed?
I suggest to put ReorderedTasks[i].ID.ToString() directly to url path.
var request = new RestRequest($"api/task/5/{ReorderedTasks[i].ID.ToString()}/", Method.PUT);
It will help to reduce possible problems with http request format.
I'll add it here, so someone will benefit from it.
If your endpoint URL have parameters like ?param=value&param2=value that you want to pass along with request RestSharp's AddParameter(string, string) won't work with PUT method (but it works just fine with GET or if endpoint doesn't have URL parameters, so it is deceiving)
Use AddParameter(string, string, ParameterType.QueryString) in order to PUT Method work correctly.
Well it depends on what does the webApi expect..
You could use Fiddler to inspect what being sent through the wire and what response You are getting (http://www.telerik.com/fiddler)
Also - here are some sample's how other users use RestSharp
How do I use PUT in RestSharp?

Read and edit the content of an HttpResponseMessage

I'm having an implementation of DelegatingHandler which basically take a request and address it to another server (http://localhost:9999/test/page.php --> http://otherSite.com/test/page.php ).
Following my question here, I now have to read the result of the page and edit it a little bit:
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
string url = request.RequestUri.PathAndQuery;
UriBuilder forwardUri = new UriBuilder(_otherWebSiteBase);
forwardUri.Path = url;
HttpRequestMessage newRequest = request.Clone(forwardUri.Uri.ToString());
HttpResponseMessage responseMessage = await _client.SendAsync(newRequest);
//HERE: How to read the responseMessage.Content in string?
return responseMessage;
}
I'm trying to read the content of the message, change some parts of it(basically change all http://otherSite.com into http://localhost:9999 ) and then return it.
The issues that I'm facing:
string content =await responseMessage.Content.ReadAsStringAsync();
Doesn't returns me anything that is readeable(I'm not sure, but I've the impression it's maybe because of the compression?)
Is there a way to replace the content of the message?
I'm trying to understand this a little better. Are you simply looking to make all requests that go to that address get redirected to another address? Given that you're putting this in the delegating handler, I'm imagining this is being run for every incoming request.
If that's the case, I don't really believe this is the location to write this code. There are two other places that I think provide a cleaner solution.
In the web server:
You seem to be recreating the idea of a Reverse Proxy (https://en.wikipedia.org/wiki/Reverse_proxy) where you want one server to simply direct requests to another without the client knowing about the change. You can make this modification on the server itself. If you're using IIS, there are guides to use IIS plugins like Application Request Routing to achieve this ( http://www.iis.net/learn/extensions/url-rewrite-module/reverse-proxy-with-url-rewrite-v2-and-application-request-routing ). Other web servers also have their own solutions but I have not personally tried them.
On the route itself
On whatever Web API route would be responding to this request, you can use http status codes to tell the browser to redirect the request elsewhere.
The 3xx series were specifically made to solve this kind of problem: http://www.restapitutorial.com/httpstatuscodes.html
That said, if you still want to use the approach in the original question, you need to ensure that there is a Media-Type Formatter for the data type that is being returned. By default, Web API will only attempt to use formatters for JSON, XML, and Form-url-encoded data. If you are returning anything else, you'll need to do a little more work ( http://www.asp.net/web-api/overview/formats-and-model-binding/media-formatters ) to get the data back to manipulate it.

Creating and sending an HttpResponse message

Given either a url or a HttpResponse instance, I need to send back a HttpResponse (note Response not Request) with Status code 200. I've tried a generic HttpClient.PostAsync and GetAsync, but I can't configure the status code.
This is basically a handshake for subscribing to events for a remote service. I send a Request, get an OK back from the server and now it's expecting me to reply to the OK with my own OK.
Any ideas on how to go about this? I don't have an incoming request to respond to.
var resp = new HttpResponseMessage(HttpStatusCode.OK);
// need to sent this to the url. no content necessary.
Here's some things I cannot do:
var client = new HttpClient();
var resp = await client.GetAsync(url);
-------------------
var content = new ByteArrayContent(new byte[0]);
var client = new HttpClient();
var resp = await client.PostAsync(url, content);
When you invoke HttpClient calls you are creating HttpRequestMessages. There are a number of helper methods (like some PostAsync overloads or PostAsJsonAsync) which let you pass in a plain old C# object, which it then wraps for you. These values get set in the Content property of the HttpRequestMessage, wrapped by an instance of HttpContent. You're also perfectly free to create these request messages yourself, setting the status code and content to anything you like. HttpResponseMessage (note Response, not Request) is the type you'll get back from your client call, which you can use to read the response code or data sent back to you (stored in HttpResponseMessage.Content, not to be confused with HttpRequestMessage.Content, which you would have already set).
That said, you CAN set your request content to an instance of HttpResponseMessage, but that would be a little bit odd. Generally, the objects you use for your content should be simple objects which exist simply to define the shape of your requests' body (like JSON).
This article goes over the basics pretty well: Calling a Web API from a .Net Client
You should be able to set the status directly on the HttpResponse object
Something like this...
HttpResponse().StatusCode = 200;

WebRequest: Query string data vs x-www-form-urlencoded content

I am trying to call Google's OAuth2 authentication service as per these instructions: https://developers.google.com/accounts/docs/OAuth2ForDevices
I put all of the required parameters into the query string and sent the request. This worked for the "Obtaining a user code" section but not for the "Obtaining Access and Refresh Tokens" section.
After much playing around and getting 400 Bad Request errors, I found that, instead of putting the data in the query string, you can create a request with a FormUrlEncodedContent and send the data through as content with application\x-www-form-urlencoded Content-Type.
Here is the code before:
var requestMessage = new HttpRequestMessage();
requestMessage.Method = "POST";
requestMessage.RequestUri = new Uri(fullUrl);
Where fullUrl is something like:
https://accounts.google.com/o/oauth2/device/code?client_id=812741506391-h38jh0j4fv0ce1krdkiq0hfvt6n5amrf.apps.googleusercontent.com&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.email%20https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fuserinfo.profile
And the new code is:
var requestMessage = new HttpRequestMessage();
requestMessage.Method = "POST";
requestMessage.RequestUri = new Uri(url);
requestMessage.Content = new FormUrlEncodedContent(CreateDictionary(queryStringNames, queryStringValues));
Where url is:
https://accounts.google.com/o/oauth2/device/code
and queryStringNames and queryStringValues are string arrays of the names and values of the required parameters.
What is the difference between these two methods? Is it safe to assume that all POST calls can use the URL Encoded Content requests instead of putting the data in the query string?
In general, POST requests do not need query string but it is still subjected to Server's logic implementation. In case of OAuth which is quite known standard and they do follow good practice, it is safe to use form encoded data unless mentioned explicitly in API to send Parameter as query string.
Query String & Post data are two different set of parameters. If server is expecting Query string then you must send query string only. It all depends on how server side logic is implemented. You can not use them alternatively. Most API documentation specify clearly what are they expecting.

Categories

Resources