ASP.NET MVC Deployment Problem - asp.net-mvc

I have deployed my application to a server running IIS6 using the method which invloves changing the routes to:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Default", // Route name
"{controller}.mvc/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = "" } // Parameter defaults
);
routes.MapRoute(
"Root",
"",
new { controller = "Home", action = "Index", id = "" }
);
}
protected void Application_Start()
{
RegisterRoutes(RouteTable.Routes);
}
And adding a handler in IIS for .mvc extentions. This is working fine for the most part until I add the [Authorize] attribute to HomeController class.
This ends up in the app trying to redirect the user to the logon page which is what I expect however the logon page URL is shown as http://server/virtualdir/Account/LogOn?ReturnUrl=%2fvirtualdir%2fDefault.aspx
This is causing a problem as no .mvc extension is being added to the Account controller part of the URL.

The problem has been solved by changing the following in web.config:
<authentication mode="Forms">
<forms loginUrl="~/Account.mvc/LogOn" timeout="2880" />
</authentication>

Not directly an answer to your question, but from my experience it worked just fine to deploy an application with the new routing features just as it is to IIS6 and add a wildcard mapping to aspnet_isapi.dll. Then you can use any URL you want, and nobody will notice when you change to a newer version in the future.
Yes, static file handling is theoretically less efficient this way, but you will need really a lot of traffic to notice anything. And if you really get a lot of traffic, you still could and even should move all your static files to a another domain/subdomain (or even a CDN) anyway, like stackoverflow.com does. It can still point to the same server, you just use different IIS settings for this subdomain site. But with e. g. just a few thousand visitors per day you don't even have to think about it.

Related

How to create an MVC route to intercept classic ASP URLs?

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" }
);

How can I set the default page in IIS to a Controller?

We have an MVC application that is accessed from two separate websites. The default website is fine, however how can I setup the second site to startup in a specific Controller?
Our default site is www.mysite.com, and we'd like to add a second IIS site for the header www.subdomain.mysite.com that should take users to www.subdomain.mysite.com/controller
But how can I tell IIS to startup www.mysubdomain.mysite.com with the specific controller action mycontroller?
I would consider configuring URL Rewrite so that requests to www.mysubdomain.mysite.com get seen as requests to www.mysubdomain.mysite.com/controller.
You could use Ionics Isapi Rewrite Filter.
Ionic's Isapi Rewrite Filter, aka IIRF, is a small, FREE, easy to use,
URL rewriting ISAPI filter. It combines a good price (free!) with good
features. It is fast and powerful. It works on IIS 6.0, and later.
I ended up adding a value to my AppSettings in web.config, and adjusting the default route of the application based on that value.
public static void RegisterRoutes(RouteCollection routes)
{
var defaultController = ConfigurationManager.AppSettings["DefaultController"];
if (string.IsNullOrEmpty(defaultController))
defaultController = "Home";
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = defaultController, action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
...
}
This allows me to host any number of IIS sites that can each start with a different controller in the application.

ASP.NET MVC: CSS file returning a 302 error when it exists

I'm getting a 302 error returning on a single CSS file on an ASP.NET MVC 2 site in localhost this morning and I don't know what would have changed to cause this.
The localhost site uses IIS 7.5, though I've had limited experience with IIS so I haven't looked to much in to what could be going on there.
The URL to the CSS file is:
http://localhost/MySite/Content/Site.css?v=16
and the location header on the response looks like this:
/MySite/Account/Login?ReturnUrl=%MySite%2fContent%2fSite.css%3fv%3d16&v=16
This makes me think that MVC is redirecting the static file or something like that, however if that was the case, then I would expect all my images, CSS and JavaScript files to be doing the same which they're not. Just in case, here is a simplified version of RegisterRoutes() in Global.ascx:
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("", "Account/{action}/", new { controller = "Account" });
routes.MapRoute("", "{action}", new { controller = "Home", action = "Index" });
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
routes.MapRoute(
"Error",
"{*url}",
new { controller = "Home", action = "ResourceNotFound" }
);
}
Also, if I change the name of my CSS file to Site2.css and reference that instead, the same thing happens.
What's going on?
The redirect to the logon method makes it look like this is because of permissions on the directory or the file rather than an MVC route catching it. (If it were caught by an MVC route, it would probably rather result in an error determining which controller and/or action to use.)
ASP.NET MVC itself leaves static files alone, but if ASP.NET in general decides that the anonymous user doesn't have access to the CSS file or its directory, ASP.NET will redirect to the log-on URL, which will be an ASP.NET MVC action.
Looks like the authorization rules in the web.config are saying that you have to be authenticated to see the css pages. You should be able to prove that by logging in and seeing if you can get the css file to be served correctly.
I'd add a location section to the web.config to remove the authorization requirement on the content directory. Taken from http://support.microsoft.com/kb/316871
<!-- This section gives the unauthenticated user access to all of the files that are stored in the Content folder. -->
<location path="content">
<system.web>
<authorization>
<allow users ="*" />
</authorization>
</system.web>
</location>

