I’m working on a new ASP.NET MVC and AngularJS application that is intended to be a collection of SPAs. I’m using the MVC areas concept to separate each individual SPA, and then I’m using AngularJS within each MVC area to create the SPA.
Since I’m new to AngularJS and haven’t been able to find an answer regarding combining both MVC and AngularJS routing, I thought I’d post my question here to see if I could get some help.
I have the standard MVC routing setup, which serves up each MVC area.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
routes.AppendTrailingSlash = true;
}
This works fine and gives me URLs like:
http://servername/Application1/
http://servername/Application2/
Now, within each application area, I’m trying to use AngularJS routing, also using $locationProvider.html5Mode(true); so that I get the client-side routing within each area, something like:
http://servername/Application1/view1
http://servername/Application1/view2
http://servername/Application2/view1/view1a
http://servername/Application2/view2/view2a
http://servername/Application2/view3
Here’s my AngularJS routing snippet for Application1:
app1.config(['$routeProvider', '$locationProvider', function ($routeProvider, $locationProvider) {
var viewBase = '/Areas/Application1/app/views/';
$routeProvider
.when('/Application1/view1', {
controller: 'View1Controller',
templateUrl: viewBase + 'view1.html'
})
.when('/Application2/view2', {
controller: 'View2Controller',
templateUrl: viewBase + 'view2.html'
})
.otherwise({ redirectTo: '/Application1/view1' });
$locationProvider.html5Mode(true);
}]);
So, initially, it seems to work (at least the URL looks correct). But, when I start navigating between areas or views within an area, or even if I refresh, something gets “lost” and things don’t work. The URL still looks correct but views aren’t found and aren’t getting loaded correctly.
Any help/guidance on how to make ASP.NET MVC and AngularJS routing work together to give me the scenario described above?
Thanks!!!
Thanks for the answer, agbenyezi. I looked at the article you provided but it only got me back to where I was anyway.
However, I was able to figure it out and get it working. The answer turned out to be relatively simple, but it took some time and a lot of searching around. Anyway, since I am using MVC areas, navigating to a URL of http://servername/Application1/view[x] (where Application1 is the MVC controller (in the area) and view1, view2, view3, etc. are Angularjs views), the MVC part of the overall application was getting confused and trying to find an action named view[x] in the Application1 controller (which doesn't exist).
So, in the area's AreaRegistration class (where it's defining specific routes for the area), I just needed to add a kind of catch-all route before any default MVC routes to always force it to the Index action on the Application controller. Something like:
// Route override to work with Angularjs and HTML5 routing
context.MapRoute(
name: "Application1Override",
url: "Application1/{*.}",
defaults: new { controller = "Application1", action = "Index" }
);
Now, when I navigate to http://servername/Application1/view[x] it routes to the Application1 MVC controller, Index action, and then Angularjs takes over routes to the different views, all while having the HTML5 routing construct in the URL.
Related
We are trying to create two views for our MVC app. Mobile and Web
These were the two links we followed
Handling routing for both Desktop & Mobile Controllers in one instance of ASP.NET MVC
Mixing ASP.NET MVC Display Mode Providers and Routing Rules
Created Account/Login.cshtml page and Account/Login.Mobile.cshtml page (with different layouts). Created a default route
routes.MapRoute(
name: "DefaultMobile",
url: "mobile/{controller}/{action}/{id}",
defaults: new
{
mobile = true,
controller = "Home",
action = "Index",
id = UrlParameter.Optional
}
);
But the problem is that we are using routes.MapMvcAttributeRoutes(); and generating urls like \login. Is there a way to force mobile/login to fetch mobile view. something that force the Routing to display mobile view if the url starts with '/mobile/'?
Or is there another way to do it?
You should be able to specify 2 route definitions with attribute routing as well, one for normal login and one for mobile
[Route("{type}/Login")]
[Route("Login")]
public ActionResult Login(string type = "")
{
var isMobile = String.Equals(type,"mobile",StringComparison.OrdinalIgnoreCase);
// to do : Return something
}
My question up front
How do I construct a route so that MVC will intercept the classic ASP URL and instead execute an MVC action?
I am migrating a legacy classic ASP application to MVC, and need to have MVC intercept a couple of the legacy ASP URLs because they are major endpoints for external access to the application. But I can't seem to figure out how to do it correctly.
I checked a few other questions and didn't quite find what I'm looking for, but maybe my search-fu is poor today. This one is specific to areas but looks similar to mine which still doesn't work, and this one is a possible workaround but I'd really rather handle this completely within MVC and eliminate the legacy file completely.
What I want to do
Given: /foo/bar.asp
Map to: /InboundLinks/HandleBar
(one URL will be a GET request, but the other will be a POST with some sensitive data, so I need them to be intercepted and the POST data still available to MVC, not sure if a 301 redirect will do that or not)
What I DON'T want to do
I do NOT want to run the classic ASP pages at all. (I'm willing to have it solely do a 301 redirect to the MVC URL if that is the only workaround, but that's it) I want the URLs to be intercepted and handled by MVC. I say this because a few questions I found here and elsewhere seemed to generate some confusion on that point.
What I've already tried
routes.MapRoute(
name: "LegacyBarUrl",
url: "foo/bar.asp",
defaults: new { controller = "InboundLinks", action = "HandleBar" }
);
But this returns a 404 Not Found error.
Environment
Visual Studio 2013 running in local dev mode on Windows 7. Deployment will be to IIS 7 on a locked down server I don't control, so installing HTTP modules on the server isn't an option unfortunately. The domain will remain the same.
Many thanks in advance for any help/guidance/etc.
What you've tried must work. Make sure it comes at the top of your routing configuration, and the default route comes after it.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "LegacyBarUrl",
url: "foo/bar.asp",
defaults: new { controller = "InboundLinks", action = "HandleBar" }
namespaces: new[] { "YourProject.Controllers" }
);
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
namespaces: new[] { "YourProject.Controllers" }
);
}
EDIT:
OK, I've tried this myself as well and it really does not work. So you have two options:
(1) capture and route your request at the IIS level: If you take this path, this extension might be very helpful: http://www.iis.net/downloads/microsoft/url-rewrite]
(2) write your own RouteBase and redirect legacy routes before MVC looks up the routing table: If you take this path, this article would be very helpful to you (it would be too long to write the code here): http://www.mikesdotnetting.com/article/108/handling-legacy-urls-with-asp-net-mvc
To Anyone running into this problem, the 404 is because the server is looking for the physical file before getting into the routes. What is needed is a handler for the extension, in this case for the classic asp that is going to catch the request so the server doesn't look for the file anymore, and the request is handled by your handler.
Add an entry to the web config file in the handlers section like this:
<add name="ClassicASPHandler" path="*.asp" verb="GET" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
Then add the needed route to the configuration routes table. Now, the route will be handled correctly as opposed of looking for the file and returning a 404.
routes.MapRoute(
name: "LegacyBarUrl",
url: "foo/bar.asp",
defaults: new { controller = "InboundLinks", action = "HandleBar" }
namespaces: new[] { "YourProject.Controllers" }
);
I have the following URL:
http://localhost/FolderB/Index
This goes to the following controller:
/FolderB/HomeController.cs
I need to instead use this URL: http://localhost/SubComponent.
I'm not sure how that is done in asp.net MVC. What is this type of masking called and where does the code live to accomplish it?
I have tried the following in RouteConfig.cs but it doesn't work:
routes.MapRoute(
name: "SubComponent",
url: "SubComponent",
defaults: new { controller="Home", action="Index", id=UrlParameter.Optional},
namespaces: new[] { "MyNamespace" }
A simple way of doing this would be to add another route in MVC that routes SubComponent.
You can add a route by looking for where your routes are wired up, which is usually either in Global.asax.cs or in a class called RouteConfig and adding your own route:
routes.MapRoute(name: "SubComponent", url: "SubComponent/{id}", defaults: new
{
controller = "Home",
action = "Index",
id = UrlParameter.Optional
});
The order which routes are added matters, so make sure this call to MapRoute occurs before all others.
And specify an area if you need to.
For ASP.NET MVC 5, use RouteAttribute. For older ASP.NET MVC version, you may have to resort to other open source (or your own custom) implementations e.g. https://github.com/mccalltd/AttributeRouting
For Latest Versions:
https://msdn.microsoft.com/en-us/library/cc668201(v=vs.100).aspx
If you are using ASP.NET 3.5 ASP.NET Routing could be a good choice for you.
MSDN page: msdn.microsoft.com/en-us/library/cc668201.aspx
Using it with ASP.NET MVC at ScottGu blog:
weblogs.asp.net/scottgu/archive/2007/12/03/asp-net-mvc-framework-part-2-url-routing.aspx
Using it with ASP.NET 3.5: www.techbubbles.com/aspnet/aspnet-35-url-routing/
If your website runs under ASP.NET 2.0 Helicon ISAPI Rewrite could be a good choise for you. This is an IIS filter that redirects requests to your pages according to regex-based configuration file. They have a free version for one website.
Have a look at Helicon: www.isapirewrite.com
Hope this helps. Good Luck
I have kind of a mixed application with Angular and ASP.NET MVC.
It works this way:
User enters example.com, MVC controller checks if he is Authorized:
if he is, controller returns view Main which contains Angular app.
if he isn't, then a view Index is shown, with login/register form
Logging in/ registering is done within Account controller at example.com/Account
Angular app has html5Mode enabled, so inside-app routing is like example.com/home,example.com/profile etc.
I've tried messing aroung with MVC's RouteConfig, as well as simple rewriting
protected void Application_BeginRequest( Object sender, EventArgs e )
{
string url = Request.Url.LocalPath;
if ( !System.IO.File.Exists( Context.Server.MapPath( url ) ) )
Context.RewritePath( ROOT_DOCUMENT );
}
source: ui-router GitHub page
But nothing adresses my situtation.
Above code basically disables whole MVC routing, so I can't access /Account/LogIn
I've faced a similar issue. I think the best answer I can come up with is to define specialized routes that will allow access to the controllers, and then define a DefaultAll route that will default to the specific controller, and action method that has my Angular code.
For example in my case I have one controller Page, and my first route is
routes.MapRoute(
name: "Default",
url: "Page/{action}/{id}",
defaults: new { controller = "Page", action = "Main", id = UrlParameter.Optional }
);
This means any request with Page/ - will route appropriately to the controller, and use the action method defined in the request. For example Page/main, Page/one, Page/two
My second request is a catch all that defaults to the controller Page, action method Main.
routes.MapRoute(
name: "DefaultAll",
url: "{*.}",
defaults: new { controller = "Page", action = "Main", id = UrlParameter.Optional }
);
This means when I paste a url like http://localhost/myapp/persons , it will load the Page controller, Main action method, which has my Angular routes defined and then Angular will parse the persons part of the URL to perform its routing.
This does mean that if you have more controller, you will need a specialized route for each one.
If you have come up with a better way please do let me know.
I have an MVC 3 site that is working and currently quite basic. There is a folder off of the root called Blog where I have BlogEngine.net setup. Both work as I want. I had to do the following code in the global.asax file to make sure that MVC would ignore any request going to the Blog folder as follows:
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{folder}/{*pathinfo}", new { folder = "Blog" });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home",
action = "Index",
id = UrlParameter.Optional } // Parameter defaults
);
}
What I am looking for is to be able to go to: blog.mysite.com and have it go directly to the /blog folder. I have a Subdomain setup through my hosting provider. However, I am not sure what to do beyond this to tell it to go anywhere. When I currently go to blog.mysite.com, it just takes me to the home page.
I suspect I will have to add a MapRoute assume it will be smart enough to still Ignore the {folder} one.
I think the answer to this question might help you along:
Is it possible to make an ASP.NET MVC route based on a subdomain?