Asp.net mvc 在运行时替换控制器操作

Asp.net mvc 在运行时替换控制器操作,asp.net-mvc,asp.net-mvc-3,Asp.net Mvc,Asp.net Mvc 3,我们已经部署了一个ASP.NET MVC 3应用程序,并且在其中一个控制器操作中发现了一个错误。出于政治原因,我们不允许在没有一个耗时数周的大型流程的情况下替换任何现有代码。也就是说,我们无法重建MVC应用程序 public class HotfixApplication : RealApplication { public override void Init() { base.Init(); var badRoute = RouteTable

我们已经部署了一个ASP.NET MVC 3应用程序,并且在其中一个控制器操作中发现了一个错误。出于政治原因,我们不允许在没有一个耗时数周的大型流程的情况下替换任何现有代码。也就是说,我们无法重建MVC应用程序

public class HotfixApplication : RealApplication
{
    public override void Init()
    {
        base.Init();
        var badRoute =  RouteTable.Routes.Where(...);
        var badRoute.FixIt();
    }
}
我们可以部署一个新的程序集,其中包含一个新的控制器,只需执行一个固定的操作

是否有方法添加或编辑MVC应用程序的路由以映射新的控制器操作


我正在考虑在修补程序DLL中对我的MVC应用程序进行子类化,并更新global.asax以引用子类化的应用程序

public class HotfixApplication : RealApplication
{
    public override void Init()
    {
        base.Init();
        var badRoute =  RouteTable.Routes.Where(...);
        var badRoute.FixIt();
    }
}
它将路由到修补程序DLL中的控制器操作


这听起来可信吗?安全?

如果我错了,请有人纠正我,但我非常确定,除非您的项目设计为动态加载程序集,否则您将无法在没有某种部署的情况下修改运行时


也就是说,您可以利用ISS重定向或添加到Web.config文件中的HttpModule,将对违规控制器的请求指向您选择的新位置。

尝试基于ControllerFactory的这种方法,HttpModule:

步骤:

1#创建一个新的“类库”项目。添加对asp.net mvc web应用程序项目的引用。还添加对“System.Web”、“System.Web.Mvc”、“Microsoft.Web.Infrastructure.dll”程序集的引用

2#创建一个新的控制器类,该类继承自具有错误的控制器(TargetController):

public class FixedContorller : TargetController
{

    [FixedActionSelector]
    [ActionName("Index")]
    public ActionResult FixedIndex()
    {
        ViewBag.Title = "I'm Fixed...";
        return View();
    }
}
[FixedActionSelectorAttribute]是ActionSelector属性,用于解析操作名称

    public class FixedActionSelector : ActionMethodSelectorAttribute
    {
    public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
    {
        return true;
    }
}
3#定义自定义控制器工厂,该工厂将创建固定控制器而不是目标控制器:

public class MyControllerFactory : DefaultControllerFactory
{
    private static string targetControllerName = "Target";
    private static string targetActionName = "Index";

    protected override Type GetControllerType(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        var action = requestContext.RouteData.Values["action"].ToString();

        if (targetControllerName.Equals(controllerName, StringComparison.InvariantCultureIgnoreCase) &&
            targetActionName.Equals(action, StringComparison.InvariantCultureIgnoreCase))
        {
            return typeof(FixedContorller);
        }

        return base.GetControllerType(requestContext, controllerName);
    }
}
4#现在定义一个HttpModule,它将在应用程序初始化时设置上述控制器工厂。httpModule将以编程方式注册自身,无需在web.config中注册

using System;
using System.Web;
using System.Web.Mvc;

[assembly: PreApplicationStartMethod(typeof(YourApp.Patch.FixerModule), "Register")]
namespace YourApp.Patch
{
    public class FixerModule : IHttpModule
    {
        private static bool isStarted = false;
        private static object locker = new object();

        public void Dispose()
        {
        }

        public void Init(HttpApplication context)
        {
            if (!isStarted)
            {
                lock (locker)
                {
                    if (!isStarted)
                    {
                        ControllerBuilder.Current.SetControllerFactory(typeof(MyControllerFactory));
                        isStarted = true;
                    }
                }
            }
        }

        public static void Register()
        {
            Microsoft.Web.Infrastructure.DynamicModuleHelper.DynamicModuleUtility.RegisterModule(typeof(FixerModule));
        }
    }
}
编译项目并将.dll复制到web应用程序的bin文件夹中

public class HotfixApplication : RealApplication
{
    public override void Init()
    {
        base.Init();
        var badRoute =  RouteTable.Routes.Where(...);
        var badRoute.FixIt();
    }
}

希望这有帮助……

是的,但这需要在旧路由之前将新路由添加到路由集合中,或者如果您使用类似UrlRewriter.net的东西,您可以尝试重写路由。否则,您需要咬紧牙关,部署修复程序。向你的生意人解释情况。这是一个网站,不是客户端应用程序。此外,你必须告诉控制器工厂在哪里可以找到控制器。相关:你能摆脱疯狂的政治限制吗?如果发现安全漏洞会发生什么?ASP.NET似乎会加载bin目录中的任何程序集。控制器工厂可以选择延迟绑定的控制器;我只是在努力更新路由表。你能发布一个github解决方案/示例,并在其中运行吗?