I have multiple controllers with the same name in different namespaces. To explain clearly what I want to do, I first briefly show part of my code.
I created a ViewLocationExpander class. Its main function is to automatically find the view corresponding to the controller in the Views directory through the namespace.
public class NamespaceViewLocationExpander : IViewLocationExpander
{
private readonly string _placeholder;
private readonly IEnumerable<string> _viewLocations;
public NamespaceViewLocationExpander(IEnumerable<string> viewLocations, string placeholder)
{
_placeholder = placeholder;
_viewLocations = viewLocations;
}
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
List<string> namespaceViewLocation = new List<string>();
var actionDescriptor = context.ActionContext.ActionDescriptor as ControllerActionDescriptor;
// controller namespace
var controllerNamespace = actionDescriptor?.ControllerTypeInfo.Namespace;
// assembly namespace
var assemblyName = actionDescriptor?.ControllerTypeInfo.Assembly.GetName().Name;
if (controllerNamespace is null || assemblyName is null)
return viewLocations;
if (!controllerNamespace.StartsWith(assemblyName += ".Controllers.") || controllerNamespace == assemblyName)
return viewLocations;
var placeReplace = controllerNamespace[assemblyName.Length..].Replace(".", "/");
foreach (var viewLocation in _viewLocations)
{
namespaceViewLocation.Add(viewLocation.Replace(_placeholder, placeReplace));
}
return viewLocations.Union(namespaceViewLocation);
}
// see https://stackoverflow.com/questions/36802661/what-is-iviewlocationexpander-populatevalues-for-in-asp-net-core-mvc
public void PopulateValues(ViewLocationExpanderContext context)
{
context.Values["FindViewByNamespace"] = typeof(NamespaceViewLocationExpander).FullName;
}
}
then configure it
builder.Services.Configure<RazorViewEngineOptions>(options =>
{
options.ViewLocationExpanders.Add(new NamespaceViewLocationExpander(new List<string> { @"/Views/{namespace}/{1}/{0}.cshtml" }, "{namespace}"));
});
So far, the controller will find the corresponding view as follows
a.b.Controllers.FooController.Bar => ~/Views/Foo/Bar.cshtml
a.b.Controllers.c.d.FooController.Bar => ~/Views/c/d/Foo/Bar.cshtml
Everything works as I envisioned.
Until I ran into a problem when trying to use the asp-controller
TagHelper
If I add tag <a asp-controller="Foo">...
in "~/Views/c/d/Foo/Bar.cshtml", since the controller has the same name, it's impossible to tell which one is used, in practice it points to itself, what if I want it to point to a.b.Controllers.FooController
?
I tried extending the AnchorTagHelper
class and adding Tag asp-controller-namespace
, but there are few relevant documents and I don’t know how to implement it.
My English is not good, I translated it through machine, I hope I made it clear.If there is a way to achieve it, please tell me. Thanks!