ASP.NET MVC IgnoreRoute() by domain
Asked Answered
F

3

9

UPDATE: rewording for conciseness...

With an ASP.NET MVC project, is it possible to have web.config rewrite rules take precedence over MVC's RegisterRoutes() call OR can IgnoreRoute be called for just a specific domain?

I have a single MVC application that accepts traffic over multiple domains (mydomain.com and otherdomain.com), the application serves different content based on the requested host (i.e. it's multi-tenant).

I have a URL rewrite (a reverse proxy) configured in web.config which should only apply to a specific host:

<rule name="Proxy" stopProcessing="true">
        <match url="proxy/(.*)" />
        <action type="Rewrite" url="http://proxydomain.com/{R:1}" />
        <conditions logicalGrouping="MatchAll">
            <add input="{HTTP_HOST}" pattern="^(mydomain\.com|www\.mydomain\.com)$" />
        </conditions>
        <serverVariables>
            <set name="HTTP_X_UNPROXIED_URL" value="http://proxydomain.com/{R:1}" />
            <set name="HTTP_X_ORIGINAL_ACCEPT_ENCODING" value="{HTTP_ACCEPT_ENCODING}" />
            <set name="HTTP_X_ORIGINAL_HOST" value="{HTTP_HOST}" />
            <set name="HTTP_ACCEPT_ENCODING" value="" />
        </serverVariables>
    </rule>

However, an MVC application will seemingly only honor web.config configured routes if they're ignored from the application's RegisterRoutes() method with:

routes.IgnoreRoute("proxy");

Which then, unfortunately, applies the ignore to both domains. Suggestions greatly appreciated...

Fumarole answered 14/2, 2018 at 18:15 Comment(2)
Probably silly but would it be possible to ignore the route only for one tenant by enabling it as a feature on that tenant?Pegg
check here #9048053Faveolate
C
3

can IgnoreRoute be called for just a specific domain?

Yes. However, since domains are completely ignored by .NET routing by default, you will need to customize routing to make IgnoreRoute specific to domains.

While it is possible to subclass RouteBase to do this, the simplest solution is to make a custom route constraint and use it to control the domains that a specific route will match. Route constraints can be used with the existing MapRoute, MapPageRoute and IgnoreRoute extension methods, so this is the least invasive fix to an existing configuration.

DomainConstraint

    public class DomainConstraint : IRouteConstraint
    {
        private readonly string[] domains;

        public DomainConstraint(params string[] domains)
        {
            this.domains = domains ?? throw new ArgumentNullException(nameof(domains));
        }

        public bool Match(HttpContextBase httpContext, Route route, string parameterName, 
            RouteValueDictionary values, RouteDirection routeDirection)
        {
            string domain =
#if DEBUG
                // A domain specified as a query parameter takes precedence 
                // over the hostname (in debug compile only).
                // This allows for testing without configuring IIS with a 
                // static IP or editing the local hosts file.
                httpContext.Request.QueryString["domain"]; 
#else
                null;
#endif
            if (string.IsNullOrEmpty(domain))
                domain = httpContext.Request.Headers["HOST"];

            return domains.Contains(domain);
        }
    }

Note that for testing purposes, the above class accepts a query string parameter when the application is compiled in debug mode. This allows you to use a URL like

http://localhost:63432/Category/Cars?domain=mydomain.com

to test the constraint locally without having to configure the local web server and hosts file. This debugging feature is left out of the release build to prevent possible bugs (vulnerabilities) in the production application.

Usage

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        // This ignores Category/Cars for www.mydomain.com and mydomain.com
        routes.IgnoreRoute("Category/Cars", 
            new { _ = new DomainConstraint("www.mydomain.com", "mydomain.com") });

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

NOTE: There is an overload that accepts a constraints parameter on all of the built-in route extensions, including IgnoreRoute and Area routes.

Reference: https://stackoverflow.com/a/48602769

Corelation answered 22/2, 2018 at 14:5 Comment(2)
I like this pluggable approachCrabbed
This should be marked as the answer, it worked great for me.Clinometer
V
0

Instead of IgnoreRoute, please use Ignore

routes.Ignore('url pattern here')
Vc answered 20/2, 2018 at 12:55 Comment(0)
T
0

is it possible to have web.config rewrite rules take precedence over MVC's RegisterRoutes()?

Yes. Note that there are some Differences Between IIS URL Rewriting and ASP.NET Routing:

  1. URL rewriting is used to manipulate URL paths before the request is handled by the Web server. The URL rewriting module does not know which handler will eventually process the rewritten URL. In addition, the actual request handler might not know that the URL has been rewritten.
  2. ASP.NET routing is used to dispatch a request to a handler based on the requested URL path. As opposed to URL rewriting, the routing module knows about the handlers and selects the handler that should generate a response for the requested URL. You can think of ASP.NET routing as an advanced handler-mapping mechanism.

Can IgnoreRoute be called for just a specific domain?

According to MSDN, you can use the version which accepts url as parameter. But for the same domain! Considering that There are some drawbacks when you work with multiple domains in ASP.NET MVC application:

  • All routing logic is hard-coded: if you want to add a new possible route, you’ll have to code for it.
  • The ASP.NET MVC infrastructure working based on VirtualPathData class. Only tokens in the URL’s path are used for routing.

if you'd like to have a single MVC app that handles multiple domains, and routes each of them differently, you need to handle with out of the box MVC routing. It is, however, possible using a custom site route inheriting from RouteBase.

Now let's discuss the following:

routes.IgnoreRoute("proxy"); Which applies the ignore to both domains.

I believe the rule does not work perfectly, since the processing reaches to ASP.NET routing! possible reason could be found in ServiceModel tag inside web.config. Add the serviceHostingEnvironment code like below:

<system.serviceModel>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true" />
</system.serviceModel>

This will allow routes to be passed through IIS to handle.

Also change <match url="proxy/(.*)" /> to <match url="^proxy/(.*)" /> (with an extra ^) which is prevalent.

Terra answered 22/2, 2018 at 9:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.