サブドメイン情報を使用してルートを決定するASP.NET MVCルートを持つことは可能ですか?例えば:
または、これらの両方がusername
パラメーターを使用して同じコントローラー/アクションに送られるようにすることはできますか?
それを行うには、新しいルートを作成し、global.asaxのRegisterRoutesのルートコレクションに追加します。以下は、カスタムルートの非常に単純な例です。
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
を使用すると、オプションでクエリパラメーターとしてサブドメインを指定できるため、sub.example.com/foo/bar
とexample.com/foo/bar?subdomain=sub
が同等になります。これにより、DNSサブドメインを構成する前にテストできます。クエリパラメータ(使用中)は、Url.Action
などによって生成された新しいリンクを介して伝播されます。
クエリパラメーターは、 netshで構成するか、管理者として実行する を必要とせずに、Visual Studio 2013でのローカルデバッグも有効にします。デフォルトでは、IIS Expressは、昇格されていない場合にのみlocalhostにバインドします。 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);
}
}
便宜上、古い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
プロパティを使用してController基本クラスを作成すると役立ちます。
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
))
;
Web APIを使用しているときにサブドメインをキャプチャするには、Action Selectorをオーバーライドしてsubdomain
クエリパラメータを挿入します。次に、コントローラーのアクションで次のようなサブドメインクエリパラメーターを使用します。
public string Get(string id, string subdomain)
このアプローチにより、実際のホスト名の代わりにlocalhostを使用するときにクエリパラメーターを手動で指定できるため、デバッグが便利になります( 標準のMVC5ルーティング応答 詳細)。これは、Action Selectorのコードです。
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
に追加して、デフォルトのAction Selectorを置き換えます。
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)Controllers/HomeController.cs
public IActionResult Index(string username)
{
//code
}
3)そのライブラリでは、URLとフォームを生成することもできます。コード:
@Html.ActionLink("User home", "Index", "Home" new { username = "user1" }, null)
<a href="http://user1.localhost:54575/Home/Index">User home</a>
を生成します生成されたURLは、現在のホストの場所とスキーマにも依存します。BeginForm
およびUrlHelper
のhtmlヘルパーも使用できます。必要に応じて、タグヘルパー(FormTagHelper
、AnchorTagHelper
)という新しい機能も使用できます。
このlibにはまだドキュメントがありませんが、いくつかのテストおよびサンプルプロジェクトがありますので、自由に探索してください。
はい。ただし、独自のルートハンドラを作成する必要があります。
通常、ルートはドメインを認識しません。これは、アプリケーションを任意のドメインにデプロイでき、ルートが何らかの形で気にしないためです。しかし、あなたの場合、コントローラーとアクションのベースをドメインから外したいので、ドメインを認識するカスタムルートを作成する必要があります。
ASP.NET Coreでは、ホストは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();
}
Luke Sampson Blog にアクセスすることをお勧めします
テナントごとに異なるドメイン/サブドメインを使用してプロジェクトに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-specific-files-with-saaskit-in-asp-net-core/
編集:ASP.NETコアプロジェクトでSaasKitを使用したくない場合は、MVC6のドメインルーティングのMaartenの実装を確認できます。 https://blog.maartenballiauw.be/post/2015/02 /17/domain-routing-and-resolving-current-tenant-with-aspnet-mvc-6-aspnet-5.html
ただし、これらのGistsは維持されておらず、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
}
}
制限:異なるフィルターを使用した異なるメソッドで2つの同じルートを使用できない場合があります。つまり、重複したルートに対して次の例外がスローされる場合があります。
[IsDomain("test1.example.com")]
[HttpGet("/Test")]
public IActionResult Test1(){}
[IsDomain("test2.example.com")]
[HttpGet("/Test")]
public IActionResult Test2(){}