Chitika

March 26, 2012

ASP.NET MVC 4 WebAPI. Support Areas in HttpControllerFactory

This article was written for ASP.NET MVC 4 Beta. If you are using Release Candidate version of ASP.NET MVC 4 then you have to read the next article.

Unfortunately DefaultHttpControllerFactory doesn't support Areas by default.
To support it you have to write your HttpControllerFactory from scratch.

In this post i will show you how you can do it.

AreaHttpControllerFactory


First of all, you have to implement IHttpControllerFactory interface:
    public class AreaHttpControllerFactory : IHttpControllerFactory
    {
        public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
        {
            throw new NotImplementedException();
        }

        public void ReleaseController(IHttpController controller)
        {
            throw new NotImplementedException();
        }
    }
We will implement two obligatory methods CreateController and ReleaseController later.

Let's start with fields and constructor:
        private const string ControllerSuffix = "Controller";
        private const string AreaRouteVariableName = "area";

        private IHttpControllerFactory _defaultFactory;
        private HttpConfiguration _configuration;
        private Dictionary<string, Type> _apiControllerTypes;

        public AreaHttpControllerFactory(HttpConfiguration configuration)
        {
            _configuration = configuration;
            _defaultFactory = new DefaultHttpControllerFactory(configuration);
        }
Our class is wrapper around DefaultHttpControllerFactory.
I hope i don't need to explain meaning of ControllerSuffix constant. But I would like to explain the AreaRouteVariableName constant - it contains the name of the variable which we will use to specify area name  in Routes collection.

In the _apiControllerTypes we will store all the API controllers types, so let's create private property:
        private Dictionary<string, Type> ApiControllerTypes
        {
            get
            {
                if (_apiControllerTypes != null)
                {
                    return _apiControllerTypes;
                }

                var assemblies = AppDomain.CurrentDomain.GetAssemblies();

                _apiControllerTypes = assemblies.SelectMany(a => a.GetTypes().Where(t => !t.IsAbstract && t.Name.EndsWith(ControllerSuffix) && typeof(IHttpController).IsAssignableFrom(t))).ToDictionary(t => t.FullName, t => t);

                return _apiControllerTypes;
            }
        }

This code, just takes all the API controllers types from all of your assemblies, and store it inside the dictionary, where the key is FullName of the type and value is the type itself.
Of course we will set this dictionary only once. And then just use it.

Now we are ready to implement the one of our main methods. I will start with ReleaseController method:
        public void ReleaseController(IHttpController controller)
        {
            _defaultFactory.ReleaseController(controller); 
        }
Easy.

The last method will do all the "magic" for us:
        public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
        {
            var controller = GetApiController(controllerContext, controllerName);
            return controller ?? _defaultFactory.CreateController(controllerContext, controllerName);
        }
Easy as well. :)
And the method which will find the controller for us:
        private IHttpController GetApiController(HttpControllerContext controllerContext, string controllerName)
        {
            if (!controllerContext.RouteData.Values.ContainsKey(AreaRouteVariableName))
            {
                return null;
            }

            var areaName = controllerContext.RouteData.Values[AreaRouteVariableName].ToString().ToLower();
            if (string.IsNullOrEmpty(areaName))
            {
                return null;
            }

            var type = ApiControllerTypes.Where(t => t.Key.ToLower().Contains(string.Format(".{0}.", areaName)) && t.Key.EndsWith(string.Format(".{0}{1}", controllerName, ControllerSuffix), StringComparison.OrdinalIgnoreCase)).Select(t => t.Value).FirstOrDefault();
            if (type == null)
            {
                return null;
            }

            return CreateControllerInstance(controllerContext, controllerName, type);
        }
So, if an area variable is specifying in RouteData.Values and this variable is not null or not empty, then it tries to find the controller in the ApiControllerTypes by full name of the controller where the full name contains area's name surrounded by "." (e.g. ".Admin.") and ends with controller name + controller suffix (e.g. UsersController).
If the controller type is found, then it will calls CreateControllerInstance method. Otherwise, the method will return null.

