سؤال

هل من الممكن أن يكون هناك ASP.NET MVC الطريق الذي يستخدم فرعي المعلومات لتحديد الطريق ؟ على سبيل المثال:

  • user1.domain.com يذهب إلى مكان واحد
  • user2.domain.com يذهب إلى آخر ؟

أو يمكن أن تجعل من ذلك كل من هذه تذهب إلى نفس تحكم/العمل مع username المعلمة ؟

هل كانت مفيدة؟

المحلول

يمكنك القيام بذلك عن طريق إنشاء مسار جديد وإضافته إلى مجموعة المسارات في RegisterRoutes في ملف global.asax الخاص بك.فيما يلي مثال بسيط جدًا لمسار مخصص:

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

نصائح أخرى

ل التقاط النطاق الفرعي مع الاحتفاظ بميزات توجيه MVC5 القياسية, ، استخدم ما يلي SubdomainRoute فئة مشتقة من Route.

بالإضافة إلى ذلك، SubdomainRoute يسمح بتحديد النطاق الفرعي بشكل اختياري كـ a معلمة الاستعلام, ، تحضير sub.example.com/foo/bar و example.com/foo/bar?subdomain=sub مقابل.يتيح لك هذا الاختبار قبل تكوين نطاقات DNS الفرعية.يتم نشر معلمة الاستعلام (عند الاستخدام) من خلال الروابط الجديدة التي تم إنشاؤها بواسطة Url.Action, ، إلخ.

تتيح معلمة الاستعلام أيضًا تصحيح الأخطاء المحلية باستخدام Visual Studio 2013 دون الحاجة إلى ذلك قم بالتكوين باستخدام netsh أو قم بتشغيله كمسؤول.بشكل افتراضي، يرتبط IIS Express فقط بـ مضيف محلي عندما تكون غير مرتفعة؛لن يرتبط بأسماء المضيفين المترادفة مثل 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);
    }
}

للراحة اتصل بالرقم التالي MapSubdomainRoute الطريقة من عندك RegisterRoutes الطريقة تمامًا كما تفعل مع القديم MapRoute:

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

أخيرًا، للوصول بسهولة إلى النطاق الفرعي (إما من نطاق فرعي حقيقي أو من معلمة استعلام)، من المفيد إنشاء فئة أساسية لوحدة التحكم باستخدام هذا Subdomain ملكية:

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

هذا ليس عملي، ولكن كان علي أن أضيفه في هذه الإجابة.

هنا حل عظيم لهذه المشكلة.كتب Maartin Balliauw تعليمات برمجية تنشئ فئة DomainRoute يمكن استخدامها بشكل مشابه جدًا للتوجيه العادي.

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

استخدام العينة سيكون مثل هذا ...

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

;

لالتقاط النطاق الفرعي عند الاستخدام واجهة برمجة تطبيقات الويب, ، تجاوز محدد الإجراء لإدخال أ subdomain معلمة الاستعلام.ثم استخدم معلمة استعلام المجال الفرعي في إجراءات وحدات التحكم الخاصة بك مثل هذا:

public string Get(string id, string subdomain)

يجعل هذا الأسلوب تصحيح الأخطاء أمرًا سهلاً حيث يمكنك تحديد معلمة الاستعلام يدويًا عند الاستخدام مضيف محلي بدلاً من اسم المضيف الفعلي (راجع ملف إجابة توجيه MVC5 القياسية للتفاصيل).هذا هو رمز محدد الإجراء:

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

استبدل محدد الإجراء الافتراضي بإضافة هذا إلى WebApiConfig.Register:

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

نعم ولكن عليك إنشاء معالج المسار الخاص بك.

عادةً لا يكون المسار على علم بالمجال لأنه يمكن نشر التطبيق في أي مجال ولن يهتم المسار بطريقة أو بأخرى.لكن في حالتك، فأنت تريد إنشاء وحدة التحكم والإجراء خارج النطاق، لذلك سيتعين عليك إنشاء مسار مخصص يكون على دراية بالمجال.

