Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC 5 & Angular 2 Multiple "Siloed" Apps Structure Advisement

We have a large already existing MVC 5 ASP.NET 4.5.1 web application. The core concept since there are so many areas it covers, is that each page was it's own application. All the existing pages don't use anything besides JQuery, regular Javascript, and Handlebars templating.

Angular 2 seems very exciting, but I'm trying to figure out how exactly it will work with our philosophy. For example below is how our mvc routing serves up our separate apps currently...

Area/Controller1/Action1(App1)

Area/Controller1/Action2(App2)

Area/Controller2/Action1(App3)

etc.

Then we have separate API controllers to serve up our JSON data. From initial readings/learnings of Angular 2 I can't seem to wrap my head around how I would serve separate apps (since everything I can find always wants the index.html as the home, which makes sense if you really are making a SPA). Essentially, we're trying to continue development with multiple SPAs served up via this existing structure, not have to change older "legacy" apps on the site to use Angular until they are revisited individually, and figure out how to do the routing effectively.

Routing: So an example in my head would be Area/Controller/Action(App)/routeUrlstuff

I still want to be able to let them copy and paste that extended link and be brought back using the angular routing, instead of maybe just cutting off that URL and starting the angular app at it's starting point.

I don't really have any code to show, as I'm attempting to do a current project as a proof of concept that using Angular 2 from now on is viable for the application.

like image 316
Richard Cawthon Avatar asked Apr 17 '17 21:04

Richard Cawthon


People also ask

Is MVC 5 a core?

The main difference between ASP.NET Core and ASP.NET MVC 5 is their cross-platform approach. ASP.NET Core can be used on Windows, Mac, or Linux, whereas ASP.NET MVC 5 can only be used for applications on Windows. The ASP.NET Core MVC is a framework for building web apps and APIs, optimized for use with ASP.NET Core.

What is difference between MVC 5 and MVC 6?

The ASP.NET 5 is an open-source platform for developing web applications on Windows, Mac and Linux. On the other hand, The ASP.NET MVC 6 is the framework for building web apps on the ASP.NET 5 platforms.


2 Answers

I recently worked on a project which had similar concerns. We did thought about implementing multiple SPAs but in the end decided to implement one SPA with multiple modules.

I think we can extend that solution for multiple SPAs as well. Let’s look at a simple use case:

You want to create 2 SPAs

  1. UserApp containing 2 modules (AddUser and ManageUser)
  2. ProductApp containing 2 modules (AddProduct and ManageProduct)

You have following MVC controller actions that you want to use for above SPAs:

  1. myApp/user/add
  2. myApp/user/manage
  3. myApp/product/add
  4. myApp/product/manage

MVC controller actions 1 and 2 are to be used with SPA UserApp, routing to AddUser and ManageUser modules. Similarly, controller actions 3 and 4 are to be used with SPA ProductApp, routing to AddProduct and ManageProduct modules.

Conceptually this looks like:

Multiple SPAs with multiple modules

Angular Bundling:

I would leave the typescript transpiling and bundling to Angular CLI. If your project gets complex and you feel that the angular cli can’t handle your bundling needs, you can always eject webpack configuration.

There is a really good blog from Yakov Fain that you can look for configuring cli to bundle multiple SPAs. Basically you will be configuring angular cli to output your SPAs to different dist folders. In our case, let’s assume that these will be:

  1. userAppDist for UserApp SPA
  2. productAppDist for ProductApp SPA

MVC Layouts:

To Load different SPAs on different pages, you will have to create different layouts or sub-layouts for each SPA.

Let’s Say: _userLayout.cshtml for UserApp

Inside _userLayout.cshtml, you will have to load your scripts from userAppDist folder

Something like this:

<main class="layout">
    <base href="/">
</main>

@*Now load scripts from userAppDist*@

Similarly you will have to implement layout for the other SPA loading scripts from productAppDist. Let’s say _productLayout.cshtml

Routes:

