Geeks With Blogs
CodeBWare A ASP.NET web and database programming blog

Original article by Nilesh Hirapra, February 29th, 2012

Updated and revised by Cory Koski, January 15th, 2013

History

This article is an updated version of the “ASP.NET MVC - Pluggable application modules/components/area/features” article written by Nilesh Hirapra. I found the original article it to be incredibly useful. However, ASP.NET MVC 4 was released, and I found following the original article (which relied on ASP.NET MVC 3) required some adjustments to make it work correctly with the updated framework. This article is an updated version of Nilesh’s original work with ASP.NET MVC 4 specific changes, as well as some extra screenshots, inline code, and some readability and grammatical improvements. I would like to acknowledge and extend a big thanks to Nilesh for providing the original text and the guidance for this useful modularization technique.

Before you begin

This article assumes you are using:

  • Visual Studio 2012
  • ASP.NET MVC 4
  • ASP.NET and Web Tools 2012.2 update
  • C#

Scenario

When a web application has many modules (or sub-applications, features, or whatever your business calls them) and gets larger the more modules you plug in, the harder the code base is to partition and maintain.

Solution

It becomes apparent that these modules should be developed independently without any direct dependencies (other than CSS, layouts, and JavaScript libraries) on the main application code. The development team desires a modular solution, one that is easily maintained over time and separates these larger modules from each other. Ideally, once each module is ready for integration, they could be then plugged into the main application with little to no adjustment of the main application.

This article discusses how to develop ASP.NET MVC 4 applications requiring these loosely coupled modules, but aren’t part of the main application code.

Business Value

This is specifically useful for product development. Using this approach, each module may be developed and deployed/shipped for the product separately. This helps in building different versions of the product, like basic, professional, premium, and enterprise versions. This loosely coupled modular approach enables product developers to create the separation needed to either build separate installers with the required features for each different version, a master setup which can only install defined features as per license key used during installation, or some other configuration requiring the modular separation technique.

Building the application

Suppose we want to build a product which has following modules:

1.        Marketing

2.        Sales

3.        Billing

4.        Inventory

5.        Warehouse

We want to build a product which allows selling/distribution/deployment of each above modules as a separate feature. Typically such products will have some basic features/infrastructure and these modules will fit on top of that. Let’s assume we have the basic application with a master page, landing page, authentication, security, logging and related resources. We will build an application with the pluggable modules as listed above.

Setting up the main application project

Open Visual Studio 2012 and create an ASP.NET MVC 4 project with a Basic template. (I have named the project/solution as ProductDemo in this example):

image

Once it’s created, your solution should look like this:

image

Next, right-click on the Controllers folder and select “Add -> Controller...”. Give it the name HomeController, and select “Empty MVC Controller” for the template:

image

Right-click on the Index method of the controller and select “Add View…”. Using the defaults, create the Index view for HomeController to create the landing page for the application:

image

Pluggable modules menu items and expected output

To prepare the application with its menu items pointing to the expected modules, edit _Layout.cshtml (in the Views\Shared folder) like so:

<!DOCTYPE html>

<html>

<head>

    <meta charset="utf-8" />

    <meta name="viewport" content="width=device-width" />

    <title>@ViewBag.Title</title>

    @Styles.Render("~/Content/css")

    @Scripts.Render("~/bundles/modernizr")

</head>

<body>

    <div>

        <div>

            <h2>Product Demo - Pluggable Modules</h2>

        </div>

        <div id="nav">

            @Html.ActionLink("Home","Index","Home", new {Area=""}, null) |

            @Html.ActionLink("Marketing","Index","Marketing", new {Area="Marketing"}, null) |

            @Html.ActionLink("Billing","Index","Billing", new {Area="Billing"}, null) |

            @Html.ActionLink("Inventory","Index","Inventory", new {Area="Inventory"}, null) |

            @Html.ActionLink("Warehouse","Index","Warehouse", new  {Area="Warehouse"}, null)

        </div>

        <hr />

        <div>

                @RenderBody()

        </div>

    </div>

    @Scripts.Render("~/bundles/jquery")

    @RenderSection("scripts", required: false)