ASP.NET MVC action and virtual directory with same path

Is any special routing or IIS config needed when a controller action uses the same URL as a virtual directory?
I have an ASP.NET MVC 1.0 application that needs Windows Authentication applied to a single action ("/Login/FromWindows"). To do this, we've setup a virtual directory with the same path as the action (e.g. "/Login/FromWindows") and enabled Windows Authentication on it in IIS.
When I visit the /Login/FromWindows URL, I get an empty HTTP 200 response and nothing is logged in the server text log. The "FromWindows" action should be logging messages and redirect the user to the home page.
It seems like the action code is simply not being executed, so there is possibly a conflict with the virtual directory.
Route config in Global.asax.cs
public static void RegisterRoutes(RouteCollection routes)
{
// snipped: ignored routes for images, scripts, etc.
routes.MapRoute( "Default", "{controller}/{action}",
new { controller = "Home", action = "Index" } );
}
You are right, the action code isn't being executed. That's because existing file paths (virtual or not) take precedence over MVC routing rules.
Why are you using a virtual directory? Just set authentication to windows in the web.config and use the [authorize] attribute over the corresponding action methods.
Web.config:
<configuration>
<system.web>
<authentication mode=”Windows” />
</system.web>
</configuration>
Action Method:
[Authorize]
public ActionResult SomeAction()
{
return View();
}
Visit http://www.asp.net/mvc/tutorials/authenticating-users-with-windows-authentication-vb for more information on mvc with windows authentication.
Just simple is using [Authorize] attribute a Chevex mention above, or if you want more, you can customize the Authorize by extension it for your business. IMHO.

ASP.NET MVC Routing in Azure

I have an Azure Web Role project that was recently MVC'd by another developer. According to the developer the app works with no problem when run on it's own (i.e. as a simple web app). However, when I try to run it in the context of the Azure cloud service, I'm seeing a number of 404 errors. I suspect something is not quite right with the routing. Here's an abbreviated version of the current RegisterRoutes method that's part of Global.asax.cs:
public static void RegisterRoutes(RouteCollection routes){
routes.IgnoreRoute("{Services}/{*pathInfo}");
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Configuration",
"Configuration",
new { controller = "Configuration", action = "Index" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Account", action = "Index", id = "" }
);}
When the app starts up, the correct view from the Account controller's Index action is displayed. However if I try to navigate to Configuration I get a 404. Converesly if I change the method to this:
public static void RegisterRoutes(RouteCollection routes){
routes.IgnoreRoute("{Services}/{*pathInfo}");
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
"Account",
"Account",
new { controller = "Account", action = "Index" }
);
routes.MapRoute(
"Default",
"{controller}/{action}/{id}",
new { controller = "Configuration", action = "Index", id = "" }
);}
I get the correct view from the Configuration controller's Index action, but I can't navigate to the Account view.
I'm guessing this is a simple problem to solve, but not knowing what exactly was done to "MVC" the Azure app and being new to MVC has me beating my head into the wall.
Here's the configuration of the machine where I'm encountering this issue:
Windows 7 Ultimate with IIS 7.0
Visual Studio 2008 SP1
ASP.NET MVC 1.0
Windows Azure SDK 1.0
Thoughts?
Try using my Routing Debugger. It can help you understand what's going on. http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx
It's weird that the behavior would be different locally than in Azure. Also, you should post your controller code (remove the contents of the action methods, we just need to see the method signatures).
If I had to make a wild guess, I'd guess your Configuration route (in the first example you gave) needs to add id="" in the defaults section.
Haacked: Thanks for pointing me to the debugger. That helped me hunt down the issue in a matter of minutes.
The answer was much simpler than I thought. It all had to do with the following line of code:
routes.IgnoreRoute("{Services}/{*pathInfo}");
I put this line in to help resolve an issue I was having with ASP.NET MVC and WCF RIA Services (more info on that here). The curly braces shouldn't be there. I don't want to replace Services. The code should look like this:
routes.IgnoreRoute("Services/{*pathInfo}");
You can read a full write-up here.
I don't think this is your problem, but you might verify that the System.Web.Mvc reference has its Copy Local = true.

Resources