I have a fairly large legacy ASP.Net MVC app that uses different AngularJS controllers on each of about 20 different pages. Many modules, services, and directives are shared, but this application has never used AngularJS's routing; each page is effectively its own app, with its own ng-app tag that loads when the .NET MVC view renders. Each page is very dynamic in the normal AngularJS way, but routing between pages is handled exclusively by MVC.
I'm very experienced in AngularJS but new to Angular 2+, having only done the Tour of Heroes tutorial and a few other samples. I assumed I would be able to do something very similar with Angular--basically rewriting each controller as a component and developing everything inside one Angular application, building it with the CLI, linking the appropriate dist/
scripts into each MVC view, but only using one component on each MVC view.
For example, I was expecting to put this onto the Billing MVC view:
<app-root>
<app-billing-component></app-billing-component>
</app-root>
and this onto the Plan view
<app-root>
<app-plan-component></app-plan-component>
</app-root>
But when I tried a proof of concept, the build process gave me only the one very basic index.html page with the empty <app-root>
element on it, because everything including all the HTML templating gets pushed into the main.js file. Trying to reference the individual components in that file (or any other file, like my MVC views) doesn't work because main.js is getting compiled "all or nothing" as if this were an SPA and no other HTML page/URL would ever be loaded into the browser as part of this app. I can't figure out how I would handle putting one component into each view without developing them in separate "apps" and building a different main.js file for each one.
I can't imagine my need is unique, but I haven't been able to dig up an example of someone trying to do the same thing. "This is not the normal way to do Angular" goes without saying; my question is: how can I do something like this? Is there a way to tweak the build? Do I have to find a way to link specific files into my MVC views without using ng build
?
Reading this 9 months later, it was hard to put myself back into the mindset I had back then, and even understand my own question. The solution turned out to be: get into the Angular mindset, and find a way to make it work within a .NET MVC application, by rendering only the one component specified by the route in the URL.
Details:
public class NgController : Controller
{
public ActionResult Index()
{
string relativePath = "~/dist/index.html";
string absolutePath = Server.MapPath(relativePath);
if (System.IO.File.Exists(absolutePath))
{
string fileText = System.IO.File.ReadAllText(absolutePath);
return Content(fileText, "text/html");
}
else
{
return HttpNotFound();
}
}
}
[NgLayoutExecute]
public ActionResult Billing()
{
throw new NotImplementedException("This action should be intercepted by the NgLayoutExecute filter attribute and this code should not be reached.");
}
public class NgLayoutExecuteAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var ngApplicationRootController = new NgController();
ngApplicationRootController.ControllerContext = filterContext.Controller.ControllerContext;
// return the result of the Index action method of the NgController -- this is basically the index.html file
var result = ngApplicationRootController.Index();
// Set the result to be rendered
filterContext.Result = result;
base.OnActionExecuting(filterContext);
}
}
<rule name="AngularFiles" stopProcessing="true">
<match url="^(runtime|polyfills|vendor|main)(\.[a-f0-9]{10,20})?(.js)(.map)?$" />
<action type="Rewrite" url="dist/{R:0}" logRewrittenUrl="true" />
</rule>
<rule name="AngularStyles" stopProcessing="true">
<match url="^styles(\.[a-f0-9]{10,20})?(.css)$" />
<action type="Rewrite" url="dist/{R:0}" logRewrittenUrl="true" />
</rule>
Kind of a lot to it, but it integrates really well, and the only way the users can tell the Angular components aren't developed with 100% the same technology as the standard MVC pages is because there are a few small style differences in the CSS files.