Friday, October 17, 2014

ASP.NET MVC - Return JSON without using JsonResult

After using ServiceStack and ASP.NET Web API, and then using ASP.NET MVC again, you'll be wanting to just return the model as-is and just forget the explicit infrastructure to return the model as JSON

public JsonResult GetTopSellingProduct(int year)
{
    using(IDataStore ds = new DataStore(_nhibernateSessionFactory))
    {
        return Json(Product.GetTopSellingProduct(ds, year), JsonRequestBehavior.AllowGet);
    }    
}


This is how we wanted to return models as JSON even in ASP.NET MVC controller:
public Product GetTopSellingProduct(int year)
{
    using(IDataStore ds = new DataStore(_nhSessionFactory))
    {
        return Product.GetTopSellingProduct(ds, year);
    }    
}


Turns out that is possible, Adam Bar noticed ASP.NET MVC can be made to return JSON object implicitly


Here's a complete code that enables ASP.NET Web API-like controller action to ASP.NET MVC. This is using NetJSON for JSON serialization, and DryIoc for IoC/DI needs. DryIoc is the fastest IoC/DI and NetJSON is the fastest JSON serializer

using Erp.Controllers;

using DryIoc; // http://www.palmmedia.de/blog/2011/8/30/ioc-container-benchmark-performance-comparison
using NJ = NetJSON; // http://theburningmonk.com/2014/08/json-serializers-benchmarks-updated-2/

using System;

using System.Linq;



namespace Erp
{
    public class MvcApplication : System.Web.HttpApplication
    {
        DryIocDependencyResolver _ioc = new DryIocDependencyResolver(); // Customized DefaultControllerFactory
        
        protected void Application_Start()
        {
            System.Web.Mvc.AreaRegistration.RegisterAllAreas();

            
            FilterConfig.RegisterGlobalFilters(System.Web.Mvc.GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(System.Web.Routing.RouteTable.Routes);

                        
            System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(_ioc);
            
        }
    
    }
       

    class DryIocDependencyResolver : System.Web.Mvc.DefaultControllerFactory
    {
        internal DryIoc.Container _container;

        public DryIocDependencyResolver()
        {
            _container = new DryIoc.Container();
            RegisterTheIocs();
        }


        protected override System.Web.Mvc.IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            System.Web.Mvc.IController ic = controllerType == null
                ? null
                : (System.Web.Mvc.IController)_container.Resolve(controllerType);


            // _container.ResolvePropertiesAndFields(controller);  // uncomment this if you want to use DI on controller's properties

            var mvcController = ic as System.Web.Mvc.Controller;

            if (mvcController != null)
                mvcController.ActionInvoker = new SimulateWebApi();

            return mvcController;
        }


        class SimulateWebApi : System.Web.Mvc.ControllerActionInvoker
        {
            const string JsonContentType = "application/json";

            protected override System.Web.Mvc.ActionResult CreateActionResult(
                System.Web.Mvc.ControllerContext controllerContext, System.Web.Mvc.ActionDescriptor actionDescriptor, object actionReturnValue)
            {
                if (actionReturnValue == null)
                    return new System.Web.Mvc.EmptyResult();

                return (actionReturnValue as System.Web.Mvc.ActionResult) ?? new System.Web.Mvc.ContentResult()
                {
                    ContentType = JsonContentType,
                    Content = NJ.NetJSON.Serialize (actionReturnValue)
                };
            }
        }


        void RegisterTheIocs()
        {            
            System.Reflection.Assembly assembly = typeof(HomeController).Assembly;

            foreach (var controller in assembly.GetTypes().Where(t => typeof(System.Web.Mvc.Controller).IsAssignableFrom(t)))
            {
                _container.Register(controller, DryIoc.Reuse.InResolutionScope);                
            }
           

            _container.Register(typeof(Elmah.Mvc.ElmahController), DryIoc.Reuse.InResolutionScope);

            // http://ayende.com/blog/153701/ask-ayende-life-without-repositories-are-they-worth-living
            // http://www.ienablemuch.com/2014/10/typical-nhibernate-sessionfactory-auto-mapping.html
            _container.RegisterDelegate<NHibernate.ISessionFactory>(x => Erp.DomainMapping.Mapper.SessionFactory, DryIoc.Reuse.Singleton);            
        }

    }//DefaultControllerFactory

    

}//namespace



JSON Serializers benchmark: http://www.ienablemuch.com/2014/10/benchmarking-net-json-serializers.html


Happy Coding!

No comments:

Post a Comment