</body>

</html>

Running the application, the output now looks like this:

image

Creating Areas folder structure and get sample of XXXXAreaRegistration file

Now right-click on the main application project title in the Solution Explorer and select “Add->Area…” from the context menu. This step will create the basic folder structure for the Area framework. Specify “Marketing” as Area name and click “Add”:

image

You should have a folder solution structure that looks like this:

image

Now take a backup of the MarketingAreaRegistration.cs file since we are going to delete the Marketing folder in the next step (copy it to the root of your application for now, Desktop, or a temporary folder). This file will be needed when we add the Marketing module to the solution as a separate project. (This file can also be created manually once you know how to make one yourself).

Now remove the Marketing subfolder from the Areas folder, keeping the Areas folder in place.

Adding pluggable module/area to main application

Next, to add the new pluggable module for “Marketing”, right-click on the solution and choose “Add-> New Project…”. In the dialog box do following:

image

  • Select ASP.NET MVC 4 Application
  • Name project as ‘Marketing’
  • Set Location as “…\ProductDemo\Areas\”

A new project should be created in the Areas folder we created. Create the project using the Basic template:

image

Note: there appears to be a bug that may cause an error when creating this project using the Visual Basic MVC4 templates. Ignoring the error doesn’t seem to be a problem however, but I can’t guarantee that it won’t have some impact. YMMV.

In the newly created Marketing project, remove the following:

  • App_Data
  • App_Start
  • Content folder
  • Shared sub-folder under View
  • global.asax file

These are added as part of the Basic MVC 4 project template but not needed for us since we are creating this as a pluggable module.  After this step, the solution should look like following:

image

Since we saved new project marketing under the Areas folder, it is appearing as hidden folder under the ProductDemo/Areas folder in the Solution Explorer:

image

Adjust the ProductDemo’s RouteConfig.cs file to properly add the correct namespace overload to the context.MapRoute() method:

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

using System.Web.Routing;

 

namespace ProductDemo

{

    public class RouteConfig

    {

        public static void RegisterRoutes(RouteCollection routes)

        {

            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

 

            routes.MapRoute(

                "Default",

                "{controller}/{action}/{id}",

                new { controller = "Home", action = "Index", id = UrlParameter.Optional },

                new string[] { "ProductDemo.Controllers" }

            );

        }

    }

}

Add your backed up MarketingAreaRegistration.cs file to the root in the Marketing project and change its namespace to use the ProductDemo namespace in the ProductDemo project, like below:

using System.Web.Mvc;

 

namespace ProductDemo

{

    public class MarketingAreaRegistration : AreaRegistration

    {

        public override string AreaName

        {

            get

            {

                return "Marketing";

            }

        }

 

        public override void RegisterArea(AreaRegistrationContext context)

        {

            context.MapRoute(

                "Marketing_default",

                "Marketing/{controller}/{action}/{id}",

                new { controller = "Marketing", action = "Index", id = UrlParameter.Optional },

                new string[] { "Marketing.Controllers" });

        }

    }

}

Also note above that the context.MapRoute() method is also using the overloaded version of the method which accepts the namespace of the controller to use.

Now set the output directory of Marketing project to ..\..\bin\ so that its compiled DLLs are placed in the bin directory of the ProductDemo application:

image

In the Marketing project, modify web.config file to remove the connection strings, authentication, membership, rolemanager, profile, and session state, sections.

Now create the Marketing controller (you can have make any other controller as well) in the Marketing project.

using System;

using System.Collections.Generic;

using System.Linq;

using System.Web;

using System.Web.Mvc;

 

namespace Marketing.Controllers

{

    public class MarketingController : Controller

    {

        //

        // GET: /Marketing/

 

        public ActionResult Index()

        {

            return View();

        }

 

    }

}

Create an Index view and place the content “Welcome to the Marketing Module” in its header:

@{

    ViewBag.Title = "Index";

}

 

<h2>Welcome to the Marketing Module</h2>

 

