Alexander Beletsky's Development Blog: 2012-07

ASP.NET MVC Routes and Namespaces

While I was working on ELMAH.MVC v.2.0.0 I noticed a something that contradicts the way I understand how the controller resolving mechanism works. Before, I always thought that namespaces matters, but in practice I saw it otherwise.

Controller in separate class assembly

The good way of distribution re-usable software is class assembly. Suppose, I have 2 projects - one ASP.NET MVC web application (MvcApplication2), and another one is class assembly (Awesome.Mvc.Lib). Web application references the class library.




I want to have some particular controller to be exposed from Awesome.Mvc.Lib. Namely, I want to have a controller inside the class library, that would be accessible from MvcApplication2. I'll add some ShinnyController.cs inside.

namespace Awesome.Mvc.Lib
{
    public class ShinnyController : Controller
    {
        [HttpGet]
        public string Index()
        {
            return "I'm in Shinny controller";
        }
    }
}    

Originally, my thought was, ShinnyController will always be "invisible" for MvcApplication2, since it placed into another namespace. Meaning, if I don't initialize a route pointing to ShinnyController, the routing mechanisms would never match it. But, if I run the application and go http://localhost:26810/shinny I will see:




This is totally unexpected to me! It turns out that default route is matching the controller/action from Awesome.Mvc.Lib class library.

routes.MapRoute(
    "Default", // Route name
    "{controller}/{action}/{id}", // URL with parameters
    new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

What I'm expecting though is that ShinnyController.cs have to be "explicitly" routed, and ideally placed into its own sub-URL, like http://localhost:26810/awesome/shinny.

What about namespaces fallback?

I've asked this question on stackoverflow. Even if I had good answer, it did not make it happy. So, to get the behavior I want, I need to do the following:

  1. Change the default routing to explicitly mention the namespace and set fallback to false:
  2. public class MvcApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            var route = routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional }, // Parameter defaults
                new[] { "MvcApplication2" }
            );
    
            route.DataTokens["UseNamespaceFallback"] = false;
    
        }
    
  3. Create an Area in Awesome.Mvc.Lib and configure routing to it:
  4. public class AwesomeAreaRegistration : AreaRegistration
    {
        public override void RegisterArea(AreaRegistrationContext context)
        {
            context.MapRoute("Awesome_default", "Awesome/{controller}/{action}", new { action = "Index" });
        }
    
        public override string AreaName
        {
            get { return "Awesome"; }
        }
    }
    

After I did so, I can reach the http://localhost:26810/awesome/shinny:




And in the same time, http://localhost:26810/shinny is getting to be rejected:




Even though, it looks like desired behavior.. It sucks.

Why it sucks?

By placing the controllers into separate assembly, I'm thinking about it's distribution by simple bin-deployment or by Nuget. Both ways assumes, simple copy of assembly into particular location, adding references and that's it! I don't suppose to change default routing that comes in ASP.NET MVC applications templates.

I want to have the control of routes *inside* the class library, not outside of it (in web application). But, the default behavior of ASP.NET MVC routing is completely different. Moreover, in some cases I want users of library to be able to control the routing.

In my opinion the default behavior with UseNamespaceFallback = true is wrong. I'll give one more example, to proof it.

I removed namespace fallback code from default route, after added new Area, called Api. Inside this Area I place one controller, called SimpleController.

namespace MvcApplication2.Areas.Api.Controllers
{
    public class SimpleController : Controller
    {
        public string Index()
        {
            return "I'm simple controller from API area";
        }

    }
}

The controller is reachable, as expected:




But now, I try to access /simple:




Hey WTF? The whole idea of Areas is just ruined. What I'm doing wrong?

I'm feeling very frustrated about this issue. Even though I understand why it happens, it smells like a bug for me? It works exactly the same for ASP.NET MVC 2, 3, 4. I'm asking you guys, to help to clarify the problem. What is your opinion on that? Are you agree on such default behavior?

Three month without .NET code

It's not farewell letter in style of "Goodbye .NET". But, I just realized that I haven't created any .NET code in about three month. That is pretty much. Mostly all the stuff I currently do, both at work and for fun projects, I do in JavaScript.

