Creating a RESTful JSON API in a legacy .NET 3.5 application

Our online Directory has been around in essentially the same form since the early 2000s, though I’ve rewritten it as a PHP application, then as part of Microsoft Content Management Server 2003 as a .NET 1.0 application, then as a PHP application again, and then as a .NET 1.1 application, and then upgraded it in .NET a few times. Along the way, it acquired a SOAP web service, which is accessible at https://directory.middlebury.edu/WebDirectory.asmx and is the primary interface for Directory information displayed in our Drupal sites, including profiles.

This fall, we needed to add a RESTful web service that returned some public Directory information as a JSON string for use in a mobile app. If I were doing the Directory all over from scratch it would probably be some MVC application with some nice endpoints that returned this data already, if it was in .NET, but that’s not the situation we’re in right now, so I had to find a way to hack a REST API on top of this thing.

Apparently, that’s possible using a Web Service ASMX file, which looks like a SOAP service, but with a few tweaks can act like a REST service. The gist below ends in .cs, but that’s just so the syntax highlighting looks nice. It’s really a .asmx file.


using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.DirectoryServices;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Web.Script.Services;
/// <summary>
/// Summary description for RESTfulDirectory
/// </summary>
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ScriptService]
public class RESTfulDirectory : System.Web.Services.WebService {
public RESTfulDirectory () {
}
[WebMethod]
[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public void Search(string q) {
Results results = new Results();
results.directory = new List<Result>();
if (q != null && q != "")
{
// get the results from the directory
string search = "the LDAP search query";
DataTable dt = Directory.query(search, "none");
foreach (DataRow dr in dt.Rows)
{
Result result = new Result();
// populate the property fields
results.directory.Add(result);
}
}
string json = Newtonsoft.Json.JsonConvert.SerializeObject(results, Newtonsoft.Json.Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore });
HttpContext.Current.Response.Write(json);
}
}
public class Results
{
public List<Result> directory;
}
public class Result
{
// properties
}

The first key is to uncomment the “[ScriptService]” notation above the class so that it can act as an AJAX response service, if needed. Next, above the method for the service response, add the notation “[ScriptMethod(UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]”, which allows the service to accept GET requests and return a JSON response. Change the return type of the method to “void”, since we’ll just be printing our response directly, rather than returning a value that gets send via an XML wrapper.

The inner part of my search method is mostly program logic that creates an object and populates it with information from the Directory application based on the input query and business logic about what data to return. I decided to use the JSON.NET NuGet package after trying .NET’s native JavaScriptSerializer class, which kept pegging the CPU t 100% trying to serialize the object.

The JSON.NET object serializer offers a few more advantages. You can tell it to indent the response, if you want (I chose not to), and you can tell it not to include any property in the response where the value is null. For instance, if a person doesn’t have a telephone number, rather than returning “{phone: null}”, that portion of their record will just be blank.

Lastly, I write the JSON string directly to the HTTP response, which is why I earlier changed the method return type to void. With this in place, the service is now available at http://directory.middlebury.edu/RESTfulDirectory.asmx/Search?q=

Leave a Reply

Your email address will not be published. Required fields are marked *