Purpose of UrlRouting.axd - asp.net-mvc

What is the purpose of "UrlRouting.axd" in web.config?
To get ASP.NET routing to work in IIS integrated mode everybody suggests adding the following line, with absolutely zero explanation as to why it should make routing work:
<add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
At first blush this line makes no sense because it just maps "UrlRouting.axd" (that is never invoked from the client) to the forbidden handler (which will always return an error). I don't really like mindlessly copy-pasting things I have no understanding of, so an explanation of how it works will help me. :)

Related

MachineKeySessionSecurityTokenHandler and the session token expiring between application restarts

In my MVC application, I am using forms authentication to authenticate the user and then System.IdentityModel.Services.SessionAuthenticationModule to persist the session.
While I'm not yet at the point where it's necessary, I did want to utilize System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler so that the application will live nicely on a web farm (as described by Dominick Baier here).
The problem I have is that, given the machineKey-based handling, I would expect that not only would the session be valid from server machine to machine, but should also survive application restarts. However, any time I either restart or rebuild the application, upon hitting the application in the browser, the cookie apparently becomes invalid and I get bounced to the authentication screen. Once authenticated again, everything is fine and the session remains. However, the next time the app restarts or is rebuilt, I'm forced to re-authenticate.
I'm sure this is an aspect of WIF that I'm not getting, but I just don't know where to turn from here. I'm not afraid of having to extend MachineKeySessionSecurityTokenHandler, but I'd like to make sure that I understand what's going on here before I proceed. I understand that the default SessionSecurityTokenHandler uses DPAPI in combination with some identifier from the app pool for its cryptography, so it makes sense that this would happen in that case, but the behavior in MachineKeySessionSecurityTokenHandler puzzles me. Is there still some identifier in the application that gets recreated on restart on which MachineKeySessionSecurityTokenHandler depends? Am I just missing a setting?
Here are the pertinent parts from my web.config:
<configSections>
<section name="system.identityModel"
type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
</configSections>
...
<system.identityModel>
<identityConfiguration>
<securityTokenHandlers>
<remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</securityTokenHandlers>
</identityConfiguration>
</system.identityModel>
...
<system.web>
<machineKey compatibilityMode="Framework45"
validationKey="E27893..."
decryptionKey="ABC..."
validation="SHA1" decryption="AES" />
<authentication mode="Forms">
<forms loginUrl="~/Account/Login"
timeout="10080" />
</authentication>
</system.web>
...
<system.webServer>
<modules runAllManagedModulesForAllRequests="true">
<add name="SessionAuthenticationModule"
type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</modules>
</system.webServer>
hm - if you are setting the machine key explicitly (like you seem to do) - I don't see a reason why this would not work. Maybe you are using other cookies, sessions etc that trigger the re-auth problem?
OK, this was my stupid fault. For reasons that are not pertinent here, I set the FedAuth cookie name to something non-standard (i.e. not "FedAuth"), like this:
FederatedAuthentication
.FederationConfiguration
.CookieHandler
.Name = "SomeThingNotStandard";
The problem was I was setting it like this only at the moment that I issued the token on a successful login. Well, of course everything's gonna be fine because now the in-memory configuration is looking for "SomeThingNotStandard" as the cookie name. But, on an app restart, the configuration will be back to the default, looking for "FedAuth", not "SomeThingNotStandard". This forces the re-login, which upon success, re-configures the app and then everything seems fine.
So I put the code bit above in Application_Start() and it works fine across re-builds and re-starts.
Dumb move on my part.
Edit:
I moved this to configuration
<system.identityModel.services>
<federationConfiguration>
<cookieHandler
name="SomeThingNotStandard" />
</federationConfiguration>
</system.identityModel.services>

Why would FederatedAuthentication.WSFederationAuthenticationModule be null in MVC Azure ACS Federated Authentication?