The ProductDemo application is now ready to use with the Marketing module. Build the solution. After building, take a look at the ProductDemo\bin folder and you will see the compiled DLLs for the Marketing module located in there:

image

Next, run the Product Demo application to see that it is working. In the browser, click the Home and Marketing links to see how the application is switching back and forth between the ProductDemo application shell page and the Marketing module page, each using their respective controllers.

ProductDemo index using the ProductDemo.Controllers.Home controller:

image

Marketing index using the Marketing.Controllers.Marketing controller:

image

Repeat the process to create the rest the modules.

That’s it!

How does this work?

The ASP.NET MVC Areas structure enables creating separate logical modules and those still resides in same project and binary. Notice xxxAreaRegistration.cs in the Marketing project which is inherited from AreaRegistration. This file tells ASP.NET MVC 4 and the Routing framework the Area name and Route for accessing the Marketing Area and its controller actions. The Global.asax.cs in the ProductDemo main application registers Route information for the application, by way of RouteConfig.cs. This registraton also registers all Areas defined in all assemblies present in application bin directory. Since we have directed the output of the Marketing module to the ProductDemo main application bin directory, the Marketing module Area gets picked up and is “automagically” included.

From a rendering perspective, the main application ProductDemo has a master page (_Layout.cshtml) which is in the Views/Shared directory in the ASP.NET application. As per ASP.NET and the MVC 4 Framework, this layout is inherited to its all sub directories. This way even if the Marketing module is a separate project, it inherits the master page of the main application. The same applies to all other resources like CSS files, images, JavaScript libraries, and other static resources or pages.

Posted on Tuesday, January 15, 2013 10:18 AM | Back to top


Comments on this post: ASP.NET MVC 4 pluggable application modules

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
terrible idea, that is very hack like and not very good. Look into razor generator and write a new article.
Left by P Bo on Feb 24, 2013 9:33 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
What about deployment?
the Area-project will be ignored during publish..
Left by Daniel on Mar 07, 2013 3:37 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
@Daniel, my guess is when publishing yes, but when you Build it, it Builds everything in the Solution. And AFAIK, if you Publish something, it builds all projects in the solution before publishing.

Wonder why P Bo is saying this is a bad idea? I can't find anything else that allows me to just upload a new DLL and have that module of my site updated
Left by Pieter on Mar 27, 2013 5:48 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Very good approach when working on a large project. Similar approach is used by Nopcommerce guys.
Left by Nikhil on Apr 23, 2013 2:42 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Could the pluggable module (marketing) have Areas in itself...ie. like having Sub-Areas under Areas in the main project?
We need to incorporate a third-party made shopping-cart MVC-4 app (which itself has Areas) into our Webapp (preferably under an Area like "Webshop"), and would like to use the _Layout.cs for that "sub-App".

Would this be the way to go?
Left by reinhard on Apr 27, 2013 8:59 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
@reinhard I've tried to implement this, and only got it partially working. An expert in .NET and MVC 4 should be able to pull it together, however out of the box it does not work and breaks. The solution needs to be well thought out, and would likely involve a lot of customization to get it going. Areas within areas is a neat idea, and would allow for some great ways to modularize projects. I wonder if there is someone who has actually done it?
Left by CokoBWare on Apr 29, 2013 9:22 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
@reinhard, it looks like someone has figured this problem out, but in a different way. I don't know how "pluggable" this is, but it definitely seems flexible.

http://mvccoderouting.codeplex.com/
Left by CokoBWare on Apr 29, 2013 9:27 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Thanks!
I will look into this link!
Left by reinhard on Apr 29, 2013 1:27 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Thank you so much for this!!! I would like to make a recommendation that was driving me a little off the walls. Instead of changing the csproj output path, use the following post-build event:

copy /Y "$(TargetDir)$(TargetFileName)" "$(SolutionDir)$(SolutionName)\$(OutDir)$(TargetFileName)"

