ASP.NET Core MVC中如何基于子域名配置数据源并实现全局检测?
ASP.NET Core MVC 根据子域名切换数据源实现方案
核心步骤
1. 解析请求的子域名
从请求Host中提取子域名,根据你的主域名结构调整解析逻辑:
private string ExtractSubDomain(HttpContext context) { var host = context.Request.Host.Host; if (string.IsNullOrWhiteSpace(host)) return "default"; var domainParts = host.Split('.'); // 针对 mywebapp.com 主域名,提取第一个子域部分 if (domainParts.Length >= 3 && domainParts[^2].Equals("mywebapp", StringComparison.OrdinalIgnoreCase) && domainParts[^1].Equals("com", StringComparison.OrdinalIgnoreCase)) { return domainParts[0]; } // 本地环境或不符合规则的域名返回默认值 return "default"; }
2. 全局拦截请求(中间件实现)
用自定义中间件捕获所有请求,将子域名存入HttpContext.Items,供后续流程使用:
public class SubDomainMiddleware { private readonly RequestDelegate _next; public SubDomainMiddleware(RequestDelegate next) { _next = next; } public async Task InvokeAsync(HttpContext context) { var subDomain = ExtractSubDomain(context); context.Items["CurrentSubDomain"] = subDomain; // 可在此提前初始化数据源配置,比如设置全局表前缀 await _next(context); } private string ExtractSubDomain(HttpContext context) { var host = context.Request.Host.Host; if (string.IsNullOrWhiteSpace(host)) return "default"; var domainParts = host.Split('.'); if (domainParts.Length >= 3 && domainParts[^2].Equals("mywebapp", StringComparison.OrdinalIgnoreCase) && domainParts[^1].Equals("com", StringComparison.OrdinalIgnoreCase)) { return domainParts[0]; } return "default"; } } // 扩展方法简化中间件注册 public static class SubDomainMiddlewareExtensions { public static IApplicationBuilder UseSubDomainResolver(this IApplicationBuilder app) { return app.UseMiddleware<SubDomainMiddleware>(); } }
在Program.cs中注册中间件(需放在路由中间件之前):
var app = builder.Build(); // 注册子域名解析中间件 app.UseSubDomainResolver(); // 其他中间件配置 app.UseRouting(); app.UseAuthorization(); app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); app.Run();
3. 控制器基类统一处理(可选)
让所有业务控制器继承自定义基类,在基类中获取子域名,供Action使用:
public class BaseController : Controller { protected string CurrentSubDomain { get; private set; } = "default"; public override void OnActionExecuting(ActionExecutingContext context) { if (context.HttpContext.Items.TryGetValue("CurrentSubDomain", out var subDomainObj)) { CurrentSubDomain = subDomainObj as string ?? "default"; } base.OnActionExecuting(context); } } // 业务控制器继承基类 public class HomeController : BaseController { private readonly MyDataRepository _repo; public HomeController(MyDataRepository repo) { _repo = repo; } public async Task<IActionResult> Index() { // 直接使用基类的CurrentSubDomain,或通过Repository获取 var data = await _repo.GetDataAsync(); return View(data); } }
4. 动态切换数据源/数据表
在数据访问层,通过IHttpContextAccessor获取子域名,动态构造表名或切换数据源:
public class MyDataRepository { private readonly string _subDomain; public MyDataRepository(IHttpContextAccessor httpContextAccessor) { _subDomain = httpContextAccessor.HttpContext?.Items["CurrentSubDomain"] as string ?? "default"; } public async Task<List<MyDataModel>> GetDataAsync() { // 根据子域名构造专属表名,例如 site1_MyData var targetTable = $"{_subDomain}_MyData"; // EF Core 示例:动态指定表查询 using var dbContext = new MyDbContext(); return await dbContext.Set<MyDataModel>() .FromSqlRaw($"SELECT * FROM {targetTable}") .ToListAsync(); } }
别忘了在Program.cs中注册IHttpContextAccessor:
builder.Services.AddHttpContextAccessor(); builder.Services.AddScoped<MyDataRepository>();
注意事项
- 子域名解析逻辑需根据实际域名结构调整,比如多层级域名、不同后缀等
- 动态拼接SQL存在注入风险,建议使用参数化查询或EF Core的动态表映射方案
- 可添加子域名白名单校验,防止非法子域名访问
内容的提问来源于stack exchange,提问作者JCBrinegar
相关产品推荐
相关产品推荐