I love .NET and love C# language. C# is probably one of the best language I ever programmed with. I think that .NET is my comfort zone. Web technologies as ASP.NET MVC, Web API, NancyFX are great. But, as I said long time ago server side development is not enough to create cool web apps.

Front-end development

For modern web application, the front-end part became as equally important as back-end. In e-conomic we are doing large scale JavaScript applications. According to Addy Osmani's definition, the large scale JavaScript applications are:

non-trivial applications requiring significant developer effort to maintain, where most heavy lifting of data manipulation and display falls to the browser.

This is exactly definition of application we released just few days ago, debitoor.de. And if you are doing front-end, the JavaScript is your friend. Actually, you don't even have a choice.. It's either JavaScript or some another language that could be compiled down to JavaScript as CoffeeScript, ClojureScript or Dart languages. The importance of JavaScript, it's common adoption, growing of community knowledge base made Scott Hanselman call JavaScript assembly language for web.

We've chosen Backbone as front end development framework. With a backbone JavaScript code became to have structure. Having a proper code structure is vital for any project. I've started to learn Backbone and even I still thinking it's too minimalistic and non-complete, I believe that was a huge step forward.

Having implemented and stabilized HTTP API for application, almost all new features implementation was at front end. That means, new features for product were actually born in JavaScript code.

Back-end development

As might know from my earlier post we've chosen ASP.NET MVC to build our HTTP API on. That worked well at the beginning, but later decision were taken to move out the API to Node.js platform. So, another team started to work on new API project, basically implementing existing API interfaces from ASP.NET MVC in Node.js.

Being wisely architected, our front-end did not have major ASP.NET MVC dependencies. We did not use any specific features (like Razor) or anything else just in sake of minification of efforts during switching back-end platform. And I would say it worked really well.

Node.js based API built on Express.js framework, that suites nice for such kind of work. There is a great blog post about convincing you boss to use Node.js. Node.js + MondoDB is very suitable for JSON API applications, for several reasons. First of all is performance, Node.js is known for it's async I/O operations that is so perfect for web. Second is simplicity (relational simplicity, of course). Serving JSON objects inside JavaScript, storing/restoring them as MongoDB documents makes the platform and approaches very solid.

So, the new stuff from HTTP API also got born of JavaScript code. Check out nice post of Allan Ebdrup (one of the Node.js inspiration guys inside e-conomic) about our experience with Node.js and MongoDB.

How does it feel like?

So, I've started to work almost all the time for front-end having Sublime Text 2 + Chrome Developers Tools as IDE. It was a really unusual at the beginning, after many years in Visual Studio.

I feel myself more productive with JavaScript now. I write the code with JavaScript construction and sometimes thinking myself "how would I do in C#?" and it feels like in C# it would be much harder. I like dynamic nature of language.

Besides the coding I have pleasure of new infrastructure. Setting up .NET solution, containing ~80 projects, long build process, setup of MS SQL and re-staring of IIS.. All of that made a lot of idle time, read wasted time. I'm in idle, during waiting till build is finished.. or waiting 30 sec while IIS update AppDomain if I rebuild and press F5. It easily can take up to 2 hours per working day just wasted.

Node.js + MongoBD environment is extremely easy to setup, amazingly fast to work with. I'm restaring the application in 1 sec, just by stopping node process and running it again. With a tools like nodemon, you don't even need to do that. Just save the code and after a sec, press F5 in browser to test it. All of that are increases general developers happiness.

JavaScript is difficult language and Node.js is new platform that requires respect and time to learn. Node.js is probably one of the best documented projects I ever worked with. Besides, it's open source. It means you can learn from sources. I haven't dig inside Node.js code itself, but I did look inside the Express.js then I had an issue and I found the answer as I see how particular method works.

Even though, Backbone.js code and Node.js code are completely different stuff, having the same language both front-end and back-end is great thing. In particular it minimizes the language context-switching then you do coding. It's possible to apply similar patterns and practices both ends.

Conclusions

Being a JavaScript developer works good for me so far. I opened just entire new world and would like to explore it more. I hope JavaScript would be my comfort zone some day.