I am creating a REST API in ASP.NET MVC. I want the format of the request and response to be JSON or XML, however I also want to make it easy to add another data format and easy to create just XML first and add JSON later.
Basically I want to specify all of the inner workings of my API GET/POST/PUT/DELETE requests without having to think about what format the data came in as or what it will leave as and I could easily specify the format later or change it per client. So one guy could use JSON, one guy could use XML, one guy could use XHTML. Then later I could add another format too without having to rewrite a ton of code.
I do NOT want to have to add a bunch of if/then statements to the end of all my Actions and have that determine the data format, I'm guessing there is some way I can do this using interfaces or inheritance or the like, just not sure the best approach.
When a client request is made via a RESTful API, it transfers a representation of the state of the resource to the requester or endpoint. This information, or representation, is delivered in one of several formats via HTTP: JSON (Javascript Object Notation), HTML, XLT, Python, PHP, or plain text.
Task 1 - Creating the API ProjectFrom the File menu, select New Project. Select the Visual C# | Web project type from the project type tree view, then select the ASP.NET MVC 4 Web Application project type. Set the project's Name to ContactManager and the Solution name to Begin, then click OK.
By default Web API returns result in XML format.
The ASP.NET pipeline is designed for this. Your controller actions don't return the result to the client, but rather a result object (ActionResult
) which is then processed in further steps in the ASP.NET pipeline. You can override the ActionResult
class. Note that FileResult, JsonResult, ContentResult
and FileContentResult
are built-in as of MVC3.
In your case, it's probably best to return something like a RestResult
object. That object is now responsible to format the data according to the user request (or whatever additional rules you may have):
public class RestResult<T> : ActionResult
{
public override void ExecuteResult(ControllerContext context)
{
string resultString = string.Empty;
string resultContentType = string.Empty;
var acceptTypes = context.RequestContext.HttpContext.Request.AcceptTypes;
if (acceptTypes == null)
{
resultString = SerializeToJsonFormatted();
resultContentType = "application/json";
}
else if (acceptTypes.Contains("application/xml") || acceptTypes.Contains("text/xml"))
{
resultString = SerializeToXml();
resultContentType = "text/xml";
}
context.RequestContext.HttpContext.Response.Write(resultString);
context.RequestContext.HttpContext.Response.ContentType = resultContentType;
}
}
This is a bit more tricky. We're using a Deserialize<T>
method on the base controller class. Please note that this code is not production ready, because reading the entire response can overflow your server:
protected T Deserialize<T>()
{
Request.InputStream.Seek(0, SeekOrigin.Begin);
StreamReader sr = new StreamReader(Request.InputStream);
var rawData = sr.ReadToEnd(); // DON'T DO THIS IN PROD!
string contentType = Request.ContentType;
// Content-Type can have the format: application/json; charset=utf-8
// Hence, we need to do some substringing:
int index = contentType.IndexOf(';');
if(index > 0)
contentType = contentType.Substring(0, index);
contentType = contentType.Trim();
// Now you can call your custom deserializers.
if (contentType == "application/json")
{
T result = ServiceStack.Text.JsonSerializer.DeserializeFromString<T>(rawData);
return result;
}
else if (contentType == "text/xml" || contentType == "application/xml")
{
throw new HttpException(501, "XML is not yet implemented!");
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With