Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should my MVC controller really know about JSON?

Tags:

The JsonResult class is a very useful way to return Json as an action to the client via AJAX.

public JsonResult JoinMailingList(string txtEmail) {         // ...         return new JsonResult()        {            Data = new { foo = "123", success = true }        }; } 

However (at least according to my first impression) this really isn't a good separation of concerns.

  • Unit test methods are harder to write becasue they don't have nice strongly typed data to test and have to know how to interpret the Json.
  • Its harder for some other View in future that isn't over HTTP (or any remote protocol involving serialization) to be 'plugged in' because its unnecessary in such cases to be serializing and deserializing the response.
  • What if you have TWO different places that need the results of that action? One wants Json and another wants XML or perhaps a fully or partially rendered view.

I'm wondering why the translation between an object and Json wasn't implemented declaratively via an attribute. In the code below you're essentially telling MVC that this method is convertible to Json, and then if it is called from an AJAX client a check is made for the attribute the new JsonResult() conversion performed internally.

Unit testing can just take the action result (ObjectActionResult) and pull out the strongly typed Foo.

[JsonConvertible] public ActionResult JoinMailingList(string txtEmail) {         // ...         return new ObjectActionResult()        {            Data = new Foo(123, true)        }; } 

I was just curious as to people's thoughts and any alternative pattern to follow.

These are also just my initial observations - there are probably more reasons why this is not an ideal design (and probably plenty why its a perfectly acceptable and practical one!) I'm just feeling theoretical and devils-advocatey tonight.

 * Disclaimer: I haven't even begun to think about how the attribute would be implemented or what sideeffects or repurcussions etc. it might have.

like image 390
Simon_Weaver Avatar asked Jan 27 '09 05:01

Simon_Weaver


People also ask

What is the use of JSON in MVC?

"JSON" (JavaScript Object Notation) is a lightweight text-based open standard designed for human-readable data interchange. When working together with "jQuery" and "ASP.NET MVC" in building web applications, it provides an efficient mechanism to exchange data between the web browser and the web server.

What is JSON result MVC?

What is JsonResult ? JsonResult is one of the type of MVC action result type which returns the data back to the view or the browser in the form of JSON (JavaScript Object notation format).

What is JSON format in MVC?

The JSON format is an open standard format. The format of data looks very easy to understand and the data objects consist of attribute-value pairs. ContentEncoding: It helps to indicate the content encoding type, the default encoding for JSON is UTF-8. ContentType: It helps to indicate the content type.


2 Answers

I think you're getting worked up over nothing. So what if the controller knows about JSON in its public interface?

I was once told: "Make your code generic, don't make your application generic."

You're writing an Application Controller here. It's OK for the Application Controller - whose responsibility is to mitigate between the model and views and to invoke changes in the model - to know about a certain view (JSON, HTML, PList, XML, YAML).

In my own projects, I usually have something like:

interface IFormatter {     ActionResult Format(object o); } class HtmlFormatter : IFormatter {     // ... } class JsonFormatter : IFormatter {     // ... } class PlistFormatter : IFormatter {     // ... } class XmlFormatter : IFormatter {     // ... } 

Basically "formatters" that take objects and give them a different representation. The HtmlFormatters are even smart enough to output tables if their object implements IEnumerable.

Now the controllers that return data (or that can generate parts of the website using HtmlFormatters) take a "format" argument:

public ActionResult JoinMailingList(string txtEmail, string format) {     // ...     return Formatter.For(format).Format(         new { foo = "123", success = true }     ); } 

You could add your "object" formatter for your unit tests:

class ObjectFormatter : IFormatter {     ActionResult Format(object o) {         return new ObjectActionResult() {             Data = o         };     } } 

Using this methodology, any of your queries/actions/procedures/ajax calls, whatever you want to call them, can output in a variety of formats.

like image 82
Frank Krueger Avatar answered Oct 23 '22 10:10

Frank Krueger


I generally try not to worry about it. The Asp.Net MVC is enough of a separation of concerns to keep leakage to a minimum. You're right though; there is a bit of a hurdle when testing.

Here's a test helper I use, and it's worked well:

protected static Dictionary<string, string> GetJsonProps(JsonResult result) {     var properties = new Dictionary<string, string>();     if (result != null && result.Data != null)     {         object o = result.Data;         foreach (PropertyDescriptor prop in TypeDescriptor.GetProperties(o))             properties.Add(prop.Name, prop.GetValue(o) as string);     }     return properties; } 

You can use the Request.IsAjaxRequest() extension method to return different ActionResult types:

if (this.Request != null && this.Request.IsAjaxRequest())     return Json(new { Message = "Success" }); else     return RedirectToAction("Some Action"); 

Note: you'll need that Request != null to not break your tests.

like image 25
Rob Rodi Avatar answered Oct 23 '22 12:10

Rob Rodi