Pergunta

É possível ter uma rota ASP.NET MVC que utiliza as informações para determinar sua rota subdomínio? Por exemplo:

  • user1 .domain.com vai para um lugar
  • user2 .domain.com vai para outro?

Ou, posso fazê-lo assim ambos vão para o mesmo controlador / ação com um parâmetro username?

Foi útil?

Solução

Você pode fazê-lo através da criação de uma nova rota e adicioná-lo à coleção rotas em RegisterRoutes em sua global.asax. Abaixo está um exemplo muito simples de uma rota personalizado:

public class ExampleRoute : RouteBase
{

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var url = httpContext.Request.Headers["HOST"];
        var index = url.IndexOf(".");

        if (index < 0)
            return null;

        var subDomain = url.Substring(0, index);

        if (subDomain == "user1")
        {
            var routeData = new RouteData(this, new MvcRouteHandler());
            routeData.Values.Add("controller", "User1"); //Goes to the User1Controller class
            routeData.Values.Add("action", "Index"); //Goes to the Index action on the User1Controller

            return routeData;
        }

        if (subDomain == "user2")
        {
            var routeData = new RouteData(this, new MvcRouteHandler());
            routeData.Values.Add("controller", "User2"); //Goes to the User2Controller class
            routeData.Values.Add("action", "Index"); //Goes to the Index action on the User2Controller

            return routeData;
        }

        return null;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        //Implement your formating Url formating here
        return null;
    }
}

Outras dicas

Para capturar o subdomínio, mantendo a MVC5 padrão recursos de roteamento , use a seguinte classe SubdomainRoute derivado de Route.

Para além disso, permite que o subdomínio SubdomainRoute opcionalmente ser especificada como consulta parâmetro , fazendo sub.example.com/foo/bar e example.com/foo/bar?subdomain=sub equivalente. Isso permite que você teste antes dos subdomínios DNS são configurados. O parâmetro de consulta (quando em uso) é propagado através de novas ligações geradas por Url.Action, etc.

O parâmetro de consulta também permite depuração local com o Visual Studio 2013 sem ter que configure com netsh ou Executar como administrador . Por padrão, o IIS Express apenas se liga a localhost quando não elevado; ele não vai ligar a nomes de host sinônimo como sub.localtest.me .

class SubdomainRoute : Route
{
    public SubdomainRoute(string url) : base(url, new MvcRouteHandler()) {}

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var routeData = base.GetRouteData(httpContext);
        if (routeData == null) return null; // Only look at the subdomain if this route matches in the first place.
        string subdomain = httpContext.Request.Params["subdomain"]; // A subdomain specified as a query parameter takes precedence over the hostname.
        if (subdomain == null) {
            string host = httpContext.Request.Headers["Host"];
            int index = host.IndexOf('.');
            if (index >= 0)
                subdomain = host.Substring(0, index);
        }
        if (subdomain != null)
            routeData.Values["subdomain"] = subdomain;
        return routeData;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        object subdomainParam = requestContext.HttpContext.Request.Params["subdomain"];
        if (subdomainParam != null)
            values["subdomain"] = subdomainParam;
        return base.GetVirtualPath(requestContext, values);
    }
}

Por conveniência, chame o seguinte método MapSubdomainRoute do seu método RegisterRoutes tal como faria MapRoute planície antiga:

static void MapSubdomainRoute(this RouteCollection routes, string name, string url, object defaults = null, object constraints = null)
{
    routes.Add(name, new SubdomainRoute(url) {
        Defaults = new RouteValueDictionary(defaults),
        Constraints = new RouteValueDictionary(constraints),
        DataTokens = new RouteValueDictionary()
    });
}

Finalmente, para acessar convenientemente o subdomínio (a partir de um verdadeiro subdomínio ou um parâmetro de consulta), é útil para criar uma classe base do Controlador com esta propriedade Subdomain:

protected string Subdomain
{
    get { return (string)Request.RequestContext.RouteData.Values["subdomain"]; }
}

Este não é o meu trabalho, mas eu tive que adicioná-lo sobre esta resposta.

Aqui é uma grande solução para este problema. Maartin Balliauw escreveu o código que cria uma classe DomainRoute que pode ser usado de forma muito semelhante ao encaminhamento normal.

