Как добавить слаг ко всем ссылкам на основной сайт asp.net?

Мне нужно иметь возможность контролировать ссылки, генерируемые моим Url.Content("~") позвоните, чтобы иметь возможность принять Slug в начале ссылки. В основном URL-адрес хостинга будет находиться за балансировщиком нагрузки и может находиться на корневом уровне или за более дружественным URL-адресом...

В качестве примера: сайт настроен для работы с http://localhost:5001/, поэтому Url.Content("~/scripts/site.js") будет генерировать "/scripts/site.js"

Это нормально, если браузер напрямую переходит по этому URL-адресу или даже по псевдониму, например www.mysite.com.

Но я хочу иметь возможность размещать сайт под www.mysite.com/Slug (думаю, сертификаты и тому подобное)...

теперь сгенерированная моя ссылка идет на www.mysite.com/scripts.site.js, которая разрешается до 404.

В идеале, слаг может быть настроен на заказ IUrlHelperили даже обычай LinkGenerator, но я не могу ввести их и перезаписать текущие.

Я пробовал:

services.AddScoped<IUrlHelper>(x =>
            {
                var actionContext = x.GetService<IActionContextAccessor>().ActionContext;
                return new MyCustomUrlHelper(actionContext);
            });

но не смог сделать это. Когда я попытался отладить, я заметил, что если вы вызываете ту же команду в контроллере, вы получаете экземпляр Microsoft.AspNetCore.Mvc.Routing.EndpointRoutingUrlHelper вместо.

Есть ли способ изменить это без создания пользовательского помощника (потому что в некоторых областях это будет отсутствовать и отладка почти не сможет найти неправильно используемого помощника)

3 ответа

Решение

Переплет IUrlHelper напрямую не имеет никакого эффекта, поскольку MVC внутренне разрешает экземпляр, используя фабрику. Чтобы получить экземпляр собственного настраиваемого помощника по URL в ваших контроллерах и представлениях бритвы, вам необходимо предоставить настраиваемую реализацию IUrlHelperFactory в вашем классе запуска.

Следующие фрагменты кода позволяют вам украсить исходный URL-помощник своими собственными функциями:

В вашем Startup класс, вам нужно добавить пользовательскую реализацию для IUrlHelperFactory с синглтоном после AddMvc:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddSingleton<IUrlHelperFactory, CustomUrlHelperFactory>();
}

И пользовательская реализация может выглядеть так:

public class CustomUrlHelper : IUrlHelper
{
    private IUrlHelper _originalUrlHelper;

    public ActionContext ActionContext { get; private set; }

    public CustomUrlHelper(ActionContext actionContext, IUrlHelper originalUrlHelper)
    {
        this.ActionContext = actionContext;
        this._originalUrlHelper = originalUrlHelper;
    }

    public string Action(UrlActionContext urlActionContext)
    {
        return _originalUrlHelper.Action(urlActionContext);
    }

    public string Content(string contentPath)
    {
        return _originalUrlHelper.Content(contentPath);
    }

    public bool IsLocalUrl(string url)
    {
        return _originalUrlHelper.IsLocalUrl(url);
    }

    public string Link(string routeName, object values)
    {
        return _originalUrlHelper.Link(routeName, values);
    }

    public string RouteUrl(UrlRouteContext routeContext)
    {
        return _originalUrlHelper.RouteUrl(routeContext);
    }
}

public class CustomUrlHelperFactory : IUrlHelperFactory
{
    public IUrlHelper GetUrlHelper(ActionContext context)
    {
        var originalUrlHelperFactory = new UrlHelperFactory();
        var originalUrlHelper = originalUrlHelperFactory.GetUrlHelper(context);
        return new CustomUrlHelper(context, originalUrlHelper);
    }
}

IUrlHelper не является инъекционным по умолчанию.

Вам придется немного изменить свой код startup.cs, как описано в этом блоге.

Вы должны будете сначала зарегистрировать IActionContextAccessor.

Затем с помощью UrlHelperFactory вы можете внедрить свою пользовательскую реализацию, как показано ниже:

services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddScoped<IUrlHelper>(x => {
    var actionContext = x.GetRequiredService<IActionContextAccessor>().ActionContext;
    var factory = x.GetRequiredService<IUrlHelperFactory>();
    return factory.GetUrlHelper(actionContext);
});

И то и другое IActionContextAccessor а также IUrlHelperFactory жить в Microsoft.AspNetCore.Mvc.Core пакет.

Если вы используете Microsoft.AspNetCore.All metapackage вы уже должны ссылаться на это.

Это должно помочь вам решить вашу проблему.

Можете ли вы не просто использовать некоторую гибкость в своем решении с помощью конкатенации строк, например:

public string SlugUrl(string slug, string url, bool tilde = false)
{
    if (tilde) then
    {
        return Url.Content("~" + slug + url);
    }
    else
    {
        return Url.Content(slug + url);
    }
}

[...]

string slug1 = "www.mysite.com";
string slug2 = "www.mysite.com/Slug";
string trailUrl = "/scripts/site.js";
string result1 = SomeClass.SlugUrl(slug1, trailUrl);
string result2 = SomeClass.SlugUrl(slug2, trailUrl);
string result3 = SomeClass.SlugUrl(slug1, trailUrl, true);
string result4 = SomeClass.SlugUrl(slug2, trailUrl, true);

так далее...

Другие вопросы по тегам