Search code examples
model-view-controllerasp.net-mvc-5

Adding self-hosted Asp.NET MVC 5 into an existing Winforms/console project


How do I add a selfhosted Asp.Net MVC 5 application inside my existing Winforms project? I already have the self-hosted mvc 5 app working fine as a separate console app.

But,now I need to load this MVC 5 project into a subfolder of my existing Winforms application and I need make calls to my existing business logic classes inside the controller.


Solution

  • On the web about adding MVC support to an existing WebForms application. The two play nicely side-by-side in the same project

    First you would need to make your MVC project a portable area. Details about this can be found here. A Portable Area is a dll that contains items that would normally be part of your solution. Portable Areas contain Views, Controllers, Models, even JS Scripts, CSS files and images.

    Disadvantages of a portable Area:

    Every time you make a change to any View, JS File, CSS File, or image within your Portable Area, you will need to rebuild it. I emphasize these components because they do not normally need to be rebuilt when being tested or developed.

    This can become a problem. If you find yourself re-building every time you tweak CSS, 30 second changes become 2 minute changes. Make 30 of those and you've stretched 15 minutes worth of work into 2 hours.

    Next, you need to update your web.config file. Replace the default compilation section with the following:

    <compilation debug="true" targetFramework="4.0">
    <assemblies>
        <add assembly="System.Web.Abstractions, Version=4.0.0.0, 
             Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Routing, Version=4.0.0.0, 
             Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
        <add assembly="System.Web.Mvc, Version=2.0.0.0, 
             Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    </assemblies>
    

    Also add a pages element with the namespaces shown:

    <pages>
        <namespaces>
            <add namespace="System.Web.Mvc"/>
            <add namespace="System.Web.Mvc.Ajax"/>
            <add namespace="System.Web.Mvc.Html"/>
            <add namespace="System.Web.Routing"/>
        </namespaces>
    </pages>
    
    
    
    <system.webServer>
      <validation validateIntegratedModeConfiguration="false"/>
      <modules runAllManagedModulesForAllRequests="true"/>
    </system.webServer>
    

    and add the MVC HTTP handler and a binding redirect for MVC:

    <httpHandlers>
        <add verb="*" path="*.mvc" 
            validate="false" type="System.Web.Mvc.MvcHttpHandler,
            System.Web.Mvc, Version=2.0.0.0, Culture=neutral, 
            PublicKeyToken=31BF3856AD364E35"/>
    </httpHandlers>
    
    <runtime>
        <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
            <dependentAssembly>
                <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
                <bindingRedirect oldVersion="1.0.0.0" newVersion="2.0.0.0" />
            </dependentAssembly>
        </assemblyBinding>
    </runtime>
    

    Now in our Global.asax file we need to register the portable area:

    public class SomeHybrid: System.Web.HttpApplication
    {
        public static void RegisterGlobalFilters(GlobalFilterCollection filters)
        {
            filters.Add(new HandleErrorAttribute());
        }
    
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    
            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
    
        }
    
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
    
            RegisterGlobalFilters(GlobalFilters.Filters);
            RegisterRoutes(RouteTable.Routes);
        }
    }
    

    Now, at this point I can visit both pages. The WebForms page is a file on disk, so ASP.NET routing passes requests directly on to this page when I /default.aspx. The ASP.NET Routing engine is engaged so I can also hit /Home/Index.

    If I want to get fancy, You can add a PageRoute so You have pretty URLs when visit my WebForms pages as well. Just add a route in the Global.asax like this. Make sure that simple routes like these come first, as the default ASP.NET MVC route is very "greedy" and would gobble up a simple URL like /calculator

    routes.MapPageRoute("WebFormThing", "Calculator", "~/Default.aspx");