http: //blog.maartenballiauw. ser / post / 2009/05/20 / ASPNET-MVC-Domain-Routing.aspx

uso Amostra seria assim ...

routes.Add("DomainRoute", new DomainRoute( 
    "{customer}.example.com", // Domain with parameters 
    "{action}/{id}",    // URL with parameters 
    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults 
))

;

Para capturar o subdomínio quando usando Web API , substituir o Selector de Acção para injetar um parâmetro de consulta subdomain. Em seguida, use o parâmetro de consulta subdomínio nas ações de seus controladores assim:

public string Get(string id, string subdomain)

Esta abordagem torna a depuração conveniente, já que você pode especificar o parâmetro de consulta à mão quando se usa localhost em vez do nome do host real (veja o MVC5 padrão resposta encaminhamento para detalhes). Este é o código para Selector Ação:

class SubdomainActionSelector : IHttpActionSelector
{
    private readonly IHttpActionSelector defaultSelector;

    public SubdomainActionSelector(IHttpActionSelector defaultSelector)
    {
        this.defaultSelector = defaultSelector;
    }

    public ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor)
    {
        return defaultSelector.GetActionMapping(controllerDescriptor);
    }

    public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
    {
        var routeValues = controllerContext.Request.GetRouteData().Values;
        if (!routeValues.ContainsKey("subdomain")) {
            string host = controllerContext.Request.Headers.Host;
            int index = host.IndexOf('.');
            if (index >= 0)
                controllerContext.Request.GetRouteData().Values.Add("subdomain", host.Substring(0, index));
        }
        return defaultSelector.SelectAction(controllerContext);
    }
}

Substitua o padrão Selector Ação adicionando este para WebApiConfig.Register:

config.Services.Replace(typeof(IHttpActionSelector), new SubdomainActionSelector(config.Services.GetActionSelector()));

Sim, mas você tem que criar seu próprio manipulador de rota.

Normalmente o caminho não tem conhecimento do domínio porque o aplicativo pode ser implantado em qualquer domínio ea rota não se importaria de uma forma ou de outra. Mas no seu caso você deseja basear o controlador e ação fora do domínio, então você terá que criar uma rota personalizada que está ciente do domínio.

Eu criei biblioteca para subdomínio roteamento que você pode criar uma tal rota. Ele está trabalhando atualmente em um .NET Núcleo 1.1 e .NET Framework 4.6.1, mas será atualizado no futuro próximo. Esta é a forma como ele está trabalhando:
1) Mapa subdomínio rota em Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    var hostnames = new[] { "localhost:54575" };

    app.UseMvc(routes =>
    {
        routes.MapSubdomainRoute(
            hostnames,
            "SubdomainRoute",
            "{username}",
            "{controller}/{action}",
            new { controller = "Home", action = "Index" });
    )};

2) Controladores / HomeController.cs

public IActionResult Index(string username)
{
    //code
}

3) Que lib também permitirá que você para gerar URLs e formas. Código:

@Html.ActionLink("User home", "Index", "Home" new { username = "user1" }, null)

Irá gerar <a href="http://user1.localhost:54575/Home/Index">User home</a> URL gerada também vai depender da localização máquina e esquema.
Você também pode usar ajudantes html para BeginForm e UrlHelper. Se quiser, você também pode usar novo recurso chamado ajudantes tag (FormTagHelper, AnchorTagHelper)
Isso lib não tem qualquer documentação ainda, mas existem alguns testes e amostras projeto tão à vontade para explorá-lo.

Em ASP.NET Núcleo , o anfitrião está disponível através Request.Host.Host. Se você quiser permitir que substituindo o anfitrião através de um parâmetro de consulta, Request.Query verificação pela primeira vez.

Para causar um parâmetro de consulta hospedeiro para se propagar para a novos URLs baseados em rota, adicione este código para a configuração de rota app.UseMvc:

routes.Routes.Add(new HostPropagationRouter(routes.DefaultHandler));

E definir HostPropagationRouter assim:

/// <summary>
/// A router that propagates the request's "host" query parameter to the response.
/// </summary>
class HostPropagationRouter : IRouter
{
    readonly IRouter router;