This will greatly help if you are using a 3rd party reference dll that you still would like to get intellisense for in the razor syntax.
Left by SMOF on May 01, 2013 5:01 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
We are implementing such an architecture at a client.
One web core with plugins created by separate teams (which go into the Areas folder).
Now we want the ability for a plugin team to deploy the plugin by creating a package. The core should not be redeployed each time.
Did you people have experience with this?
How would these have to be achieved.

The goals is that an administrative person runs the package (eventually with some customizations).

(Deployment package - MSBuild - MSDeploy)
Left by Stephan Peters on May 06, 2013 8:19 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Thanks for sharing!
Left by Rainmaker on May 09, 2013 1:17 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Hi,
I have a question!
Why do I need to add namespace to ProductDemo’s RouteConfig.cs?
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
=>
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new string[] { "ProductDemo.Controllers" }
);
Left by Rainmaker on May 09, 2013 1:47 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
@Rainmaker I can't really recall why. Here's two possible reasons:

It is also possible that I included the namespaces because I had run into an issue of having a "dirty" bin folder in my initial experimentation. Older DLLs that were no longer being written were still there at one point. When I ran the application, I got ambiguous controller error messages.

OR

Without namespaces for your route mappings, your web app gets confused and doesn't know which controller to invoke if you have similar method names in your controller.

In any event, I've moved onto other projects, so I would recommend you experiment with the last reason I mentioned and see if your application breaks or not when you remove namespaces in the route information.
Left by CokoBWare on May 10, 2013 11:50 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
I followed this article, everything worked perfectly fine but I wonder about one thing: Does it really load the sub-projects dynamically?

I can replace an assembly (e.g. marketing.dll) but I can't add a new assembly unless I rebuild the ProductDemo project. Any chance to improve this solution to achieve this?
Left by Remo on May 15, 2013 4:11 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
This seems really nice. But I see a huge drawback in the fact that if you were to move the PROJECT (not the assemblies) from the Area, then this does not work, which tells me that convention over config is taking place. Having to keep source code in the area doesn't sit well with me. Possibly messing with the viewengine would help?
Left by Chris on May 20, 2013 5:27 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
@Chris yeah this is a convention over config solution. I didn't develop it initally, just translated it to MVC 4. However, I think you're right in that if you need to have a more flexible option, then a custom view engine would totally work better.

As an aside, I played with this trying to come up with a way to do Areas within Areas, with limited success (my .NET kung fu is limited). I managed to get the pages to target the sub areas by messing with the view engine, but once I got the sub-Area pages loading, I couldn't render them with the master page. I'm certain someone with a bit more .NET prowess could do it though.
Left by CokoBWare on May 21, 2013 9:50 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
@Remo, the way Areas work is that when you create an Area, it's registered by way of a class inheriting from AreaRegistration. Each Area has it's own registration and subsequent routing rules, and they are built into the main ProductDemo.dll assembly. I'm sure you could engineer a way to "plug-in" these Area registrations in some way, but that is beyond the scope of this article. If you have an implementation that can achieve this, let me know and I'll link to it.
Left by CokoBWare on May 21, 2013 10:10 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Hi, I am getting following Error. The view 'Index' or its master was not found or no view engine supports the searched locations.
When runing Admin Area. Please can you upload Code of this article.
Left by Najam on Jul 03, 2013 3:57 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Please can you provide code for this article. Thanks in advance
Left by Najam on Jul 03, 2013 3:58 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Really good and easy to read article.
I made a small prototype at first and it worked perfectly. But now I'm trying to apply the whole idea to the real big project and I'm just stuck with 404 error.
Looks like I cannot access the controller. I posted a full description here - http://stackoverflow.com/questions/17471918/asp-net-mvc-4-routing-a-controller-in-a-separate-assembly-returns-error-404
I would appreciate if you can give me any ideas.
Thanks!
Left by Anelook on Jul 04, 2013 11:02 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
When I implement your solution and I add a view named Index to my marketing controller and run the application it is saying that it can't find the view.

