2009-12-30 11 views
3

ProblèmeMigration ASP.NET existant vers MVC 2 (RC): événements non mise à feu HttpApplication, principal utilisateur est null

Je suis en train de prendre une application Web ASP.NET existante et migrer manuellement vers utiliser MVC 2 (Je cours actuellement le RC). J'ai suivi plusieurs étapes (je vais énumérer dans un instant) et a semblé l'avoir fonctionné, mais alors j'ai noté que je ne peux pas placer le AuthorizeAttribute parce que l'utilisateur est nul sur le contrôleur. Ensuite, j'ai remarqué que lorsque je navigue vers une action, aucun des événements de cycle de vie habituels de HttpApplication n'est levé (comme BeginRequest, etc.). Je pense que c'est probablement lié à pourquoi le principal de l'utilisateur est null. L'hôte Web est une instance locale IIS7 (sur mon poste de travail Vista). J'ai créé une toute nouvelle application Web MVC 2 à utiliser comme référence lors de la migration. Il fonctionne très bien, en levant des événements d'application et en remplissant l'utilisateur principal comme je m'y attendais.

Si vous avez envie de vous punir, lisez la suite pour obtenir tous les détails (au meilleur de mes capacités) ci-dessous.


étapes de migration

  1. Vérifiez que le pool d'applications pour le répertoire de l'application est .NET 2.0 et
  2. intégré
  3. System.Web.Abstractions Référencés (de v.3.5.0.0), système. Web.routing (v3.5.0.0) et System.Web.Mvc (v2.0.0.0) dans mon projet Web. Maintenant, j'ai ajouté System.Web.Mvc en tant que référence locale pour faciliter l'intégration et le déploiement.
  4. a modifié le csproj pour permettre la bonté d'ajouter dans MVC VS (Voir this article)
  5. Ajouté les Contrôleurs et Vues répertoires du projet, ajouté dans le /Views/web.config de mon exemple d'application MVC.
  6. modifié mon web.config (NOTE: J'ai d'autres conneries dans les modules et les gestionnaires, mais je cachèrent que par souci de simplicité et de sécurité ... mais ceux-ci peuvent très bien faire partie du problème):

La section compilation:

<compilation defaultLanguage="c#" debug="true"> 
     <assemblies> 
     <add assembly="System.Core, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> 
     <add assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
     <add assembly="System.Web.Abstractions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
     <add assembly="System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
     <add assembly="System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
     <add assembly="System.Data.DataSetExtensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> 
     <add assembly="System.Xml.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> 
     <add assembly="System.Data.Linq, Version=3.5.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/> 
     </assemblies> 
    </compilation> 

La section pages:

<pages enableEventValidation="false" 
     pageBaseType="MyAssembly.ThemedBasePage"> 
    <controls> 
    <add tagPrefix="asp" namespace="System.Web.UI" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 
    <add tagPrefix="asp" namespace="System.Web.UI.WebControls" assembly="System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 
    </controls> 

    <namespaces> 
    <add namespace="System.Web.Mvc"/> 
    <add namespace="System.Web.Mvc.Ajax"/> 
    <add namespace="System.Web.Mvc.Html"/> 
    <add namespace="System.Web.Routing"/> 
    <add namespace="System.Linq"/> 
    <add namespace="System.Collections.Generic"/> 
    </namespaces> 
</pages> 

La section system.webServer/modules (souvenez-vous, IIS7 intégré):

<modules> 
    <remove name="ScriptModule" /> 
    <remove name="UrlRoutingModule" /> 
    <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 
    <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 

</modules> 

La section system.webServer/handlers:

<handlers> 
     <remove name="WebServiceHandlerFactory-Integrated"/> 
     <remove name="ScriptHandlerFactory"/> 
     <remove name="ScriptHandlerFactoryAppServices"/> 
     <remove name="ScriptResource"/> 
     <remove name="MvcHttpHandler"/> 
     <remove name="UrlRoutingHandler"/> 
     <add name="ScriptHandlerFactory" verb="*" path="*.asmx" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 
     <add name="ScriptHandlerFactoryAppServices" verb="*" path="*_AppService.axd" preCondition="integratedMode" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 
     <add name="ScriptResource" preCondition="integratedMode" verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" /> 
     <add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
     <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" /> 
    </handlers> 
  1. Mis à jour mon global.asax d'enregistrer des itinéraires, et des choses qui ignorent interférer avec mes affaires de l'héritage:

    private static void RegisterRoutes(RouteCollection routes) 
    { 
        // place any routes here you need to ignore, whether they 
        // be legacy or legitimate resources. 
        routes.IgnoreRoute(""); // i currently have functionality at "/", and this route frees up the root to be used by my Default.aspx 
        routes.IgnoreRoute("{webForms}.aspx/{*pathInfo}"); 
        routes.IgnoreRoute("{webServices}.asmx/{*pathInfo}"); 
        routes.IgnoreRoute("ajaxpro/{*pathInfo}"); 
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); 
    
        routes.MapRoute(
        "Default", // Route name 
        "{controller}/{action}/{id}", // URL with parameters 
        new {controller = "Home", action = "Index", id = ""} // Parameter defaults 
    ); 
    } 
    
    
    
    protected void Application_Start() 
    { 
        // legacy crap here 
    
        AreaRegistration.RegisterAllAreas();  
        RegisterRoutes(RouteTable.Routes); 
    } 
    

Informations additionnelles

J'utilise également la dernière version de Autofac (v1.4.5.676) et utiliser leurs gestionnaires d'intégration Web. J'ai vérifié dans les deux sens, avec tous les trucs autofact complètement supprimés/désactivés et avec tout mis en place comme je le veux; aucun effet sur la question de toute façon.