صنعت مكتبة لتوجيه النطاق الفرعي والتي يمكنك إنشاء مثل هذا الطريق.وهو يعمل حاليًا مع الإصدار .NET Core 1.1 و.NET Framework 4.6.1 ولكن سيتم تحديثه في المستقبل القريب.هذه هي الطريقة التي تعمل بها:
1) قم بتعيين مسار المجال الفرعي في 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) وحدات التحكم/HomeController.cs

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

3) سيسمح لك هذا lib أيضًا بإنشاء عناوين URL والنماذج.شفرة:

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

سوف يولد <a href="http://user1.localhost:54575/Home/Index">User home</a>سيعتمد عنوان URL الذي تم إنشاؤه أيضًا على موقع المضيف الحالي والمخطط.
يمكنك أيضًا استخدام مساعدات HTML لـ BeginForm و UrlHelper.إذا أردت، يمكنك أيضًا استخدام ميزة جديدة تسمى مساعدي العلامات (FormTagHelper, AnchorTagHelper)
لا يحتوي هذا lib على أي وثائق حتى الآن، ولكن هناك بعض الاختبارات ونماذج المشروع، لذا لا تتردد في استكشافها.

في ASP.NET الأساسية, ، المضيف متاح عبر Request.Host.Host.إذا كنت تريد السماح بتجاوز المضيف عبر معلمة استعلام، فتحقق أولاً Request.Query.

لكي يتم نشر معلمة استعلام مضيف إلى عناوين URL الجديدة المستندة إلى المسار، أضف هذا الرمز إلى ملف app.UseMvc تكوين المسار:

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

وتحديد 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);
}

بعد تحديد معالج المسار الجديد الذي سيلقي نظرة على المضيف الذي تم تمريره في عنوان URL, ، يمكنك اتباع فكرة وحدة التحكم الأساسية التي تكون على علم بالموقع الذي يتم الوصول إليه من أجله.تبدو هكذا:

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 هي واجهة بسيطة:

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

أشير عليك بالذهاب إلى مدونة لوك سامبسون

إذا كنت تتطلع إلى منح إمكانات MultiTenancy لمشروعك بنطاقات/نطاقات فرعية مختلفة لكل مستأجر، فيجب عليك إلقاء نظرة على SaasKit:

https://github.com/saaskit/saaskit

يمكن رؤية أمثلة التعليمات البرمجية هنا: http://benfoster.io/blog/saaskit-multi-tenancy-made-easy

بعض الأمثلة باستخدام ASP.NET الأساسية: http://andrewlock.net/forking-the-pipeline-adding-tenant-special-files-with-saaskit-in-asp-net-core/

يحرر:إذا كنت لا ترغب في استخدام SaasKit في مشروع ASP.NET الأساسي الخاص بك، فيمكنك إلقاء نظرة على تنفيذ Maarten لتوجيه المجال لـ MVC6: https://blog.maartenballiauw.be/post/2015/02/17/domain-routing-and-resolve-current-tenant-with-aspnet-mvc-6-aspnet-5.html

ومع ذلك، لا تتم صيانة هذه العناصر وتحتاج إلى تعديلها لتعمل مع الإصدار الأحدث من ASP.NET الأساسي.

رابط مباشر للكود: https://Gist.github.com/maartenba/77ca6f9cfef50efa96ec#file-domaintemplateroutebuilderextensions-cs

في الأشهر القليلة الماضية لقد وضعت السمة التي تقيد أساليب أو وحدات تحكم نطاقات محددة.

فمن السهل جدا استخدام:

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

كما يمكنك تطبيقه مباشرة على وحدة تحكم.

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

قيود:قد لا تكون قادرة على الحصول على اثنين من نفس طرق على طرق مختلفة مع مرشحات مختلفة أعني التالية قد رمي استثناء مكررة الطريق:

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

[IsDomain("test2.example.com")]
[HttpGet("/Test")]
public IActionResult Test2(){}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top