And the code for CreateControllerInstance:
        private IHttpController CreateControllerInstance(HttpControllerContext controllerContext, string controllerName, Type controllerType)
        {
            var descriptor = new HttpControllerDescriptor(_configuration, controllerName, controllerType);
            controllerContext.ControllerDescriptor = descriptor;
            var controller = descriptor.HttpControllerActivator.Create(controllerContext, controllerType);
            controllerContext.Controller = controller;
            return controller;
        }

Registering AreaHttpControllerFactory


The next thing you have to do is to say to your application to use this controller factory instead of DefaultHttpControllerFactory. And fortunately it is really easy - just add one additional line to the end of Application_Start method in Glogal.asax file:
        protected void Application_Start()
        {
            // your default code

            GlobalConfiguration.Configuration.ServiceResolver.SetService(typeof(IHttpControllerFactory), new AreaHttpControllerFactory(GlobalConfiguration.Configuration));
        }
That's all.

Using AreaHttpControllerFactory

If you did everything right, now you can forget about that "nightmare" code. And just start to use it!

You have to add new HttpRoute to your AreaRegistration.cs file:
        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.Routes.MapHttpRoute(
                name: "Admin_Api",
                routeTemplate: "api/admin/{controller}/{id}",
                defaults: new { area = AreaName, id = RouteParameter.Optional }
            );

            // other mappings
        }

That's all. Good luck, and have a nice day.

