Bir alt etki alanına dayalı bir ASP.NET MVC yolu yapmak mümkün mü?


235

Rotasını belirlemek için alt alan bilgisini kullanan bir ASP.NET MVC yoluna sahip olmak mümkün müdür? Örneğin:

  • kullanici1 .etkialanı.com tek bir yere gider
  • kullanici2 .etkialanı.com diğerine gidiyor mu?

Veya, her ikisinin de bir usernameparametre ile aynı denetleyiciye / eyleme geçmesini sağlayabilir miyim ?


Çok kiracılı uygulamalar için benzer bir şey uyguladım, ancak özel bir Route sınıfı yerine soyut bir temel Denetleyici kullanarak. Blog yazım burada .
Luke Sampson

6
Bu yaklaşımı göz önünde bulundurduğunuzdan emin olun: http://blog.tonywilliams.me.uk/asp-net-mvc-2-routing-subdomains-to-areas Çok taraflılığı tanıtmak için diğer yanıtlardan daha iyi buldum çünkü MVC alanları kiracıya özgü denetleyicileri ve görünümleri organize bir şekilde tanıtmanın iyi bir yoludur.
trebormf

2
@trebormf - Sanırım bir cevap olarak eklemelisin, bu benim çözümüm için temel olarak kullandım.
Shagglez

@Shagglez - Teşekkürler. Bu bir cevaptı, ancak bir moderatör anlayamadığım nedenlerle bir yoruma çevirdi.
trebormf

5
Tony gibi kırılmıştı. İşte benim için çalışan biri: blog.tonywilliams.me.uk/…
Ronnie Overby

Yanıtlar:


168

Bunu, yeni bir rota oluşturarak ve global.asax'ınızdaki RegisterRoutes'da rota koleksiyonuna ekleyerek yapabilirsiniz. Aşağıda, özel bir Rotanın çok basit bir örneği verilmiştir:

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;
    }
}

1
Ayrıntılı örnek için teşekkürler, ancak Global.asax .Add yürütmek nasıl takip etmiyorum.
justSteve

4
Ben yol SubdomainRoute çağırdı ve böyle ilk yol olarak ekledi: route.Add (new SubdomainRoute ());
Jeff Handley

6
Bu yaklaşım olası alt alan adlarının bir listesini sabit olarak kodlamayı gerektiriyor mu?
Maxim V.Pavlov

2
Hayır, alt alan adının belirli bir kullanıcı için olmasını beklediğiniz veya başka bir şey olacağını düşündüğünüz "alt alan adı" adı verilen bir veritabanı alanı ekleyebilirsiniz.
Ryan Hayes

1
Herkes bunun web formlarının bir sürümünü önerebilir mi?
MatthewT

52

İçin standart MVC5 yönlendirme özelliklerini korurken alt alan yakalama aşağıdaki kullanmak SubdomainRoutetüretilmiş sınıfı Route.

Ayrıca, SubdomainRoutealt etki alanının isteğe bağlı olarak sorgu parametresi , yapma sub.example.com/foo/barve example.com/foo/bar?subdomain=subeşdeğeri olarak belirtilmesine izin verir . Bu, DNS alt etki alanları yapılandırılmadan önce test etmenizi sağlar. Query parametresi (kullanımdayken) Url.Action, vb. Tarafından oluşturulan yeni bağlantılar aracılığıyla yayılır .

Query parametresi , netsh ile yapılandırmaya veya Yönetici olarak çalıştırmaya gerek kalmadan Visual Studio 2013 ile yerel hata ayıklamayı da etkinleştirir . Varsayılan olarak, IIS Express yerel ana bilgisayara yalnızca yükseltilmediğinde bağlanır ; sub.localtest.me gibi eş anlamlı ana bilgisayar adlarına bağlanmaz .

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);
    }
}

Kolaylık sağlamak için, tıpkı eskisi gibi yönteminizden aşağıdaki MapSubdomainRouteyöntemi çağırın :RegisterRoutesMapRoute

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()
    });
}

