How to forward a REST web service using C# (WCF)? - c#

There is a web service that can only be consumed via http and a client that can only consume https web services. Therefore I need some intermediary that forwards on requests received in https and returns responses in http.
Supposing that the intermediary is completely dumb save for the fact that it knows where the web service endpoint is (i.e. it doesn't know what the signature of the service is, it just knows that it can communicate with it via an http web request, and it listens on some https uri, forwarding on anything it receives), what is the most simple way of achieving this?
I've been playing around with this all day and am not sure how to achieve the "dumb" bit, i.e. not knowing the signature for passing back the verbatim response.

A dumb intermediary is essentially a proxy. Your best bet might to be just use standard asp.net pages (instead of shoehorning into service functionality like ASMX or WCF which are just going to fight you) so you can receive the request exactly as-is and process it in a simple way using standard request/response. You can make use of HttpWebRequest class to forward the request on to the other endpoint.
Client requests https://myserver.com/forwarder.aspx?forwardUrl=http://3rdparty.com/api/login
myserver.com (your proxy) reads querystring forwardUrl and any POST or GET request included.
myserver.com requests to http://3rdparty.com/api/login and passes along GET or POST data sent from the client.
myserver.com takes response and sends back as response to other endpoint (essentially just Response.Write contents out to the response)
You would need to write forwarder.aspx to process the requests. Code for forwarder.aspx would be something like this (untested):
protected void Page_Load(object sender, EventArgs e)
{
var forwardUrl = Request.QueryString["forwardUrl"];
var post = new StreamReader(Request.InputStream).ReadToEnd();
var req = (HttpWebRequest) HttpWebRequest.Create(forwardUrl);
new StreamWriter(req.GetRequestStream()).Write(post);
var resp = (HttpWebResponse)req.GetResponse();
var result = new StreamReader(resp.GetResponseStream).ReadToEnd();
Response.Write(result); // send result back to caller
}

Related

Parsing raw HTTP in C# - or some better option?

I have a raw socket I want to make HTTP requests over. I would like to get back nicely-parsed-for-me http responses. Ideally I could feed this raw socket to HttpClient - something in a standard library. "TheWrapperClass" around the socket would allow me to use higher level instructions like again - the ones from HttpClient/HttpClientHandler like : clientHandler.ClientCertificates or clientHandler.Credentials etc.
Something like this maybe?:
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.SocketFactory = mySocket/FactoryGoesHere???
HttpClient client = new HttpClient(new CustomMessageHandler());
var resp = await client.GetAsync("http://whatever");
I'm thinking of something like SSLSocketFactory from Java - is there an equivalent of this in .NET that I just haven't found yet?
At the end of the day - I really only want to have a library to invoke that writes HTTP to the wire easily and reads HTTP from the wire easily. If I had that I don't need HttpClient. Alternatively I need a way to use HttpClient to send bytes down the socket I give the class.
Edit:
I tried using a HttpMessageHandler but the HttpRespons is one that I hand craft. I need something that reads a stream and parses the http for me.
If you don't have a need for executing JavaScript, SimpleBrowser might fit for you:
https://github.com/SimpleBrowserDotNet/SimpleBrowser
It will not expose a raw socket for you to use as a bi-directional stream, but it will allow you to navigate via HTTP and receive an HTTP response. The HTTP response can either be the raw text response from the web server, or an parsed XML (XHTML) document.

How to create simple IIS site to redirect all calls to another service?

I've written a REST API service in Delphi, which runs as its own stand-alone service. I also have IIS hosting some sites on port 80. I would like to use port 80 for my REST API as well, but since I'm already using it in IIS, I'm forced to use another port.
What I'd like to do to overcome this is create a very simple site in IIS (Preferably with ASP.NET/C#) which simply redirects all incoming HTTP requests to this other service running on a different port. This would allow me to take advantage of binding multiple sites under the same port in IIS. I don't want to perform a literal "redirect", but just replicate the request to the desired server, and respond back - as if user was connecting to original REST server. Only, without having to use a non-standard port. The URL on the client-side shouldn't change (as what you normally see with an HTTP Redirect).
Essentially, if user makes such a request:
http://api.mydomain.com/SomeReq?some=query
It will turn around and make a corresponding request to the real server, and carry over the entire URI - just a different port number:
http://api.mydomain.com:8664/SomeReq?some=query
How can I accomplish this?
Using ASP.NET Web API it is pretty simple to write such a proxy server. All you need is a delegating handler:
public class ProxyHandler : DelegatingHandler
{
private static HttpClient client = new HttpClient();
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
// strip the /proxy portion of the path when making the request
// to the backend node because our server will be made to listen
// to :80/proxy/* (see below when registering the /proxy route)
var forwardUri = new UriBuilder(request.RequestUri.AbsoluteUri.Replace("/proxy", string.Empty));
// replace the port from 80 to the backend target port
forwardUri.Port = 8664;
request.RequestUri = forwardUri.Uri;
if (request.Method == HttpMethod.Get)
{
request.Content = null;
}
// replace the Host header when making the request to the
// backend node
request.Headers.Host = "localhost:8664";
var response = await client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
return response;
}
}
and finally all that's left is to register this handler:
config.Routes.MapHttpRoute(
name: "Proxy",
routeTemplate: "proxy/{*path}",
handler: HttpClientFactory.CreatePipeline(
innerHandler: new HttpClientHandler(),
handlers: new DelegatingHandler[]
{
new ProxyHandler()
}
),
defaults: new { path = RouteParameter.Optional },
constraints: null
);
In this example the proxy will listen on :80/proxy/* and forward it to :8664/*.
So if you send the following request to your Web API:
GET http://localhost:80/proxy/SomeReq?some=query HTTP/1.1
Host: localhost:80
Connection: close
it will be translated to:
GET http://localhost:8664/SomeReq?some=query HTTP/1.1
Host: localhost:8664
Connection: close
This will also work for POST and other verbs made to :80/proxy/*.
Obviously if you want to turn your entire webserver into a proxy and listen to :80/* then you could get rid of the /proxy prefix that I used in my example.
This being said, this is only a proof-of-concept proxy server. In a real production system I would off-load this task to a full blown frontend load balancer such as nginx or HAProxy which are designed exactly for this purpose. Then both your IIS and Delphi application could listen on arbitrary ports and your nginx configured to listen to port 80 and forward the traffic to the backend node(s) based on some patterns. Using a load balancer also has other benefits as if you are having multiple backend nodes, it will distribute the load between them and also give you the possibility to make updates to your applications without any downtime (because you have full control over which node is in the load balancer pool).

Consume a HTTP POST from a self hosted service

I have a self hosted service that needs to listen for upload notifications coming from a BITS server (they are a simple HTTP POST request with custom headers). If I was not self hosting my service and was using IIS I would just make a ASPX page and I could handle the incoming requests, but I am using self hosted WCF and I can not switch to IIS.
I looked in to using WebInvokeAttribute, however that appears to only be for sending JSON or XML as a reply and I need to follow the protocol spec. Also I did not see a way of pulling out the custom headers.
The next thing I looked in to was HttpListener and it appears to do what I need, however I did not see if there is a way to configure it via my app.config file like normal WCF endpoints.
Do I just add the address to my applicationSettings section or is there a better way to achieve what I am trying to do?
I ended up just using the Properties class and storing the url there.
//This is run on it's own thread
HttpListener listener = new HttpListener();
listener.Prefixes.Add(Properties.Settings.Default.BitsReplierAddress);
listener.Start();
while (_running)
{
// Note: The GetContext method blocks while waiting for a request.
// Could be done with BeginGetContext but I was having trouble
// cleanly shutting down
HttpListenerContext context = listener.GetContext();
HttpListenerRequest request = context.Request;
var requestUrl = request.Headers["BITS-Original-Request-URL"];
var requestDatafileName = request.Headers["BITS-Request-DataFile-Name"];
//(Snip...) Deal with the file that was uploaded
}
listener.Stop();

Integrate a C# client into a node.js + socket.io chat app

As part of learning node.js, I just created a very basic chat server with node.js and socket.io. The server basically adds everyone who visits the chat.html wep page into a real time chat and everything seems to be working!
Now, I'd like to have a C# desktop application take part in the chat (without using a web browser control :)).
What's the best way to go about this?
I created a socket server in nodejs, and connected to it using TcpClient.
using (var client = new TcpClient())
{
client.Connect(serverIp, port));
using (var w = new StreamWriter(client.GetStream()))
w.Write("Here comes the message");
}
Try using the HttpWebRequest class. It is pretty easy to use and doesn't have any dependencies on things like System.Web or any specific web browser. I use it simulating browser requests and analyzing responses in testing applications. It is flexible enough to allow you to set your own per request headers (in case you are working with a restful service, or some other service with expectations of specific headers). Additionally, it will follow redirects for you by default, but this behavior easy to turn off.
Creating a new request is simple:
HttpWebRequest my_request = (HttpWebRequest)WebRequest.Create("http://some.url/and/resource");
To submit the request:
HttpWebResponse my_response = my_request.GetResponse();
Now you can make sure you got the right status code, look at response headers, and you have access to the response body through a stream object. In order to do things like add post data (like HTML form data) to the request, you just write a UTF8 encoded string to the request object's stream.
This library should be pretty easy to include into any WinForms or WPF application. The docs on MSDN are pretty good.
One gotcha though, if the response isn't in the 200-402 range, HttpWebRequest throws an exception that you have to catch. Fortunately you can still access the response object, but it is kind of annoying that you have to handle it as an exception (especially since the exception is on the server side and not in your client code).

Very fast and light web call, which technology to use: legacy web service or HttpWebRequest

I need some insecure, fast, light and easy to implement web method. Something like this:
// Client side
// Parametrize client address which is dynamic and we don't know until run-time
myClient.Address = "http://example.com/method.aspx/?input=" + value;
string result = "";
if (myClient.TryCallWebMethod(out result))
// Web method succeed. Use returned value.
else
// Web method failed. No problem, go with plan B.
// Server side
Response.Write("Answer is: " + Request.QueryString[input]);
I know this is reconstructing the wheel, but what I need is as simple as above code. I can implement client with HttpWebRequest but maybe using a legacy Web Service is a better choice.
I have tried WCF but there are more choices which I don't need like sessions, security, etc. Also I did a localhost benchmarking and WCF came to it's knees at 200 concurrent requests, where I need a support of more than 1000 concurrent calls which is a normal load for an aspx page.
This web method is gonna be consumed from a asp.net page. I never used a legacy web service, is it OK for my scenario or like WCF it has a dozen of configurations and certificate installations... ?
After going through the operations provided by WebClient, it looks like it just wraps a HttpWebRequest functionality and provides extra utility operations. Hence I would suggest you to go for HttpWebRequest.
Also on the server side, try to go for a HttpHandler instead of aspx page (handlers are light weight)
If this is a standard ASPX page you could use a WebClient:
using (var client = new WebClient())
{
var url = "http://example.com/method.aspx?input=" + HttpUtility.UrlEncode(value);
string result = client.DownloadString(url);
}

Categories

Resources