I'm trying to put together FederatedAuthentication with .NET 4.5, MVC 4, and active redirect using a custom server-side login page, using code from this tutorial, and from this code sample.
Redirecting to the LogOn method of my AccountController works fine, and the method looks like this:
public ActionResult LogOn()
{
HrdClient hrdClient = new HrdClient();
WSFederationAuthenticationModule fam = FederatedAuthentication.WSFederationAuthenticationModule; /*** Fails here because this is null **/
HrdRequest request = new HrdRequest(fam.Issuer, fam.Realm, context: Request.QueryString["ReturnUrl"]);
IEnumerable<HrdIdentityProvider> hrdIdentityProviders = hrdClient.GetHrdResponse(request);
ViewData["Providers"] = hrdIdentityProviders;
return View();
}
This fails because FederatedAuthentication.WSFederationAuthenticationModule is null.
Using VS 2012, I've run the new Identity and Access wizard (which seems to replace the old STS dialog). This has given me a folder of FederationMetadata, which appears correct, and several modifications to my Web.Config. In particular, the modules section looks like this:
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<modules runAllManagedModulesForAllRequests="true">
<add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
<add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
</modules>
And having seen SO answers 8937123 and 8926099, I've added the following as well:
<httpModules>
<add name="WSFederationAuthenticationModule" type="Microsoft.IdentityModel.Web.WSFederationAuthenticationModule, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</httpModules>
And finally my nuget packages config shows Microsoft.IdentityModel, which is correctly referenced by the MVC app:
<packages>
<package id="Microsoft.IdentityModel" version="6.1.7600.16394" targetFramework="net45" />
</packages>
I've also seen this question on social.msdn, which just seems to suggest that the STS dialog does need to be run.
Can anybody explain why FederatedAuthentication.WSFederationAuthenticationModule would be null, and what I can do to stop this happening?
I managed to fix this myself, and since there are a few unanswered questions similar to this on SO, I'll leave the question up and post my own answer.
The issue is to do with upgrading the MVC application to .NET 4.5. Much of the WIF functionality remains the same (at least on the surface), but the classes have all moved to different assemblies. I fixed my problem following the migration guidelines here: http://msdn.microsoft.com/en-us/library/jj157089.aspx
The most important thing is to remove old references to the Microsoft.IdentityModel package (v 3.5.0) and make sure they are replaced by similar references to the System.IdentityModel and System.IdentityModel.Services dlls, which should be version 4.0, and come from the GAC rather than an external package.
My steps to fix were:
Clean out all the junk I'd added to Web.Config and start again with a default MVC Config file.
Remove the Microsoft.IdentityModel package and de-reference the dll
Run the Access and Identity wizard in VS 2012
Duplicate the System.IdentityModel.Services.WSFederationAuthenticationModule reference from <system.webServer><modules> in <system.web><httpModules>
Add <authentication mode="Forms"><forms loginUrl="~/Account/LogOn" /></authentication>
Compile, test, dance little jig of delight...
And this got the original WIF3.5 / MVC3 Code Sample working under.NET 4.5

ASP MVC Route issue with dot "."

I have this route:
file{FileId}/{name}
It works perfectly unless name has a dot in it.
For example, these work:
file1/blah, file90/foo -
but it doesn't:
file1/blah.doc
All I get in this case is 404 error. Seems like it looks for the actual file blah.doc instead of use routing system.
This problem happens only in production server. I've even tried
httpRuntime relaxedUrlToFileSystemMapping="true"
but it didn't help.
Everything after the '.' is the file extension. If that extension isn't mapped to ASP.NET, it won't get handed off to the ASP.NET handler. IIS looks for a static file instead. So you need to add a handler for your case (web.config), then your route will be able to catch the request.
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<add name="FileHandlerDot" verb="GET" path="file*/*.*" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</handlers>
</validation>

MEF and Razor Views inside Class Library

