3

问题

我正在尝试采用现有的 ASP.NET Web 应用程序并手动将其迁移到使用 MVC 2(我目前正在运行 RC)。我遵循了几个步骤(稍后会列出)并且似乎可以正常工作,但后来我注意到我无法设置,AuthorizeAttribute因为控制器上的 User 为 null。然后我注意到,当我导航到一个操作时,没有引发 HttpApplication 的常规生命周期事件(例如 BeginRequest 等)。我认为这可能与用户主体为空的原因有关。Web 主机是本地 IIS7 实例(在我的 Vista 工作站上)。

我创建了一个全新的 MVC 2 Web 应用程序,在迁移时用作参考。它运行得很好,引发了应用程序事件并按照我的预期填充了用户主体。

如果您想惩罚自己,请继续阅读下面的详细信息(尽我所能)。


迁移步骤

  1. 确保应用程序目录的应用程序池是 .NET 2.0 和集成
  2. 在我的 Web 项目中引用了 System.Web.Abstractions (v.3.5.0.0)、System.Web.routing (v3.5.0.0) 和 System.Web.Mvc (v2.0.0.0)。现在,我添加了 System.Web.Mvc 作为本地引用,以便更轻松地进行集成和部署。
  3. 修改了 csproj 以启用 MVC VS 插件优点(请参阅本文
  4. 在项目中添加了 Controllers 和 Views 目录,从我的示例 MVC 应用程序中添加到 /Views/web.config 中。
  5. 修改了我的 web.config (注意:我在模块和处理程序中有其他废话,但为了简单和安全起见,我隐藏了......但这些很可能是问题的一部分):

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>

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>

system.webServer/modules部分(记住,IIS7 集成)

<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>

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. 更新了我的 global.asax 以注册路由,并忽略会干扰我的遗留内容的内容:

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

附加信息

我还使用 Autofac (v1.4.5.676) 的最新版本并利用他们的 Web 集成处理程序。我已经检查了两种方式,所有自动事实的东西都完全删除/禁用了,一切都按照我想要的方式进行了设置;无论哪种方式,对这个问题都没有影响。

我也试过这个,有没有我专门的超甜 IgnoreRoute 设置。没有效果。

另外,我想明确一点,路由似乎确实有效,我被正确发送到我的控制器和操作,我在 HttpContext.Current.User 处只有一个 Null 主体,它似乎完全没有提高任何应用程序生命周期事件。如果我不必,你知道,得到现任校长或做任何讨厌的授权,我永远不会知道有什么问题;)

是的,常规 ASPX 页面正常工作,应用程序生命周期事件正常引发。

这是我制作的一个失败的简单测试控制器的示例:

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

    }

产生以下异常:

[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

这很糟糕:(。感谢您阅读我的短篇小说。

4

2 回答 2

1

已更新 好吧,我认为这个问题是我对 MVC 真正工作原理的理解失败(直到我回过头来并以全新的思维比较了 ASP.NET 和 MVC Web 配置之间的差异之前,我还不清楚这一点)。

我的问题的原因是因为MVC应用程序需要以下设置才能在集成模式下正常运行(重要部分是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>

这对我来说是个问题,因为我的 ASP.NET 应用程序使用默认授权规则拒绝未经身份验证的用户访问:

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

而 MVC 不鼓励这种做法,而是使用AuthorizeAttribute或其他一些过滤器。

在我将所有现有代码移至 MVC 之前(这将需要相当长的时间),我将不得不想出一个聪明的解决方案来保持 ASP.NET 风格的授权到位以推出未经身份验证的请求(可能是自定义HttpModule?) 用于安全资源(对我们来说是除图像、javascript、css、静态 html 和登录/注销页面之外的所有资源),并从 web.config 中删除上述内容。

此外,我的应用程序最初只是 ASP.NET,假设 Application_BeginRequest(和类似的)只是重要的资源请求,如 ASPX、ASMX、ASHX 和 AXD 页面。因此,我需要调整任何应用程序事件以停止对我不关心的静态资源(再次,图像等)的任何资源密集型处理(命中数据库的安全检查等)。

概括

runAllManagedModulesForAllRequests="true"在集成模式下 MVC是必需的。如果您的 ASP.NET 应用程序大量使用基于位置的授权,和/或对请求生命周期事件进行大量处理,那么您将需要做一些额外的工作来让 MVC 与您的 ASP.NET 表单一起工作.

于 2009-12-30T22:48:35.550 回答
0

这可能有帮助,也可能没有帮助:我刚刚完成了对 Nerd Dinner 代码的审查,他们在单元测试领域专门讨论了这个主题。尝试浏览这个http://www.wrox.com/WileyCDA/Section/id-321793.html并滚动到几乎覆盖示例单元测试的底部。他们有一些虚假的魔法,可以让他们的示例帐户控制器工作,让您提供一个虚假的用户 ID。可能对你有用。

于 2009-12-30T21:56:36.963 回答