I have a base controller that contains several actions that I would like to use attribute routing on, and not have to override these methods in the controllers that inherit from the base.
As of .NET MVC 5.2 this should be possible according to this: http://www.asp.net/mvc/overview/releases/whats-new-in-aspnet-mvc-52
The example provided shows how to use a class level attribute, but I would like to Implment it at the action level. Has anyone successfuly implemented inheritance of attributes on the action level? I see another answer Attribute routing and inheritance claims this is possible in with web API controllers, but can it be done using the standard MVC controller?
[InheritedRoute("attributerouting/{controller}/{action=Index}/{id?}")]
public abstract class BaseController : Controller
{
}
public class BlogController : BaseController
{
public string Index()
{
return "Hello from blog!";
}
}
public class StoreController : BaseController
{
public string Index()
{
return "Hello from store!";
}
}
[AttributeUsage(AttributeTargets.Class, Inherited=true, AllowMultiple=true)]
public class InheritedRouteAttribute : Attribute, IDirectRouteFactory
{
public InheritedRouteAttribute(string template)
{
Template=template;
}
public string Name { get; set; }
public int Order { get; set; }
public string Template { get; private set; }
public new RouteEntry CreateRoute(DirectRouteFactoryContext context)
{
// context.Actions will always contain at least one action - and all of the
// actions will always belong to the same controller.
var controllerDescriptor=context.Actions.First().ControllerDescriptor;
var template=Template.Replace("{controller}",
controllerDescriptor.ControllerName);
IDirectRouteBuilder builder=context.CreateBuilder(template);
builder.Name=Name;
builder.Order=Order;
return builder.Build();
}
}
// Custom direct route provider which looks for route attributes of type
// InheritedRouteAttribute and also supports attribute route inheritance.
public class InheritedDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetControllerRouteFactories(ControllerDescriptor controllerDescriptor)
{
return controllerDescriptor
.GetCustomAttributes(typeof(InheritedRouteAttribute), inherit: true)
.Cast<IDirectRouteFactory>()
.ToArray();
}
}
I think I have the action level working with the following code:
public class InheritedDirectRouteProvider : DefaultDirectRouteProvider
{
protected override IReadOnlyList<IDirectRouteFactory>
GetActionRouteFactories(ActionDescriptor actionDescriptor)
{
return actionDescriptor.GetCustomAttributes(typeof(IDirectRouteFactory), inherit: true).Cast<IDirectRouteFactory>().ToArray();
}
}
and call:
routes.MapMvcAttributeRoutes(new InheritedDirectRouteProvider());
this lets me inherit the controller and its routines from an abstract controller, simplified example:
// Inherited class needs to define [RoutePrefix("childPrefix")]
public abstract class ChildBaseController<TChildEntity> : BaseController where TChildEntity : ChildEntity
{
public ChildBaseController(IUnitOfWork DAL) : base(DAL) { }
protected abstract GenericChildRepository<TChildEntity> ChildRepository { get; }
protected abstract string[] GetCreateBindFields();
protected abstract string[] GetEditBindFields();
[Route("{valueId}")]
public ActionResult Index(int valueId)
{
ViewBag.ValueId = valueId;
return View(ChildRepository.Get().Where(cr => cr.ValueId == valueId));
}
... bunch more CRUD actions with [Route(...)] ...
}
inherited class:
namespace Web.Frontend.Controllers
{
[RoutePrefix("Fields")]
public class FieldsController : ChildBaseController<Field>
{
public FieldsController(IUnitOfWork DAL) : base(DAL) { }
protected override GenericChildRepository<Field> ChildRepository
{
get
{
return DAL.Fields;
}
}
protected override string[] GetCreateBindFields()
{
return new string[] { ... };
}
protected override string[] GetEditBindFields()
{
return new string[] { ... };
}
}
}