Carlos Cifuentes
Modernization · ASP.NET MVC

Migrating AngularJS that lives inside ASP.NET MVC

Many AngularJS apps were never standalone. They grew inside ASP.NET MVC projects, with Razor rendering part of the page. Before the frontend can move, four knots between client and server have to be untied.

By Carlos Cifuentes · Frontend architect · Updated 2026-10-02

What this kind of app looks like

A typical project has an MVC controller that returns a Razor view. The layout file renders the navigation and the script bundles. The view contains an ng-app attribute, and AngularJS takes over from there. Often each MVC view hosts its own small AngularJS module, so the product is a set of mini applications connected by full page loads.

For a migration this means the frontend cannot be moved alone. Four things tie it to the server.

Knot 1: Razor inside the templates

AngularJS templates are frequently served as Razor partial views. That lets the server decide what goes into the template:

  • Role checks that include or remove a button.
  • Localized labels from resource files.
  • Model data serialized into the page or into ng-init.

A modern Angular build compiles its templates ahead of time. It cannot consume a template that the server changes per request.

How to untie it

  1. List every template that contains Razor expressions.
  2. Move permissions to an endpoint that returns what the current user may do. The client shows or hides elements from that data. The server keeps enforcing the rules on every API call.
  3. Move localized text to JSON files or an endpoint that the client loads.
  4. Replace injected model data with API calls.
  5. Convert the partial views to static HTML templates.

After this step the old frontend is still AngularJS, and it now talks to the server only through HTTP. That is the precondition for everything else.

Knot 2: Bundling

Classic MVC projects bundle scripts on the server, with the bundle configuration in C# and render helpers in the layout. Angular needs a Node-based build that produces its own hashed files.

How to untie it

  • Add the Angular workspace to the repository and build it in CI before the .NET build.
  • Publish the output as static files in the same site.
  • Let the layout reference the generated files. Because the file names contain hashes, read them from the build output, or serve the generated index.html directly for the SPA routes.

Knot 3: Authentication cookies

MVC applications normally sign users in with a cookie. This is good news: a SPA served from the same site sends that cookie automatically, so users keep one login. Two details need attention.

  • Expired sessions. By default, cookie authentication answers an unauthenticated request with a redirect to the login page. An API call from the SPA then receives the login page HTML instead of an error. Configure API paths to return a 401 status, and handle it in one HTTP interceptor.
  • Anti-forgery tokens. Razor forms carry a hidden token. API calls need the same protection through a request header. Angular's HTTP client can read a token from a cookie and send it as a header, and ASP.NET can validate that header. Set up both sides and test a POST early.

Do not replace the authentication mechanism in the same phase as the first migrated screens. Moving from cookies to tokens with an identity provider is a valid project. Run it separately, before or after, so each change can be tested and rolled back independently.

Knot 4: Routing split between server and client

In the old model, MVC routes pick the page and AngularJS routes work inside it. In the target model, the client router owns the application URLs and the server exposes an API.

How to untie it

  • Reserve a path prefix for the API, for example /api.
  • Add a fallback so that any application URL returns the SPA entry page. Deep links and refresh then work.
  • Keep the remaining MVC pages on their existing routes until they are migrated. The proxy or the MVC route table decides which URLs still belong to Razor.

A workable order

  1. Assessment: inventory views, Razor expressions in templates and endpoints.
  2. Untie Knot 1 inside the AngularJS app. No user-visible change.
  3. Set up the Angular build and the hybrid application (Knot 2).
  4. Fix the 401 and anti-forgery behavior (Knot 3).
  5. Add the fallback route (Knot 4) and migrate the first screen.
  6. Continue screen by screen, as described in How to migrate AngularJS to Angular without downtime.

Keep the backend upgrade separate

If a move from .NET Framework to current .NET is also planned, run it as its own project. With an API between them, each side can be upgraded alone.

Pages that mix Razor with jQuery follow a similar route, described in the jQuery migration guide. The Java equivalent of this guide is AngularJS with Java and JSP.

More in this section

Planning a migration or a micro-frontend platform?

In a 20-minute call you describe your situation and I tell you how I'd approach it. If it isn't worth doing yet, I'll say so.

Message me on LinkedIn