Code

An Asp.Net REST/json service proxy

I had a REST/json service with token authentication that I wanted to consume from a javascript application in an Asp.Net web application.

I didn’t want to expose the token used to access the service, and I wanted to put the service behind Asp.Net authentication on the fronting application.

The solution was a simple but nice proxy for the service.

The proxy is a HttpHandler, which is protected by Asp.Net authentication using the following web.config settings:

<location path="myserviceproxypath">
  <system.web>
    <authorization>
      <allow roles="Administrators, SomeOtherRole" />
      <deny users="*" />
    </authorization>
  </system.web>
  <system.webServer>
    <handlers>
      <add name="MyServiceProxy" verb="*" path="*" type="My.Namespace.MyServiceProxy, MyAssembly" />
    </handlers>
  </system.webServer>
</location>

Some appsettings:

<add key="MyServiceBaseAddress" value="http://my.service.baseaddress/api/" />
<add key="MySecretAccessToken" value="..." />

The code for the HttpHandler proxy:

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Configuration;
using System.Net;
using System.Text;
using System.Web;

namespace My.Namespace
{
    public class MyServiceProxy : IHttpHandler
    {
        private static string _apiBaseAddress = ConfigurationManager.AppSettings["MyServiceBaseAddress"];
        private static string _accessToken = ConfigurationManager.AppSettings["MySecretAccessToken"];
        private static string _proxyPath = "/myserviceproxypath";

        public bool IsReusable
        {
            get { return true; }
        }

        public void ProcessRequest(HttpContext context)
        {
            string response = null;
            var path = context.Request.Url.PathAndQuery.ToLower().Replace(_proxyPath.ToLower(), "");

            if (context.Request.RequestType.ToUpper() == "POST")
            {
                var postData = GetPostData(context.Request);
                postData.Add("AccessToken", _accessToken);
                response = Post(path, postData);
            }
            else if (context.Request.RequestType.ToUpper() == "GET")
            {
                response = Get(path);
            }
            context.Response.ContentType = "application/json";
            context.Response.Write(response);
        }

        private JObject GetPostData(HttpRequest request)
        {
            byte[] postData = new byte[request.InputStream.Length];
            request.InputStream.Read(postData, 0, (int)request.InputStream.Length);
            string jsonString = Encoding.UTF8.GetString(postData);
            return JsonConvert.DeserializeObject(jsonString);
        }

        private string Post(string path, JObject postData)
        {
            using (var client = new WebClient())
            {
                var dataString = JsonConvert.SerializeObject(postData);
                client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
                return client.UploadString(new Uri(new Uri(_apiBaseAddress), path), "POST", dataString);
            }
        }

        private string Get(string path)
        {
            using (var client = new WebClient())
            {
                //Todo: Add the AccessToken here as well...
                client.Headers.Add(HttpRequestHeader.ContentType, "application/json");
                return client.DownloadString(new Uri(new Uri(_apiBaseAddress), path));
            }
        }
    }
}

So, then a POST to:

http://my.fronting.server/myserviceproxypath/api/my/method

Is first authenticated by Asp.Net authentication and then routed to:

http://my.service.baseaddress/api/my/method

with the secret authentication token argument added to data passed. Then the resulting json data is passed back via the proxy.

Pretty nice I think.

Note that I’m using WebClient here instead of HttpClient or HttpWebRequest which are the other two technologies for making requests in the .Net framework. I’m using it because it’s simpler, and because I never seem to get along with Microsofts async approach. I love node.js and promises, but the async await thing just leaves me confused.