ActionResult for all occasions

    The farther into the forest, the thicker the MVC framework. Just the other day, preview of the second version came out. Quickly familiarizing myself with the possibilities, I was very pleased. But then I remembered about a simple and very interesting RoR feature , which is not yet (even in plans) in MS MVC.
    We are talking about the ability to specify an "extension" for the Action method and, thus, determine the type of View.


    To get started, consider an example. Request ht_p: // localhost / Blog / Comments / 0 returns an html page containing a list of comments for article number 0 on the blog. In this case, Blog is the name of the controller, Comments is the name of the method, 0 is the post ID.
    The controller code will look something like this:

    public class BlogController : Controller
    {
      public ActionResult Comments(int id)
      {
        var strings = new[] { "Один", "Два", "Три" }; // Представим, что это комментарии
        return View(strings);
      }
    }

    * This source code was highlighted with Source Code Highlighter.


    Everything is simple here!

    But what if we need to get a list of comments serialized in json in addition to the html page? The easiest way is to create another method, name it, say, CommentsJson, and explicitly call the Json () method. For example, like this:

    public ActionResult CommentsJson(int id)
    {
      var strings = new[] { "Один", "Два", "Три" }; // Представим, что это комментарии
      return Json(strings);
    }

    * This source code was highlighted with Source Code Highlighter.


    Now we can get the json list at ht_p: // localhost / Blog / CommentsJson / 0.

    The problem is solved, do we disagree? Frankly, this code does not suit me. Firstly, duplication, secondly, I don’t like the url that will have to be used later, thirdly, there is no way to use the scheme in other methods.

    In this case, the opportunity to create our own ActionResult will come to our aid. We will try to solve the problem "on the forehead." Change the Comments method as follows:

    public class BlogController : Controller
    {
      public ActionResult Comments(int id)
      {
        var strings = new[] { "Один", "Два", "Три" }; // Представим, что это комментарии
        return new ComplexResult
            {
              Json = () => Json(strings),
              View = () => View(strings)
            };
      }
    }

    * This source code was highlighted with Source Code Highlighter.


    As you can see, the ComplexResult class must be inherited from ActionResult.
    Let's try to implement it like this:

    public class ComplexResult : ActionResult
    {
      public override void ExecuteResult(ControllerContext context)
      {
        object value;
        if (context.RouteData.Values.TryGetValue("result", out value))
        {
          var result = value.ToString();
          if (result.Equals("json", StringComparison.InvariantCultureIgnoreCase))
          {
            Json().ExecuteResult(context);
            return;
          }
        }

        View().ExecuteResult(context);
      }

      public Func Json { get; set; }

      public Func View { get; set; }
    }

    * This source code was highlighted with Source Code Highlighter.


    Here we need to explain: when processing the result, we check for the presence of the string “result” in the list of values ​​obtained when parsing the request. We make sure that the user has sent the line “json” and run JsonResult, predefined by the user. If the line is not found or it is not equal to "json", we launch ViewResult. The logic is pretty simple.

    In parallel with this, add the lines to the routes setting:

    public static void RegisterRoutes(RouteCollection routes)
    {
      routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

      // Наш route должен стоять перед default
      routes.MapRoute("Result", "{controller}/{action}.{result}/{id}",
        new { controller = "Home", action = "Index", id = "", result = "view" });

      routes.MapRoute("Default", "{controller}/{action}/{id}",
              new { controller = "Home", action = "Index", id = "" });
    }

    * This source code was highlighted with Source Code Highlighter.


    Now we are able to get the json object by explicitly specifying this in the ht_p: //localhost/Blog/Comments.json/0 query string. Or ht_p: // localhost / Blog / Comments / 0 - when we need html. And most importantly, we can easily use ComplexResult in other methods without clogging the code with repeated methods.

    Fantasy suggests that in this way you can add other standard or non-standard (XmlResult, RssResult, etc.) ActionResults to ComplexResult. Perhaps this awaits us in future versions of ASP.NET MVC.

    The code is written, now excuses: I recommend using the code written in this note only to familiarize yourself with the capabilities of the MVC framework, it is obvious that it is not safe, some checks and conditions are omitted to simplify.

    Thanks for attention.

    Also popular now: