Can AnchorTagHelper specify different controllers with the same name?

刘琦 0 Reputation points
2023-09-21T00:59:44.6833333+00:00

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!

ASP.NET Core
ASP.NET Core
A set of technologies in the .NET Framework for building web applications and XML web services.
4,560 questions
{count} votes

1 answer

Sort by: Most helpful
  1. Ping Ni-MSFT 4,335 Reputation points Microsoft Vendor
    2023-10-06T04:04:18.9533333+00:00

    Hi @刘琦,

    You could custom tag helper like below:

    [HtmlTargetElement("namespacelink")]
    public class NamespaceLinkTagHelper : TagHelper
    {
        [HtmlAttributeName("namespace")]
        public string Namespace { get; set; }
        [HtmlAttributeName("asp-controller")]
        public string Controller { get; set; }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "a";
            var slash = Namespace == "" ? "" : "/";
            output.Attributes.Add("href", "/"+Namespace+ slash+Controller);
        }
    }
    

    Then import your custom Tag Helper in the _ViewImports.cshtml file:

    @addTagHelper *, YourNamespace
    

    Use the custom tag helper in razor view:

    <namespacelink namespace="" asp-controller="Blog">All Blogs</namespacelink>
    <namespacelink namespace="Dash" asp-controller="Blog" >Blog</namespacelink>
    <namespacelink namespace="Dash/Details" asp-controller="Blog">Blog Details</namespacelink>
    

    If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Rena

    0 comments No comments

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.