Son olarak, alt etki alanına (gerçek bir alt etki alanından veya sorgu parametresinden) rahatça erişmek için, bu Subdomainözelliğe sahip bir Denetleyici temel sınıfı oluşturmak yardımcı olur :

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

1
Alt alan adını her zaman bir rota değeri olarak kullanılabilir hale getirmek için kodu güncelledim. Bu, alt alana erişimi kolaylaştırır.
Edward Brey

Bunu severim. Çok basit ve projem için fazlasıyla yeterli.
SoonDead

Bu harika bir cevap. Bunun rota nitelikleriyle çalışmasının bir yolu var mı? Ben "subdomain.domain.com/portal/register" gibi yollar için bu iş yapmaya çalışıyorum ve öznitelikleri kullanarak bunu kolaylaştırır.
perfect_element

@perfect_element - Özellik yolları, kural tabanlı yollar gibi genişletilemez. Böyle bir şey yapmanın tek yolu kendi öznitelik yönlendirme sisteminizi oluşturmak olacaktır.
NightOwl888

23

Bu benim işim değil, ama bu cevaba eklemek zorunda kaldım.

İşte bu soruna harika bir çözüm. Maartin Balliauw, normal yönlendirmeye çok benzer şekilde kullanılabilen bir DomainRoute sınıfı oluşturan kod yazdı.

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

Örnek kullanım şöyle olurdu ...

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

;


5
Bu çözümle ilgili bir sorun var. Diyelim ki alt alanları farklı kullanıcılar olarak işlemek istiyorsunuz: route.Add ("SD", yeni DomainRoute ("user} .localhost", "", yeni {controller = "Home", action = "IndexForUser", user = "u1 "})); Ana sayfayı da önbelleğe alır. Bunun nedeni üretilen regex'tir. Bunu düzeltmek için DomainRoute.cs içindeki CreateRegex yönteminin bir kopyasını oluşturabilir, CreateDomainRegex olarak adlandırabilir, bu satırdaki * işaretini +: source = source.Replace ("}", @ "> ([a- z-A-Z, 0-9 _] *)) "); ve GetRouteData yönteminde domain regx için bu yeni yöntemi kullanın: domainRegex = CreateDomainRegex (Domain);
Görkem Pacaci

Neden bu kodu çalıştıramıyorum bilmiyorum ... Sadece SERVER NOT FOUNDhata alıyorum ... kod benim için çalışmıyor demektir ... başka bir yapılandırma veya başka bir şey mi ayarlıyorsunuz ?!
Dr TJ


1
@IDisposable MvcApplication.DnsSuffix nedir?
HaBo

Web.config ... adresindeki temel DNS etki alanını açıklıyoruz. Tipik değer .example.org
IDisposable

4

Web API'sını kullanırken alt etki alanını yakalamak için , bir subdomainsorgu parametresi enjekte etmek üzere Eylem Seçici'yi geçersiz kılın . Ardından, denetleyicilerinizin eylemlerinde aşağıdaki gibi alt alan sorgusu parametresini kullanın:

public string Get(string id, string subdomain)

Bu ana bilgisayar adı yerine localhost kullanırken sorgu parametresini elle belirtebileceğiniz için hata ayıklamayı kolaylaştırır (ayrıntılar için standart MVC5 yönlendirme yanıtına bakın). Eylem Seçici kodu:

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);
    }
}

Varsayılan Eylem Seçici'yi aşağıdakilere ekleyerek değiştirin WebApiConfig.Register:

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

Rota verilerinin web API denetleyicisinde görünmediği ve denetleyicinin içindeki Request.GetRouteData'yı inceleyen sorunları olan herkes değer göstermiyor mu?
Alan Macdonald

3

Evet, ancak kendi rota işleyicinizi oluşturmanız gerekir.

Uygulama herhangi bir etki alanına dağıtılabileceğinden ve yol şu veya bu şekilde ilgilenmediğinden, yol genellikle etki alanının farkında değildir. Ancak sizin durumunuzda, denetleyiciyi ve eylemi etki alanına dayandırmak istersiniz, bu nedenle etki alanının farkında olan özel bir rota oluşturmanız gerekir.


