I have a ASP.NET Web API (.NET 4) application which has a few controllers. We will run several instances of the Web API application on IIS with one difference. Only certain controllers will be available under certain IIS instances. What I was thinking is to disable/unload the controllers that are not applicable to an instance when the instance starts up.
Anyone got some information that could guide me in the right direction on this?
You can put your own custom IHttpControllerActivator
in by decorating the DefaultHttpControllerActivator. Inside just check for a setting and only create the controller if allowed.
When you return null from the Create method the user will receive 404 Not Found message.
My example shows a value in App Settings (App.Config or Web.Config) being checked but obviously this could any other environment aware condition.
public class YourCustomControllerActivator : IHttpControllerActivator
{
private readonly IHttpControllerActivator _default = new DefaultHttpControllerActivator();
public YourCustomControllerActivator()
{
}
public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor,
Type controllerType)
{
if (ConfigurationManager.AppSettings["MySetting"] == "Off")
{
//Or get clever and look for attributes on the controller in controllerDescriptor.GetCustomAttributes<>();
//Or use the contoller name controllerDescriptor.ControllerName
//This example uses the type
if (controllerType == typeof (MyController) ||
controllerType == typeof (EtcController))
{
return null;
}
}
return _default.Create(request, controllerDescriptor, controllerType);
}
}
You can switch your activator in like so:
GlobalConfiguration.Configuration.Services.Replace(typeof(IHttpControllerActivator), new YourCustomControllerActivator());
Update
It has been a while since I looked at this question but if I was to tackle it today I would alter the approach slightly and use a custom IHttpControllerSelector
. This is called before the activator and makes for a slightly more efficient place to enable and disable controllers... (although the other approach does work). You should be able to decorate or inherit from DefaultHttpControllerSelector
.
Rather than unloading the controllers, I think I'd create a custom Authorize attribute that looked at the instance information in deciding to grant authorization.
You would add the following to each controller at the class level, or you could also add this to individual controller actions:
[ControllerAuthorize (AuthorizedUserSources = new[] { "IISInstance1","IISInstance2","..." })]
Here's the code for the Attribute:
public class ControllerAuthorize : AuthorizeAttribute
{
public ControllerAuthorize()
{
UnauthorizedAccessMessage = "You do not have the required access to view this content.";
}
//Property to allow array instead of single string.
private string[] _authorizedSources;
public string UnauthorizedAccessMessage { get; set; }
public string[] AuthorizedSources
{
get { return _authorizedSources ?? new string[0]; }
set { _authorizedSources = value; }
}
// return true if the IIS instance ID matches any of the AllowedSources.
protected override bool AuthorizeCore(HttpContextBase httpContext)
{
if (httpContext == null)
throw new ArgumentNullException("httpContext");
//If no sources are supplied then return true, assuming none means any.
if (!AuthorizedSources.Any())
return true;
return AuthorizedSources.Any(ut => ut == httpContext.ApplicationInstance.Request.ServerVariables["INSTANCE_ID"]);
}
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