开发者

Best way to structure the code for an ASP.NET MVC REST API that is decoupled from the data formats?

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 开发者_Go百科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.


Serialization

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;
   }
}

Deserialization

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!");
    }
}


Just wanted to put this on here for the sake of reference, but I have discovered that using ASP.NET MVC may not be the best way to do this:

Windows Communication Foundation (WCF) provides a unified programming model for rapidly building service-oriented applications that communicate across the web and the enterprise

Web application developers today are facing new challenges around how to expose data and services. The cloud, move to devices, and shift toward browser-based frameworks such as jQuery are all placing increasing demands on surfacing such functionality in a web-friendly way. WCF's Web API offering is focused on providing developers the tools to compose simple yet powerful applications that play in this new world. For developers that want to go further than just exposing over HTTP, our API will allow you to access all the richness of HTTP and to apply RESTful constraints in your application development. This work is an evolution of the HTTP/ASP.NET AJAX features already shipped in .Net 4.0.

http://wcf.codeplex.com/

However I will not select this as the answer because it doesn't actually answer the question despite the fact that this is the route I am going to take. I just wanted to put it here to be helpful for future researchers.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