基于不同域的Razor页面路由

时间:2019-06-19 23:03:10

标签: asp.net-core razor

我正在尝试设置一个本地化的ASP.NET Core Razor Web应用程序,以在多个域上使用。我正在进行本地化,每个域使用一种不同的语言。但是现在我想让.com域接受路由参数,以使URL路径决定要显示的语言。

类似的东西:

  • www.mysite.pt-无自定义路由-www.mysite.pt/PageA可以使用葡萄牙语进行本地化。
  • www.mysite.com-自定义路由-www.mysite.com/cn/PageA转到了在美国本地化的PageA。但是www.mysite.com/PageA应该返回404,因为该域的每个页面都需要使用country参数。

对于MVC,这可以通过将MapRoute与自定义IRouteConstraint结合使用以按域进行过滤来实现。 但是,对于Razor页面,我只能看到遵循约定并添加从IPageRouteModelConvention派生的类的选项。

但是我在IPageRouteModelConvention方法论上看不到使用IRouteConstraint的方法。 有办法吗?

1 个答案:

答案 0 :(得分:0)

并不是最好的解决方案...但是可以解决:

在ConfigureServices上添加了一个自定义约定,该约定仅使用带有两个国家/地区代码US和CA的国家/地区参数:

  options.Conventions.Add(new CountryTemplateRouteModelConvention());

该类为:

public class CountryTemplateRouteModelConvention : IPageRouteModelConvention
{
    public void Apply(PageRouteModel model)
    {

        var selectorCount = model.Selectors.Count;
        for (var i = 0; i < selectorCount; i++)
        {
            var selector = model.Selectors[i];
            // selector.AttributeRouteModel.SuppressLinkGeneration = false;

            //we are not adding the selector, but replacing the existing one
            model.Selectors.Add(new SelectorModel
            {

                AttributeRouteModel = new AttributeRouteModel
                {
                    Order = -1,

                    Template = AttributeRouteModel.CombineTemplates(@"{country:length(2):regex(^(us|ca)$)}", selector.AttributeRouteModel.Template),
                }
            });
        }
    }
}

然后,在配置UseMvc之前,我使用了两种重写规则:

var options = new RewriteOptions();
options.Add(new CountryBasedOnDomainRewriteRule(domains: GetDomainsWhereCountryComesFromDomain(Configuration)));
options.Add(new CountryBasedOnPathRewriteRule(domains: GetDomainsWhereCountryComesFromPath(Configuration)));
app.UseRewriter(options);

方法GetDomainsWhereCountryComesFromDomain和GetDomainsWhereCountryComesFromPath只是从应用程序设置中读取我要使用一种语言的域以及希望从URL路径获得该语言的域。

现在,有两个IRule类:

public class CountryBasedOnPathRewriteRule : IRule
{
    private readonly string[] domains;

    public CountryBasedOnPathRewriteRule(string[] domains)
    {
        this.domains = domains;
    }

    public void ApplyRule(RewriteContext context)
    {
        string hostname = context.HttpContext.Request.Host.Host.ToLower();
        if (!domains.Contains(hostname)) return;

        //only traffic that has the country on the path is valid. examples:
        // www.mysite.com/ -> www.mysite.com/US/
        // www.mysite.com/Cart -> www.mysite.com/US/Cart

        var path = context.HttpContext.Request.Path.ToString().ToLower();

        /* let's exclude the error page, as method UseExceptionHandler doesn't accept the country parameter */
        if (path == "/" || path == "/error")
        {
            //redirect to language default

            var response = context.HttpContext.Response;
            response.StatusCode = (int)HttpStatusCode.Moved;
            response.Headers[HeaderNames.Location] = "/us/"; //default language/country
            context.Result = RuleResult.EndResponse;
        }

        string pathFirst = path.Split('/')?[1];

        if (pathFirst.Length != 2) /* US and CA country parameter is already enforced by the routing */
        {
            var response = context.HttpContext.Response;
            response.StatusCode = (int)HttpStatusCode.NotFound;
            context.Result = RuleResult.EndResponse;
        }
    }
}

public class CountryBasedOnDomainRewriteRule : IRule
{
    private readonly string[] domains;

    public CountryBasedOnDomainRewriteRule(string[] domains)
    {
        this.domains = domains;
    }

    public void ApplyRule(RewriteContext context)
    {
        string hostname = context.HttpContext.Request.Host.Host.ToLower();
        if (!domains.Contains(hostname)) return;

        var path = context.HttpContext.Request.Path.ToString().ToLower();

        string pathFirst = path.Split('/')?[1];

        if (pathFirst.Length == 2) //we are trying to use www.mysite.co.uk/us which is not allowed 
        {
            var response = context.HttpContext.Response;
            response.StatusCode = (int)HttpStatusCode.NotFound;
            context.Result = RuleResult.EndResponse;
        }
    }
}

就是这样。