ASP.NET MVCでユーザー定義のサブドメインを実装する方法

以下の例では、ユーザーが独自に設定できるサブドメインをASP.NET MVCで実現するためのカスタムルーティングクラスを作成します。
まず、カスタムルーティングクラスを作成します。

public class CustomSubdomainRoute : Route
{
    private Regex subdomainRegex;
    private Regex urlRegex;

    public string SubdomainPattern { get; set; }

    public CustomSubdomainRoute(string subdomainPattern, string urlPattern, RouteValueDictionary defaults)
        : base(urlPattern, defaults, new MvcRouteHandler())
    {
        SubdomainPattern = subdomainPattern;
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        subdomainRegex = CreateRegex(SubdomainPattern);
        urlRegex = CreateRegex(Url);

        string requestHost = httpContext.Request.Headers["host"];
        if (string.IsNullOrEmpty(requestHost))
        {
            requestHost = httpContext.Request.Url.Host;
        }
        else if (requestHost.Contains(":"))
        {
            requestHost = requestHost.Split(':')[0];
        }

        string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;

        Match hostMatch = subdomainRegex.Match(requestHost);
        Match pathMatch = urlRegex.Match(requestPath);

        if (hostMatch.Success && pathMatch.Success)
        {
            var routeData = new RouteData(this, RouteHandler);

            if (Defaults != null)
            {
                foreach (var item in Defaults)
                {
                    routeData.Values[item.Key] = item.Value;
                }
            }

            for (int i = 1; i < hostMatch.Groups.Count; i++)
            {
                Group group = hostMatch.Groups[i];
                if (group.Success)
                {
                    string key = subdomainRegex.GroupNameFromNumber(i);
                    if (!string.IsNullOrEmpty(key) && !char.IsDigit(key[0]))
                    {
                        routeData.Values[key] = group.Value;
                    }
                }
            }

            for (int i = 1; i < pathMatch.Groups.Count; i++)
            {
                Group group = pathMatch.Groups[i];
                if (group.Success)
                {
                    string key = urlRegex.GroupNameFromNumber(i);
                    if (!string.IsNullOrEmpty(key) && !char.IsDigit(key[0]))
                    {
                        routeData.Values[key] = group.Value;
                    }
                }
            }

            return routeData;
        }

        return null;
    }

    private Regex CreateRegex(string pattern)
    {
        pattern = pattern.Replace("/", @"\/?");
        pattern = pattern.Replace(".", @"\.");
        pattern = pattern.Replace("-", @"\-?");
        pattern = pattern.Replace("{", @"(?<");
        pattern = pattern.Replace("}", @">([a-zA-Z0-9_]*))");

        return new Regex("^" + pattern + "$");
    }
}
次に、サブドメイン情報を持つデータモデルを作成します。

public class SubdomainInfo
{
    public string Protocol { get; set; } = "http";
    public string Host { get; set; }
    public string Fragment { get; set; } = "";
}
Global.asaxでルートを登録します。

routes.Add("CustomSubdomainRoute", new CustomSubdomainRoute(
    "{subdomain}.example.com", // サブドメインパターン
    "{controller}/{action}/{id}", // URLパターン
    new { subdomain = "", controller = "Home", action = "Index", id = "" } // デフォルト値
));
最後に、HomeControllerでサブドメイン情報を取得します。

public ActionResult Index()
{
    string subdomain = RouteData.Values["subdomain"]?.ToString();
    // 必要な処理をここに追加
    return View();
}
これで、ユーザーが独自に設定したサブドメインに対応する機能を実装できます。

タグ: ASP.NET-MVC C# custom-routing

7月6日 23:05 投稿