Read and edit the content of an HttpResponseMessage - c#

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.

Related

Why return object in WebAPI POST method with CreatedAtAction?

When writing a POST method for an API in Asp.NET Core there is the possibility to use CreatedAtAction
Following example from the documentation
[HttpPost]
[Consumes(MediaTypeNames.Application.Json)]
[ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> CreateAsync(Product product)
{
if (product.Description.Contains("XYZ Widget"))
{
return BadRequest();
}
await _repository.AddProductAsync(product);
return CreatedAtAction(nameof(GetById), new { id = product.Id }, product);
}
The CreatedAtAction action result has following effects:
The Response Status Code will be 201
A "Location" response Header will be included with the URI of the new resource
The created object will be returned in the response body
The first two seem reasonable to me. However I wonder why the third effect would be desired? At first it seems to be an unnecessary increase of the response size, yet I am curious to understand why that pattern is presented in the documentation as it is, including the created object. What is the benefit of returning the created resource, which was sent as request anyway? Or could it be that the (only) reason for including the object in the response is to include values which are generated server side, as for example a create date or a primary key?
The server can generate new data that the client will not know about, such as an ID or timestamps for creation or modification. If the client requires this data after the initial request, you save an unnecessary round trip by including the created resource in the response body.
It's not always the best choice. You have weigh the benefit of having immediate access against the increased bandwidth use. Some consideration is warranted before returning large resources this way.

Read content body from a HTTP GET in C# WebAPI

I have a WebAPI C# application. My GET method is defined as:
[HttpGet]
public HttpResponseMessage Get(string id)
This API retrieves some content from a database, based on a given id. Another parameter is required but it is so long that having it on the URL would not work, so I'm using the GET body to send such second parameter.
How can I retrieve it from inside the get method?
I tried
var dataOnBody = await Request.Content.ReadAsStringAsync();
but it doesn't work as the Get method is not async and I think it doesn't need to be that (I want a normal blocking function which reads the content of the body and outputs a string)
I just need a simple way to extract my string from the request body
Even if you somehow manage to do this, you will find that support is not universal. The HTTP specs say:
The GET method means retrieve whatever information (in the form of an
entity) is identified by the Request-URI.
So the data returned relies only on the URI, not anything in the body. Many libraries won't even let you send a request body during a GET.

How to get more details on a BadRequest from HttpResponse

I'm trying to connect to a companies web service, but I'm getting a BadRequest value returned. I suppose that isn't a huge issue, and I'm not asking for help on how to fix the bad request. The issue I'm running into, is how to get more details on what is causing it. So I have this HttpResponseMessage Class variable:
HttpResponseMessage response = c.Post(address, content);
//...fill in content
response = cAssessments.Post(addressInfo, content); //return "Bad Response"
I send it off to their servers with the proper content, and I get back 400 response stating "Bad Request". My question is how do I dig deeper into that repsonse variable to see exactly what is causing it. I'm figuring that there is some dependance on the service I'm hitting to supply information so I'm going to assume it's in there somewhere. But what are something things inside that variable I should be looking into? For example:
"response.StatusCode" gives me the the 400 code. What other properties can I look into?
Any help is appreciated.
Filling content of BadRequest response with some useful tip or information what could possibly go wrong is totally up to web service which serves response. You cant do anything from your side.
Try the Content itself, also the URL of the originating request.
Depending on the API you're requesting against, they may include what specifically caused the 400 in the response's Content.
Also the format you are requesting it in (json vs xml vs whatever)
It all depends on what the service is returning. To check that, you can read the response stream:
using (var stream = response.GetResponseStream ()){
using (var reader = new StreamReader(stream, Encoding.UTF8)
{
var text = reader.ReadToEnd();
// text contains your info
}
}
Another useful option for debugging is using something like postman, where you can paste in your request and see the full response immediately
If the response doesn't include any useful info, you're stuck though, there's nothing you can do about that.

adding content to a getasync

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

Redirect to another URL from a WCF REST function without returning HTTP 302

I have a REST service that gets a GET request, and I want it to be able to redirect to one of three urls, without having to send an http 302 error and the new url.
[OperationContract(Name = "MyService")]
[WebGet(ResponseFormat = WebMessageFormat.Xml, UriTemplate = "/myservice/{option}")]
public System.IO.Stream MyService(String option)
This is how I have it defined, but when I look at WebOperationContext.Current.OutgoingResponse I don't have a method for redirect.
Is there any way to do this automatically? The reason I am hoping to do this is that this webservice may be called by a program, and it would be simpler on the program to not have to catch the 302 error and then do the redirect manually.
It appears the correct way is to follow this:
http://christopherdeweese.com/blog2/post/redirecting-from-a-wcf-rest-service
and do this:
WebOperationContext.Current.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.Redirect;
WebOperationContext.Current.OutgoingResponse.Location = "/someOtherPage.aspx";
return null;
I just hope to find another solution.
Redirect is always client side feature. The server just informs client that the resource is elsewhere. There is nothing like server side redirect except completely hiding this redirection into separate service call from your current operation.
Btw. REST is about uniform interface and redirects (3xx) are part of this interface so if you create REST service and you want such feature you should use it in common way. REST client is responsible for handling the uniform interface correctly.

Categories

Resources