3

Alt alan yönlendirmesi için böyle bir rota oluşturabileceğiniz bir kitaplık oluşturdum . Şu anda bir .NET Core 1.1 ve .NET Framework 4.6.1 için çalışıyor, ancak yakın zamanda güncellenecek. Şu şekilde çalışır:
1) Startup.cs içindeki alt alan yolunu eşleme

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) Kontrolörler / HomeController.cs

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

3) Bu lib aynı zamanda URL'ler ve formlar oluşturmanıza da izin verecektir. Kod:

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

Üretecektir <a href="http://user1.localhost:54575/Home/Index">User home</a> ayrıca geçerli konak yeri ve şema bağlıdır Oluşturulan URL.
Html yardımcılarını BeginFormve için de kullanabilirsiniz UrlHelper. İsterseniz tag helpers ( FormTagHelper, AnchorTagHelper) adlı yeni özelliği de kullanabilirsiniz.
Bu lib'in henüz bir belgesi yok, ancak bazı testler ve örnekler projesi var.


2

In ASP.NET Çekirdek , ev sahibi üzerinden ulaşılabilir Request.Host.Host. Bir sorgu parametresi aracılığıyla ana makinenin geçersiz kılınmasına izin vermek istiyorsanız, önce kontrol edin Request.Query.

Bir ana bilgisayar sorgu parametresinin yeni rota tabanlı URL'lere yayılmasına neden olmak için bu kodu app.UseMvcrota yapılandırmasına ekleyin :

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

Ve tanımla HostPropagationRouter :

/// <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);
}

1

URL'ye iletilen ana bilgisayara bakacak yeni bir Rota işleyicisi tanımladıktan sonra , erişildiği Sitenin farkında olan bir temel Denetleyici fikri ile gidebilirsiniz. Şöyle görünüyor:

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 basit bir arayüzdür:

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

Seni Luke Sampson Blog'a yönlendiriyorum


1

Her kiracı için farklı etki alanları / alt etki alanlarıyla projenize MultiTenancy yetenekleri sağlamayı düşünüyorsanız, SaasKit'e göz atmalısınız:

https://github.com/saaskit/saaskit

Kod örnekleri burada görülebilir: http://benfoster.io/blog/saaskit-multi-tenancy-made-easy

ASP.NET çekirdeğini kullanan bazı örnekler: http://andrewlock.net/forking-the-pipeline-adding-tenant-specific-files-with-saaskit-in-asp-net-core/

DÜZENLEME: Sa.Kit'i ASP.NET çekirdek projenizde kullanmak istemiyorsanız Maarten'in MVC6 için etki alanı yönlendirmesi uygulamasını inceleyebilirsiniz: https://blog.maartenballiauw.be/post/2015/02/17/domain -yönlendirme-ve-ayırıcı akım-kiracı-ile-aspnet-mVC-6-aspnet-5.html

Ancak bu Gists korunmaz ve ASP.NET çekirdeğinin en son sürümü ile çalışmak için ince ayar yapılması gerekir.

Koda doğrudan bağlantı: https://gist.github.com/maartenba/77ca6f9cfef50efa96ec#file-domaintemplateroutebuilderextensions-cs


Multitenancy aramıyorum - ama ipucu için teşekkürler!
Dan Esparza

0

Birkaç ay önce yöntemleri veya denetleyicileri belirli alanlarla kısıtlayan bir özellik geliştirdim.

Kullanımı oldukça kolaydır:

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

Ayrıca doğrudan bir denetleyiciye de uygulayabilirsiniz.

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
    }
}

Kısıtlama: Farklı filtrelerle farklı yöntemlerde iki aynı rotaya sahip olamayabilirsiniz, yani aşağıdakiler yinelenen rota için bir istisna atabilir:

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

[IsDomain("test2.example.com")]
[HttpGet("/Test")]
public IActionResult Test2(){}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.