We have a deployed ASP.NET MVC 3 application, and have discovered a bug in one of the controller actions. For political reasons, we are not allowed to replace any existing code without a big process that takes weeks of headache. I.e. we can't rebuild the MVC application.
We are allowed to deploy a new assembly, containing a new controller with just the one fixed action.
Is there a way to add to or edit the routes of the MVC application to map the new controller action?
I am considering subclassing my MVC application in the hotfix DLL and updating global.asax to reference the subclassed application.
public class HotfixApplication : RealApplication
{
public override void Init()
{
base.Init();
var badRoute = RouteTable.Routes.Where(...);
var badRoute.FixIt();
}
}
And it would route to a controller action in the hotfix DLL.
Does this sound plausible? Safe?
Try this approach based on ControllerFactory, HttpModule:
Steps:
1# Create a new 'Class Library' Project. Add reference to your asp.net mvc web application project. Also add reference to 'System.Web', 'System.Web.Mvc', 'Microsoft.Web.Infrastructure.dll' assemblies.
2# Create a new Controller class inherited from the controller (TargetController) that has the bug:
public class FixedContorller : TargetController
{
[FixedActionSelector]
[ActionName("Index")]
public ActionResult FixedIndex()
{
ViewBag.Title = "I'm Fixed...";
return View();
}
}
The [FixedActionSelectorAttribute] is ActionSelector attribute, used to resolve the action name.
public class FixedActionSelector : ActionMethodSelectorAttribute
{
public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo)
{
return true;
}
}
3# Define a custom ControllerFactory, that will create the fixed controller instead of the target controller:
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# Now define a HttpModule, that will set the above controller-factory on application init. The httpModule will register itself programmatically, no need to register in 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));
}
}
}
Compile the project and copy the .dll in the bin folder of your web application.
Hopes this helps...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With