user2771704
user2771704

Reputation: 6202

Call particular filter for particular Razor Pages Route?

I have 2 domains (.com and .ru) and 2 URLs like site.com/about-us and site.ru/o-nas which should be redirected to the same page. The site uses Razor Pages.

Also, the particular URL should be available in the appropriate domain. For example:

How to call only 1 for particular URL, is it possible? Thank you, my current code is below.

public static class DomainFilters
{
    public static IPageApplicationModelConvention DomainEng(
        this PageConventionCollection con, string pageName, string route = "")
    {
        return con.AddPageApplicationModelConvention(pageName, model =>
        {
            model.Filters.Add(new EnglishActionFilter(route));
        });
    }
    public static IPageApplicationModelConvention DomainRussian(
        this PageConventionCollection con, string pageName, string route = "")
    {
        return con.AddPageApplicationModelConvention(pageName, model =>
        {
            model.Filters.Add(new RussianActionFilter(route));
        });
    }
}

public class EnglishActionFilter : IResultFilter
{
    public void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.HttpContext.Request.Host.ToString().Contains(".ru"))
        {
            context.Result = new NotFoundResult();
        }
    }

    public void OnResultExecuted(ResultExecutedContext context) { }
}

public class RussianActionFilter : IResultFilter
{
    public void OnResultExecuting(ResultExecutingContext context)
    {
        if (context.HttpContext.Request.Host.ToString().Contains(".com"))
        {
            context.Result = new NotFoundResult();
        }
    }

    public void OnResultExecuted(ResultExecutedContext context) { }
}

And finally ConfigureServices method from Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc()
        .AddRazorPagesOptions(options =>
        {
            options.Conventions.DomainEng("/AboutUs", "about-us");
            options.Conventions.DomainRussian("/AboutUs", "o-nas");
        })
}

Upvotes: 2

Views: 587

Answers (1)

Artem
Artem

Reputation: 2314

Consider implementation of a custom FilterFactory:

public class LanguageFilterFactory : Attribute, IFilterFactory
{
    public bool IsReusable => false;

    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        var context = serviceProvider.GetService<IHttpContextAccessor>();

        if (context.HttpContext.Request.Host.ToString().Contains(".com"))
        {
            return new EnglishActionFilter();
        }

        return new RussianActionFilter();
    }
}

This factory will create either an English or Russian filter (depending on the domain). That's all about its responsibilities. The rest goes to Filters themselves (you'll need to change a code inside the filters to make them validate the page locator):

public class RussianActionFilter : IResultFilter
{
    public void OnResultExecuting(ResultExecutingContext context)
    {
        // you may want to play with RouteData in order to make this check more elegant   
        if (context.HttpContext.Request.Path.Value.Contains("About"))
        {
            context.Result = new NotFoundResult();
        }
    }
}

The filter factory is applied in the same way as other filters:

[LanguageFilterFactory]
public class IndexModel : PageModel

The Startup.cs file update:

.AddMvcOptions(options =>
{
   options.Filters.Add<LanguageFilterFactory>();
});

Upvotes: 1

Related Questions