I have a composite ASP .NET MVC 3 Razor application using MEF. Everything goes fine if I am to deploy plugins as DLL files and views (CSHTML) under the regular Views folder from the application. But this is not very clean and it won't be a real plugin if I don't place views as embedded resources within the DLL files (along with both controllers and models).
I've followed many articles (most of them are outdated). In fact there is one quite good one here on Stack Overflow: Controllers and Views inside a Class Library
I've also checked docs for VirtualPathProvider and I've been able to build a custom one that finds the file within the assembly and loads it perfectly (or at least gets the stream to it). For this I've followed the VirtualPathProvider documentation on MSDN.
There is also an implementation for VirtualFile but not yet for VirtualDirectory.
Here is the problem. I'm working with Razor views. I do know that they need config specs from the web.config file for Razor to build them. But if I embed them within the DLL this config is simply lost.
I wonder if that's why I keep getting the error:
The view at '~/Plugins/CRM.Web.Views.CRM.Index.cshtml' must derive
from WebViewPage, or WebViewPage.
Maybe I just need to add some code to make it work? Any ideas?
My preferred way to embed Razor Views in a Class Library is to copy them into the MVC website's Views/Areas folders with a post build event. Custom view locations can be specified if you override the ViewEngine or VirtualPathProvider.
The tricky part for me was getting intellisense to work in these View Class libraries. First, you must add a Web.Config to your View assembly. Note that you don't have to actually include it in your assembly. It only has to be in the assembly root directory (or views folder). Here is an example. Regard the important Assemblies/Compilation section.
<?xml version="1.0"?>
<configuration>
<configSections>
<sectionGroup name="system.web.webPages.razor" type="System.Web.WebPages.Razor.Configuration.RazorWebSectionGroup, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<section name="host" type="System.Web.WebPages.Razor.Configuration.HostSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
<section name="pages" type="System.Web.WebPages.Razor.Configuration.RazorPagesSection, System.Web.WebPages.Razor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" requirePermission="false" />
</sectionGroup>
</configSections>
<system.web.webPages.razor>
<host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="System.Web.Mvc" />
<add namespace="System.Web.Mvc.Ajax" />
<add namespace="System.Web.Mvc.Html" />
<add namespace="System.Web.Routing" />
</namespaces>
</pages>
</system.web.webPages.razor>
<appSettings>
<add key="webpages:Enabled" value="false" />
</appSettings>
<system.web>
<compilation targetFramework="4.0">
<assemblies>
<add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
<add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>
<httpHandlers>
<add path="*" verb="*" type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
<!--
Enabling request validation in view pages would cause validation to occur
after the input has already been processed by the controller. By default
MVC performs request validation before a controller processes the input.
To change this behavior apply the ValidateInputAttribute to a
controller or action.
-->
<pages
validateRequest="false"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false" />
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler" />
</handlers>
</system.webServer>
</configuration>
Next, you need to modify your class library's vbproj file so that all OutputPath elements point to 'bin\' instead of 'Debug\bin\' or 'Release\bin\'. This is the main difference I found between class libraries and ASP.Net web project types that can cause intellisense bugs.
If you still recieve your must inherits error, consider using #Inherits System.Web.Mvc.WebViewPage in your views. If you are not copying your views into your website project, you may be loading them from Embedded Resources using a custom ViewEngine / VirtualPathProvider. If that is the case, you definately need the Inherits so Razor knows what your view base class is unfortunately.
Good luck.
You might take a look at the following blog post.
Hossam,
The post you're talking about is what Darin has already suggested. The main down side to that approach is using the custom MvcRazorClassGenerator compiler to convert the CSHTML view files in to class files. To do so you have to set every CSHTML view in your project to Content and set the Custom Tool to MvcRazorClassGenerator.
I can't speak for LordALMMa but I did download the compiler source and gave it a shot and it doesn't exactly work the way I was hoping.
My other approach was to include the CSHTML files as Embeded Resources in the external DLL, read in the raw contents of the file and execute the view as a string (See the RazorEngine on CodeProject for an example: http://razorengine.codeplex.com/)
I didn't want to fully depend on the RazorEngine in an enterprise application because I don't know how well it is compatiable with all of the Razor syntax so I gave up on that for now.
I'm coming from a prototype I built in ASP.NET MVC 2.0 that is a multi-tennant application. On a server farm we have one instance of an application running where all clients share the same code base. In my MVC 2.0 prototype I was able to determine what "client" the request was being made for, check for a custom controller that over-rides the base (for customizations of the core code) and also check for custom views (for customizations of the core view). What this does is allow us to deploy a "plugin" per say for each client. The software detects if the client has a custom controller that matches the request as well as a custom action that matches and if it does, it uses the customized controller/action instead.
When I started migrating my prototype to MVC 3 I ran in to the same problem as LordALMMa, the error "The view at '...Index.cshtml' must derive from WebViewPage, or WebViewPage". I'll look in to placing "#inherits System.Web.Mvc.WebViewPage" on my CSHTML views and see if that gets me any closer to getting it to work.
Since I have a working MVC 2.0 prototype using MVC 3 Razor is not a top priority and I don't waste a ton of time on it. I'm sure I can port the MVC 2.0 to MVC 3.0 using the WebForms engine if we need to leverage the 4.0 Framework.
Hey I suspect you have good reasons for wanting views inside DLLs. However also consider that it is an unusual way of packaging everything into one entity.
If you are developing a plugin, these days people opt for packaging in the NUGET format, which also solves your kind of problem among other things. It has a .nupkg structure which is also one way of distributing plugins as packages and libraries.
Another solution which communities generally follow is (if they do not want something as elaborate as nuget) they code up the plugin DLLs such that, it does not use view engines like razor, instead outputs HTML all by itself using the old primitive way of Response.Write and thus become independent of cshtml files. If you still want to use cshtml - see this blog entry for precompiling those into classes.

MVCContrib Portable Area No Intellisense for ViewPage<T>

I am trying out portable areas using MVCContrib.
In general these work well and it seems to be a good way to share controllers\views between web projects.
The only problem that I'm having is that Intellisense (specifically, for the HtmlHelper) is not working in the view for strongly typed views i.e. ViewPage.
The intellisense does work however when the view is a plain 'ol System.Web.Mvc.ViewPage
A similar questions has been asked here:
MvcContrib Portable Areas View Intellisense?
But these suggestions don't seem to make any difference.
I am using MVC 2, the portable areas are in their own class library as in the MVCContrib sample code.
I'd also like to add that the MVC sample code gives me the same behaviour, if I change the sample project to make the view page strongly typed then intellisense stops working.
Are other people having the same problem ?
Does anyone know the cause and or solution ?
the web.config from my Views folder is as follows:
<?xml version="1.0"?>
<configuration>
<system.web>
<httpHandlers>
<add path="*" verb="*"
type="System.Web.HttpNotFoundHandler"/>
</httpHandlers>
<!--
Enabling request validation in view pages would cause validation to occur
after the input has already been processed by the controller. By default
MVC performs request validation before a controller processes the input.
To change this behavior apply the ValidateInputAttribute to a
controller or action.
-->
<pages
validateRequest="false"
pageParserFilterType="System.Web.Mvc.ViewTypeParserFilter, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
pageBaseType="System.Web.Mvc.ViewPage, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"
userControlBaseType="System.Web.Mvc.ViewUserControl, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35">
<controls>
<add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" namespace="System.Web.Mvc" tagPrefix="mvc" />
</controls>
</pages>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<handlers>
<remove name="BlockViewHandler"/>
<add name="BlockViewHandler" path="*" verb="*" preCondition="integratedMode" type="System.Web.HttpNotFoundHandler"/>
</handlers>
</system.webServer>
</configuration>
This was a problem with ReSharper intellisense in VS2010, ReSharper v5.0.
If I change my ReSharper options (ReSharper->Options->Intellisense->General) to use Visual Studio intellisense then it works!!

Resources