To keep things simple you can match your server routes to angular SPA module routes. Otherwise, you will have to implement HashLocationStrategy on angular App. Assuming you are going with the simple option, you have following views:

  1. myApp/user/add --> AddUser.cshtml
  2. myApp/user/manage --> ManageUser.cshtml
  3. myApp/product/add --> AddProduct.cshtml
  4. myApp/product/manage --> ManageProduct.cshtml

AddUser.chtml and ManageUser.cshtml will use _userLayout and will look like:

<user-app></user-app>

This is targeting UserApp SPA

AddProduct.cshtml and ManageProduct.cshtml will use _productLayout and will look like:

<product-app></product-app>

This is targeting ProductApp SPA

The MainAppComponent templates for these Apps will have

<router-outlet></router-outlet>

which will resolve to the angular module routes, based on the routes from the server. Now you have to match the routes in you angular Apps

Example for UserAppRoutingModule:

const routes: Routes = [
  { path: 'myApp/user/add', loadChildren: 'userApp/modules/add-user/add-user.module#AddUserModule' },
  { path: 'myApp/user/manage', loadChildren: 'userApp/modules/manage-user/manage-user.module#ManageUserModule' }
];

Similarly, you will have to define matching routes for the product pages in product App SPA.

Hope this helps.

Update: Configuration to avoid multiple route files

For above use case, there will be following controllers:

UserController with index action pointing to user/index.cshtml (using _userLayout) having following code:

 <user-app></user-app>

ProductController with index action pointing to product/index.cshtml (using _productLayout) having following code:

<product-app></product-app>

You will also need to modify you routeConfig.cs to include following:

routes.MapRoute("user", "user/{*catchall}", new { controller = "User", action = "Index", id = UrlParameter.Optional });
routes.MapRoute("product", "product/{*catchall}", new { controller = "Product", action = "Index", id = UrlParameter.Optional });

Above changes will force following behaviour:

  1. Routes to myapp/user --> will go to user/index.cshtml
  2. Also, any extended routes after myapp/user/blah/blah will still resolve to user/index.cstml

User/index.chtml spins up Angular User SPA and then angular routes will kick in. You will observe similar behavior from product route and product/index.cshtml as well.

Final route configuration on angular SPA user:

const routes: Routes = [
    { path: 'user', redirectTo: 'user/add' },
    { path: 'user/add', loadChildren: 'userApp/modules/add-user/add-user.module#AddUserModule' },
    { path: 'user/manage', loadChildren: 'userApp/modules/manage-user/manage-user.module#ManageUserModule' }
  ];

The first route is default for user app. This maps to the MVC route myapp/user. Rest of the routes are not required to match MVC routes. You will have to do similar configuration on product SPA as well.

like image 176
Saurabh Lath Avatar answered Oct 21 '22 00:10

Saurabh Lath


From a solution architect perspective, I would recommend changes both on server side and client side.

To being with, lets say there are 3 apps Area/Controller1/Action1(App1)

Area/Controller1/Action2(App2)

Area/Controller2/Action1(App3)

1. Identify SPA's

Develop angular SPA for main application. The view from the main application has links to Controller1. This should be a route in your angular SPA. However Controller1/Action1 should be a route not available in angular SPA. It needs to be requested directly from the server using html href links. This essentially means page reload.

2. Project Locations on Server

Once development is complete for different SPA's, generate the production build with compressed JS and index.html.

Place the different SPA under their respective folders. For example, /home/user/proj/Controller1/Action1 is a folder which has independent SPA

proj
-- Controller 1
---- Action 1
---- Action 2
-- Controller 2
---- Action 1

3. Webserver Configuration

Configure your web/app server. For example in nodejs. (IIS will have something similar)

# For Action SPA
location = /area/(.*)/(.*) {
  root /home/user/proj/$1/$2;
}
# For main SPA
location = / {
  root /home/user/proj;
}

where $1 will contain target Controller and $2 will contain target Action

The index.html from /area/target Controller/target Action will be fetched and these Action are independent SPA of their own.

4. Summary

Different teams can work on Main, App1, App2 and App3 as independent deliverables with this approach.

like image 30
Faiz Mohamed Haneef Avatar answered Oct 21 '22 00:10

Faiz Mohamed Haneef