61 comments:

  1. "public class AreaControllerFactory" "new AreaHttpControllerFactory(" small error here. :)

    ReplyDelete
  2. Care to add this to http://github.com/WebApiContrib/WebAPIContrib?

    ReplyDelete
  3. Thanks for the article. I was stumbling over this.

    ReplyDelete
    Replies
    1. I'm happy that my posts are helping

      Delete
    2. It is working for me...good work

      Delete
  4. Worked like a charm. Thanks for writing it up.

    ReplyDelete
  5. Looking forward to see how you implement this now that IHttpControllerFactory is gone from RC.

    ReplyDelete
    Replies
    1. Finally I finished it. You can find it at http://netmvc.blogspot.be/2012/06/aspnet-mvc-4-webapi-support-areas-in.html

      Delete
  6. Ecorptrainings.com provides ASP.NET in hyderabad with best faculties on real time projects. We give the best online trainingamong the ASP.NET in Hyderabad. Classroom Training in Hyderabad India

    ReplyDelete
  7. This is great article about online training.thanks for giving information about
    online training.
    oracle fusion procurement online training

    ReplyDelete
  8. Your blog gives the best and the most interesting information. This kind of information that i had been looking from many days thanks for sharing this blog........ R12 HRMS Online Training

    ReplyDelete
  9. CALFRE handles oracle fusion financials online training and its modules maintaining classroom based training with
    the self-paced videos. An expert having ten plus years of self-experience handles the training period through
    online and explains each and every point perfectly. We recently launched our institute in the USA and getting
    the best reputation over there



    Oracle fusion Financials Online Training

    Oracle Fusion Financials online Training

    ReplyDelete
  10. Thanks for posting the blog. I felt comfortable while reading the post. Keep posting more blogs.
    we are the best CALFRE Search Engine search about all different courses in Al Karama, Dubai Locations. For Example Seach a course like Oracle Training Oracle Training Click Here

    ReplyDelete
  11. Nice Information Sir,Thanks for sharing.For more details visit us:
    Oracle Fusion Financials Online Training

    ReplyDelete
  12. This blog explains the details of most popular technological details. This helps to learn about what are all the different method is there. And the working methods all of that are explained here. Informative blog.
    Oracle HRMS Training Institutes in Hyderabad

    ReplyDelete
  13. Thanks for such a great website which is helping people who is new to oracle apps and professional also.Your site is very impressive and you are doing an amazing job.
    Oracle Fusion Financials Training in Chennai

    ReplyDelete
  14. Good Post. I like your blog. Thanks for Sharing-----------------!
    ASP.NET Course Delhi

    ReplyDelete
  15. This is a nice article you shared great information. I have read it thanks for giving such a wonderful Blog for the reader.
    SQL Azure Online Training
    Azure SQL Training
    SQL Azure Training

    ReplyDelete
  16. Thanks for sharing such a great information. Its really nice and informative. learn devops online and devops training videos.

    ReplyDelete

  17. I found some useful information in your blog, it was awesome to read, thanks for sharing

    Workday HCM Online Training
    Workday HCM Training
    Workday HCM Certification

    ReplyDelete
  18. That is nice article from you , this is informative stuff . Hope more articles from you . I also want to share some information about ibm mainframe training .

    ReplyDelete

  19. That is nice article from you , this is informative stuff . Hope more articles from you . I also want to share some information about mainframe tutorial .

    ReplyDelete
  20. Your good knowledge and kindness in playing with all the pieces were very useful. I don’t know what I would have done if I had not encountered such a step like this.

    python training in bangalore

    python training in hyderabad

    python online training

    python training

    python flask training

    python flask online training

    python training in coimbatore


    ReplyDelete
  21. An overwhelming web journal I visit this blog, it's unfathomably amazing. Unusually, in this present blog's substance made inspiration driving truth and reasonable. The substance of data is enlightening.


    Full Stack Course Chennai
    Full Stack Training in Bangalore

    Full Stack Course in Bangalore

    Full Stack Training in Hyderabad

    Full Stack Course in Hyderabad

    Full Stack Training

    Full Stack Course

    Full Stack Online Training

    Full Stack Online Course



    ReplyDelete
  22. This is an amazing blog, thank you so much for sharing such valuable information with us.
    Workday Integration Training
    Workday Integration Course India

    ReplyDelete
  23. Compre documentos en línea, documentos originales y registrados.
    Acerca de Permisodeespana, algunos dicen que somos los solucionadores de problemas, mientras que otros se refieren a nosotros como vendedores de soluciones. Contamos con cientos de clientes satisfechos a nivel mundial. Hacemos documentos falsos autorizados y aprobados como Permiso de Residencia Español, DNI, Pasaporte Español y Licencia de Conducir Española. Somos los fabricantes y proveedores de primer nivel de estos documentos, reconocidos a nivel mundial.

    Comprar permiso de residencia,
    permiso de residenciareal y falso en línea,
    Compre licencia de conducir en línea,
    Compre una licencia de conducir española falsa en línea,
    Comprar tarjeta de identificación,
    Licencia de conducir real y falsa,
    Compre pasaporte real en línea,

    Visit Here fpr more information. :- https://permisodeespana.com/licencia-de-conducir-espanola/
    Address: 56 Guild Street, London, EC4A 3WU (UK)
    Email: contact@permisodeespana.com
    WhatsApp: +443455280186

    ReplyDelete
  24. This blog covers some most asked topics in the Azure Data Engineer Interview Questions with fully explained answers and details dp203

    ReplyDelete
  25. Microsoft recently updated a certification named Azure Data Engineer Associate. To get this tag you need to clear one examination named: Exam DP-203: Data Engineering on Microsoft Azure.

    ReplyDelete

  26. Thanks for sharing this valuable information to our vision. You have posted a trust worthy blog keep sharing.we provide internship training in chennai

    ReplyDelete
  27. Thanks for Sharing This Article. It is very so much valuable content. Embedded Systems Course in Hyderabad

    ReplyDelete
  28. Once you have thoroughly cleaned and dried your curvy sex dollラブドールyou can place it back in its storage bag or box. If your sex doll has detachable parts, such as the head, arms, or legs, store them separately to avoid damage or loss

    ReplyDelete
  29. Great Write - up, very much informative for the readers. For more information's Click Here

    ReplyDelete
  30. Informative blog, Really insightful Click Here

    ReplyDelete
  31. Very Insightful, As the contents being described detailly. If you are interested in knowing more information Check Here

    ReplyDelete
  32. Amazing Write up - For more informations check Here

    ReplyDelete
  33. ery Insightful, As the contents being described detailly. If you are interested in knowing more information click here

    ReplyDelete
  34. This is the good website and also i love this website https://sclinbio.com

    ReplyDelete
  35. This comment has been removed by the author.

    ReplyDelete