I set a breakpoint on the index actionresult in the marketingcontroller and it will get hit.
Left by DrOak on Jul 19, 2013 9:10 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Hi, this works perfectly when the area/plugin s created by me. However, I want to integrate a 3rd party blog engine (nblog.codeplex.com). My problem is that this blog engine does some stuff in the global.asax file like initializing IoC containers etc. Is there anyway to do this within my plugin project, it kinda defeats the aim if have to tinker with the main application code to get the plugin to work. Any help will be appreciated. Thanks.
Left by ObiOne on Jul 27, 2013 3:59 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
How would you reference CSS and JavaScripts which are in the pluggable area? E.g. <script type="text/javascript" src="~/Scripts/abc.js"></script> will go back to the root and look in a scripts folder in the root project, not in the area project.
Left by James D on Jul 28, 2013 8:30 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Thanks for this great article.
Can we add more controllers to the marketing plugin. If so, how?
I added a new controller called Page1Controller and its view. The application is not able to detect it when it runs.
Left by Satyajit on Aug 13, 2013 12:26 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Is uploading a single DLL do? What about the views of the module projects?
Left by Ramesh on Aug 27, 2013 9:07 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Thanks for this good article.
I am having issue while sharing javascript variable across module.

Ex. added new script at main app level and I am able to access same variable from module. issue is variable get initialize at every module level. is it possible to maintain scope of variable as global across module? how.

Left by Sanjay Jha on Oct 02, 2013 6:00 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Hi Guy,

I follow the guide, found difficulty here
putting the 1 JS under Marketing/Scripts/common.js
How to include this Javascript, encounter 404 in my test project.
Left by xcod on Oct 22, 2013 10:06 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
hi,
I have followed above steps I have added maketing successfully .But getting error that resource not found while adding billing.Can you tell me where i went wrong
Left by Kiran on Dec 10, 2013 2:52 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
How about Unity.MVC? When I try to register the containers in Bootstrapper.cs, I can't get a reference to them. How would I incorporate his?
Left by Jass on Feb 11, 2014 1:43 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Figured it out by using httpPost instead of httpGet.
Left by Jass on Feb 11, 2014 4:52 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
this approach is not Applied!!
this approach only do causing rise development costs.
Thank you ,for define new way to development web app.
Yours truly.
Left by Amin Ghaderi on Mar 09, 2014 10:04 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Facing problem while deploying the application.
Its only publishing the main project with its views (in this case ProductDemo)the projects in the area folder are not deploying.
Even if I add references of the projects in area (in this case Marketing) in the main projects, only the ddl of the projects in area get deployed in bin folder, no views of the project in areas getting deployed.
Whats going wrong
Left by Saurabh on Apr 30, 2014 5:24 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Dear all,

I have implement this method to my organization. Everything is fine except the problem about Razor (*.cshtml) files. In some projects, I am facing with the Razor error problem such as "The name '..' does not exist in the current context", "[PagePath]: ASP.Net runtime error: there is no build provider registered for the extension '.cshtml'.." or other errors (that I have found and forgot)

Please notice that I have tried many instruction but there is not solved the problems permanently.

Sincerely yours,
Pranithan
Left by Pranithan on May 06, 2014 4:43 AM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Good try , but IMHO it's a hack.Need of copying the files into View folder is.I wonder is there any solution proposed by Microsoft ..Is there any wcsf equivalent for asp.net mvc ?
Left by Pushpendra s patwal on May 28, 2014 10:31 PM

# ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Hi!
I have a problem about 2 HomeController, one located Marketing Project, other one located Main Project but they render 1 view. How can i fix ?
Left by Jimmy on Aug 12, 2014 11:13 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Hi,
I tried this module. it's working nice , please can you tell me how to deploy this project
Left by Sangeeth on Nov 22, 2014 1:47 PM

# re: ASP.NET MVC 4 pluggable application modules
Requesting Gravatar...
Hi,

Did anyone know how the deployment works for this asp.net mvc4 plug-in application?

Thanks in advance
Left by lalith on Jun 05, 2015 10:00 AM

Your comment:
 (will show your gravatar)


Copyright © Cory Koski | Powered by: GeeksWithBlogs.net | Join free