HTTPResponse not arriving at client - c#

I have a http handler which is registered and working fine. Now i want to process a request, and send a custom html response which is then shown on the client.
So my function is written as follows:
public void ProcessRequest(HttpContext _context)
{
HttpResponse response = _context.Response;
response.Clear();
var requestedUrl = _context.Request.Url;
PhantomModuleController pmc = new PhantomModuleController();
response.BufferOutput = true;
var snapshot = pmc.DoThings(requestedUrl); //this returns a string
response.Write(snapshot); //i put it in the response
response.ContentType = "text/html";
response.End(); //it should send it to the client now
}
But according to my fiddler, the response never arrives on the client. In fact, the httpresponse is never even sent.
Did i forget somethiing

Because the request is not showing up in Fiddler as being sent back to the client (nor an error back to the client), the routing engine may be getting in the way of the request. The scenerio is described by phil hack.
However, there are other cases where you might have requests for files
that don’t exist on disk. For example, if you register an HTTP Handler
directly to a type that implements IHttpHandler. Not to mention
requests for favicon.ico that the browser makes automatically. ASP.NET
Routing attempts to route these requests to a controller. One solution
to this is to add an appropriate ignore route to indicate that routing
should ignore these requests. Unfortunately, we can’t do something
like this: {*path}.aspx/{*pathinfo}
You need to setup the route engine to ignore the route that has the file extension. E.G.
routes.IgnoreRoute("{*allaspx}", new {allaspx=#".*\.aspx(/.*)?"});
routes.IgnoreRoute("{*favicon}", new {favicon=#"(.*/)?favicon.ico(/.*)?"});

Related

Why is postman sending form data in an HTTP GET?

I received a Postman json collection from an API vendor that works perfectly, but has something mystifying to me: The request is in a GET format, yet there is an x-www-form-urlencoded body.
URL: https://login.microsoftonline.com/d1e<secret>9563/oauth2/token
And when I look at the postman-generated c# code, the mystery continues:
var client = new RestClient("https://login.microsoftonline.com/d1e...d3/oauth2/token");
client.Timeout = -1;
var request = new RestRequest(Method.GET);
request.AddHeader("Content-Type", "application/x-www-form-urlencoded");
request.AddParameter("grant_type", "client_credentials");
request.AddParameter("client_id", "c06bb...79");
request.AddParameter("client_secret", "7~u...D");
request.AddParameter("resource", "https://vault.azure.net");
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
Note the AddParameter constructions for a GET call. To me, this must be a slight-of-hand for merely adding those values to the querystring. But when I look at the postman console I see:
In the postman console I would have expected to see those params appended to the url as a querystring, and then everything would have made sense. But you can see that it's a bonafide Request Body.
When I make GET calls in my c# code I like to use the simple yet solid WebClient object to call the DownloadString() method. But this method is only for GETs and there's no way to send a form-post style body, understandably.
Is postman truly sending a GET with all those values being appended to the url as a querystring? And should I do the same in my DownloadString() call? Or is there something else going on here? Should I instead, in my c#, be calling the UploadString() method and sending a form post BODY as a GET??
Http protocol supports adding a body to a request, but the WebClient class you use doesn't. Presumably because it isn't considered the norm.
I'm sure there's good reasons for Microsoft using it in the OAuth flow though. Those guys normally do things right!
HTTP GET with request body
API is just an abstraction , you can send what ever you want to the API . It depends on the implementation , how the server handles these data.
Some services considers only what it requires and ignores other information
some services considers the entire requests and validates that it has only the allowed data. what should be allowed depends on the service
Postman is just a client that sends data to server , its upto you to decide what all information it should send . If you dont need any body then keep it as none. if you need some thing then add it.

Get instance of ApiController class from a URL directly

I am looking for a way to call the appropriate method (get, post etc.) on an ApiController class based on the URL and request type etc. without making a http request.
Background: We have an API application with numerous controllers that needs to also accept requests from a remote server. Due to restrictions I cannot control there is no way to open ports between the two servers to allow the remote server to make the request directly so we decided to forward the data using websockets (SignalR). I can send (within reason) whatever information is required.
I have tried the below:
HttpRequestMessage request = new HttpRequestMessage();
var bld = new UriBuilder
{
Port = 123,
Path = "api/v1/search",
Query = "query=search_string"
};
request.RequestUri = bld.Uri;
var httpCfg = AppConfiguration.Get().HttpConfig; //this is the same config that UseWebApi was called with and contains the routes.
var route = httpCfg.Routes.GetRouteData(request);
var controllerSelector = new DefaultHttpControllerSelector(httpCfg);
var descriptor = controllerSelector.SelectController(request);
route contains the controller name (search) but the call to SelectController throws an exception with a 404 response in it (I presume this indicates I am missing something from the fake request). The same URI works when sent as a direct http request so the routes do work as best I can tell.
Is there a better way to do this, or if not what am I missing from the request that is causing the 404?

Is there a simple way to create a new outbound HttpWebRequest from the inbound request?

I need to effect a type of reverse proxy from C# code. (Yes, I know that IIS has a reverse proxy, but for several reasons, I need to do this from code.)
So, my controller action will "relay" the inbound request to another URL, then return the response. Kind of like this:
public string Proxy()
{
// This would be an extension method; it's currently hypothetical
var newRequest = Request.GetRequestToNewUrl("http://newurl.com");
// Make the request and send back whatever we get
var response = newRequest.GetResponse();
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.Something))
{
return reader.ReadToEnd();
}
}
The proxied request (to newurl.com) should be identical to the inbound request (headers, body, cookies, etc.), just to a different URL.
I've been playing around with it, and it's more complex than I thought. The inbound Request is an HttpRequestBase, and the proxy request will be an HttpWebRequest. They are fundamentally different types, and there's no direct translation between the two. So far, it's been a tedious process of copy and translating properties.
Before I spend a ton of time debugging all this, is there an easier way? There are a fair number of different types to represent an HTTP request:
HttpRequestBase
HttpWebRequest
HttpRequest
HttpRequestWrapper
Is there a way I'm not aware of to simply "reuse" the inbound request, while changing the URL? Or should I continue with my translation from HttpRequestBase?
yes, it is possible. You can reuse the Request content from an incoming request and the forward it by creating a new request of your own. Create a new client with the address where the request was supposed to be forwarded. And do a get or post with new HTTP client and just return the result.
var client = new HttpClient
{
BaseAddress = new Uri(destinationBaseAddress)
};
return await client.PostAsync(requestUrl, Request.Content);

How to clean up existing response in webapi?

There is a authentication library that I have to use that helpfully does things like
Response.Redirect(url, false);
inside of it's method calls. I can't change this libraries code and it's fine for MVC style apps but in angular SPA -> WebApi apps this is just awful.
I really need a 401 otherwise I get into trouble with CORS when my angular scripts, using $http, try to call out to the auth server on another domain in response to the 302, that's if it even could as the Response.Redirect also sends down the object moved html and the angle brackets cause an error to be thrown.
Since I have to make the call to the auth library first the Response.Redirect is already in the response pipeline and so I need to clean it up to remove the body content and convert the 302 into a 401. I thought I could just:
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent("data");
}
but this just gets appended to the response and doesn't replace it plus I also need the Location: header which I can't seem to access via WebApi methods.
So instead I've had to do this in my ApiController:
var ctxw = this.Request.Properties["MS_HtpContext"] as HttpContextWrapper;
var ctx = ctxw.ApplicationInstance.Context;
var url = ctx.Response.RedirectLocation;
ctx.Response.ClearContent();
return new HttpWebResponse(StatusCode.UnAuthorized){
Content = new StringContent(url);
}
But this seems terrible and counter to webapi "feel". Plus I'm tied to the controller in doing this. I can't get the wrapper in a MessageHandler for example.
What I'd like to do is monitor the response for a given route in a message handler or in an AuthorizationFilterAttribute, if its a 302, I want to read it's headers, take what I want, wipe it and replace it with my own "fresh" response as a 401. How can I do this?
You might want to write your own ActionFilter and override its OnActionExecuted method where you can access HttpActionExecutedContext. From there, you can check response code, for example, and overwrite response with whatever you want.
Ref: https://msdn.microsoft.com/en-us/library/system.web.http.filters.actionfilterattribute.onactionexecuted%28v=vs.118%29.aspx#M:System.Web.Http.Filters.ActionFilterAttribute.OnActionExecuted%28System.Web.Http.Filters.HttpActionExecutedContext%29

Is it possible or necessary to set the content type of a ServiceStack client delete request?

I have the following code.
public T SendUpdateRequest(string url)
{
using (JsonServiceClient client = new JsonServiceClient())
{
T response = client.Put<T>(url);
return response;
}
}
I have similar methods for create and delete requests, calling the JsonServiceClient Post and Delete methods respectively.
When calling my update or create methods, the call to the external API works fine. Delete does not. I can see that the API's delete method does indeed work if I fire a request to it via REST console.
When I compare my non-working delete with the working one's request/response in Fiddler, I can see the main difference is my request is not setting content-type to application/json (all these methods return JSON).
My question is, is it possible (or even necessary) to explicitly set the content-type of my delete request to application/json in order to successfully call my API method?
The ServiceStack clients do not set the content-type header on requests where there is no request body, as the content-type only applies to the body, and is therefore redundant.
This can be seen here in the code that prepares the client request.
if (httpMethod.HasRequestBody())
{
client.ContentType = ContentType;
...
A correctly implemented RESTful service should be happy with a DELETE request without content-type being specified where there is no body.
DELETE /User/123 HTTP/1.1
If the service you are calling is not happy with your request without this type being specified (which is unusual), then you can manually enforce the sending of the type using this filter:
var client = new JsonServiceClient("https://service/");
client.RequestFilter += (httpReq) => {
// Force content type to be sent on all requests
httpReq.ContentType = "application/json";
};
I hope that helps.

Categories