    public HostPropagationRouter(IRouter router)
    {
        this.router = router;
    }

    public VirtualPathData GetVirtualPath(VirtualPathContext context)
    {
        if (context.HttpContext.Request.Query.TryGetValue("host", out var host))
            context.Values["host"] = host;
        return router.GetVirtualPath(context);
    }

    public Task RouteAsync(RouteContext context) => router.RouteAsync(context);
}

Depois de definir um novo manipulador de rota que iria olhar para o anfitrião passado na URL , você pode ir com a ideia de uma base Controller que está ciente do site que está sendo acessado por. Parece que este:

public abstract class SiteController : Controller {
    ISiteProvider _siteProvider;

    public SiteController() {
        _siteProvider = new SiteProvider();
    }

    public SiteController(ISiteProvider siteProvider) {
        _siteProvider = siteProvider;
    }

    protected override void Initialize(RequestContext requestContext) {
        string[] host = requestContext.HttpContext.Request.Headers["Host"].Split(':');

        _siteProvider.Initialise(host[0]);

        base.Initialize(requestContext);
    }

    protected override void OnActionExecuting(ActionExecutingContext filterContext) {
        ViewData["Site"] = Site;

        base.OnActionExecuting(filterContext);
    }

    public Site Site {
        get {
            return _siteProvider.GetCurrentSite();
        }
    }

}

ISiteProvider é uma interface simples:

public interface ISiteProvider {
    void Initialise(string host);
    Site GetCurrentSite();
}

Refiro-me de ir para a Luke Sampson Blog

Se você está olhando para dar capacidades multitenancy ao seu projeto com diferentes domínios / subdomínios para cada inquilino, você deve ter um olhar para SaasKit:

https://github.com/saaskit/saaskit

Exemplos de código pode ser visto aqui: http://benfoster.io/blog / saaskit-multi-tenancy-made-easy

Alguns exemplos usando núcleo ASP.NET: http://andrewlock.net/forking-the-pipeline-adding-tenant-specific-files-with-saaskit-in-asp-net-core/

EDIT: Se você fizer não desejar usar SaasKit em seu projeto núcleo ASP.NET você pode ter um olhar para a implementação de Maarten de domínio roteamento para MVC6: https://blog.maartenballiauw.be/post/2015/02/ 17 / domínio encaminhamento-e-resolver-corrente-inquilino-com-aspnet-mvc-6-aspnet-5.html

No entanto, essas Gists não são mantidos e necessidade de ser ajustado para trabalhar com a última versão do núcleo ASP.NET.

link direto para o código: https://gist.github.com/ maartenba / 77ca6f9cfef50efa96ec # file-domaintemplateroutebuilderextensions-cs

Poucos dias atrás eu desenvolvi um atributo que restringe os métodos ou controladores para domínios específicos.

É muito fácil de usar:

[IsDomain("localhost","example.com","www.example.com","*.t1.example.com")]
[HttpGet("RestrictedByHost")]
public IActionResult Test(){}

Você também pode aplicá-lo diretamente em um controlador.

public class IsDomainAttribute : Attribute, Microsoft.AspNetCore.Mvc.Filters.IAuthorizationFilter
{

    public IsDomainAttribute(params string[]  domains)
    {
        Domains = domains;
    }

    public string[] Domains { get; }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var host = context.HttpContext.Request.Host.Host;
        if (Domains.Contains(host))
            return;
        if (Domains.Any(d => d.EndsWith("*"))
                && Domains.Any(d => host.StartsWith(d.Substring(0, d.Length - 1))))
            return;
        if (Domains.Any(d => d.StartsWith("*"))
                && Domains.Any(d => host.EndsWith(d.Substring(1))))
            return;

        context.Result = new Microsoft.AspNetCore.Mvc.NotFoundResult();//.ChallengeResult
    }
}

Restrição: você pode não ser capaz de ter duas mesmas rotas em diferentes métodos com diferentes filtros Quero dizer o seguinte pode lançar uma exceção para a rota duplicada:

[IsDomain("test1.example.com")]
[HttpGet("/Test")]
public IActionResult Test1(){}

[IsDomain("test2.example.com")]
[HttpGet("/Test")]
public IActionResult Test2(){}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top