J'ai également essayé ceci avec et sans mes arrangements spécialisés super-doux IgnoreRoute. Aucun effet.

En outre, je tiens à préciser que les routes semblent fonctionner, je suis envoyé à mes contrôleurs et actions correctement, j'ai juste un principal Null à HttpContext.Current.User et il semble ne pas totalement soulever des événements de cycle de vie d'application. Si je n'étais pas obligé, vous savez, d'obtenir le principal actuel ou de faire une quelconque autorisation, je n'aurais jamais su que quelque chose n'allait pas;)

Et oui, les pages ASPX normales fonctionnent correctement et les événements du cycle de vie de l'application sont soulevé normalement.

Voici un exemple d'un contrôleur de test simple, je fait cela échoue:

[Authorize] 
    public class FartsController : Controller 
    { 
     // 
     // GET: /Farts/ 
     public ActionResult Index() 
     { 
      return View(); 
     } 

    } 

qui donne l'exception suivante:..

[NullReferenceException: Object reference not set to an instance of an object.] 
    System.Web.Mvc.AuthorizeAttribute.AuthorizeCore(HttpContextBase httpContext) +48 
    System.Web.Mvc.AuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext) +35 
    System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor) +103 
    System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName) +316 
    System.Web.Mvc.Controller.ExecuteCore() +104 
    System.Web.Mvc.ControllerBase.Execute(RequestContext requestContext) +36 
    System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute(RequestContext requestContext) +7 
    System.Web.Mvc.<>c__DisplayClass8.<BeginProcessRequest>b__4() +34 
    System.Web.Mvc.Async.<>c__DisplayClass1.<MakeVoidDelegate>b__0() +21 
    System.Web.Mvc.Async.<>c__DisplayClass8`1.<BeginSynchronous>b__7(IAsyncResult _) +12 
    System.Web.Mvc.Async.WrappedAsyncResult`1.End() +53 
    System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +43 
    System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +7 
    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +8678910 
    System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155 

Ce :(succions Merci d'avoir lu mon histoire courte

Répondre

1

MIS À JOUR D'accord, je pense que la question est un échec dans ma compréhension de la façon dont fonctionne vraiment MVC (qui n'a pas été clair jusqu'à ce que je reculai et avec un esprit frais comparé les différences entre les configs Web ASP.NET et MVC).

La raison de mon problème est parce que le réglage suivant est nécessaire pour les applications MVC de fonctionner correctement en mode intégré (la partie importante est runAllManagedModulesForAllRequests="true"):

<system.webServer> 
    <validation validateIntegratedModeConfiguration="false"/> 
    <modules runAllManagedModulesForAllRequests="true"> 
     <remove name="ScriptModule"/> 
     <remove name="UrlRoutingModule"/> 
     <add name="ScriptModule" preCondition="managedHandler" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
     <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 

     <!-- omitted for clarify --> 
    </modules> 
    <handlers> 
     <!-- omitted for clarity --> 
     <add name="MvcHttpHandler" preCondition="integratedMode" verb="*" path="*.mvc" type="System.Web.Mvc.MvcHttpHandler, System.Web.Mvc, Version=2.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/> 
     <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler, System.Web, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/> 
    </handlers> 
</system.webServer> 

Lorsque cela provoque un problème pour moi serait le fait que mon application ASP.NET utilise une règle d'autorisation par défaut refuser l'accès aux utilisateurs non authentifiés:

<system.web> 
    <authorization> 
     <deny users="?"/> 
    </authorization> 
    </system.web> 

Alors MVC ne pas encourager cette pratique, mais le rat elle en utilisant AuthorizeAttribute ou un autre filtre. Jusqu'à ce que je mette tout mon code existant sur MVC (ce qui prendra du temps), je vais devoir trouver une solution astucieuse pour garder l'autorisation de style ASP.NET en place pour expulser les requêtes non authentifiées (peut-être un HttpModule personnalisé?) pour les ressources sécurisées (qui pour nous est tout sauf les images, javascript, css, static html, et les pages de connexion/déconnexion), et supprimez ce qui précède du web.config.

En outre, mon application, étant à l'origine juste ASP.NET, supposait que Application_BeginRequest (et les goûts) ne seraient que des demandes de ressources significatives, comme les pages ASPX, ASMX, ASHX et AXD. Donc, j'ai besoin d'ajuster les événements d'application pour arrêter tout traitement gourmand en ressources (contrôles de sécurité qui touchent la BD, etc.) pour les ressources statiques dont je ne me soucie pas (encore une fois, des choses comme des images, etc.).

RÉSUMÉ

runAllManagedModulesForAllRequests="true" est requis pour MVC en mode intégré. Si votre application ASP.NET utilise massivement l'autorisation basée sur l'emplacement et/ou effectue beaucoup de traitement sur les événements de cycle de vie de la demande, vous aurez besoin de plus de travail pour que MVC fonctionne avec vos formulaires ASP.NET .

+0

Merci beaucoup! il suffit de passer un temps loooong pas repérer le manquant runAllManagedModulesForAllRequests = "true"! – Whisk

0

Cela peut ou ne peut pas aider: Je viens de terminer l'examen du code Nerd Dinner et ils ont couvert ce sujet spécifiquement dans le domaine des tests unitaires Essayez de parcourir ce http://www.wrox.com/WileyCDA/Section/id-321793.html et défilement presque vers le bas où ils couvrent les tests unitaires de l'échantillon. Ils ont une fausse magie qui fait fonctionner leur exemple de contrôleur de compte pour vous permettre de fournir un faux ID utilisateur. Ça pourrait marcher pour toi.