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.
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.
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.
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
You have following MVC controller actions that you want to use for above SPAs:
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
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:
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
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:
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.
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:
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.
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)
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.
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
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.
Different teams can work on Main, App1, App2 and App3 as independent deliverables with this approach.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With