Subdomain Based Multi Tenancy in ASP.NET Zero (MVC)
Introduction
This document provides detailed guidance for configuring and troubleshooting subdomain based multi tenancy in ASP.NET Zero projects utilizing an MVC frontend. It expands upon the foundational knowledge offered in the official documentation, aiming to cover advanced configurations, development environment strategies, and common issues.
This document assumes you have a basic understanding of ASP.NET Zero's multi tenancy concepts and have reviewed the main Overview MVC documentation.
1. Configuration for Subdomain Based Tenancy
This section involves SSL management, web server setup, and specific MVC application settings.
SSL Certificate Management for Wildcard Domains
- Requirement: For HTTPS, a wildcard SSL certificate (e.g., for
*.mydomain.com) or a Subject Alternative Name (SAN) certificate covering all required tenant subdomains is essential. This secures communication for all your tenants. - Setup:
- Obtain a wildcard or appropriate SAN certificate from a Certificate Authority (CA).
- Install the certificate on your web server (e.g., IIS, Nginx, Apache) or load balancer.
- For IIS, this involves binding the HTTPS protocol (port 443) to the installed wildcard certificate for your application's site.
- Note on
WebSiteRootAddress: If yourWebSiteRootAddressfor tenants (e.g.,https://{TENANCY_NAME}.mydomain.com/) uses a different primary domain or distinct sets of subdomains, ensure your SSL certificate(s) cover all relevant wildcard domains.
Web Server Detailed Configuration (Example: IIS)
- Host Headers & Bindings:
- Configure a single website in IIS to respond to requests for all tenant subdomains.
- For HTTP binding (port 80), you can often leave the "Host Name" field empty if it's the only site on that IP, or specify each primary domain if needed.
- For HTTPS binding (port 443), select the appropriate wildcard SSL certificate. The host name field might be left blank or set if your IIS version supports specific SNI configurations with wildcards, but often the wildcard nature is primarily handled by the certificate itself. The key is that IIS listens for traffic on the IP and port, and the certificate validates for
*.mydomain.com.
- Default Document/Application: Ensure your IIS site is configured to correctly serve the MVC application (which handles routing to appropriate views and static assets) for all subdomain requests.
- URL Rewrite (If Necessary): While ASP.NET Zero handles tenant resolution based on the host, complex infrastructures involving reverse proxies might require URL Rewrite rules. However, for standard deployments, this is generally not needed for the core multi tenancy functionality.
MVC Application Considerations
WebSiteRootAddressConfiguration:- It is critical that the
{TENANCY_NAME}placeholder is used in theApp:WebSiteRootAddresssetting within yourYourProjectName.Web.Mvc/appsettings.jsonfile. - Example (in
appsettings.json):{ "App": { "WebSiteRootAddress": "https://{TENANCY_NAME}[.mydomain.com/](https://.mydomain.com/)" } //... Other Settings }
- It is critical that the
- URL Generation in Views/Controllers:
- ASP.NET Core's URL helpers (e.g.,
@Url.Action(),<a asp-controller="..." asp-action="...">tag helpers,RedirectToAction) will typically generate URLs relative to the current request's host, which includes the tenant subdomain. This is because the routing system and URL generation are aware of the incoming request's scheme and host. - This ensures that links within the application correctly point to tenant specific URLs without manual string manipulation of the domain in most cases.
- ASP.NET Core's URL helpers (e.g.,
- Static Assets: Static assets (CSS, JS, images) served by the MVC application (typically from
wwwroot) will also be accessed via the tenant specific subdomain, as the browser requests them relative to the current page's domain.
2. Development Environment Strategies for Subdomain Testing
Testing subdomain based multi tenancy locally requires a few extra steps compared to path based tenancy or using the tenant switch dialog.
Using the hosts File
- Purpose: To simulate DNS resolution for your subdomains on your local machine, you can edit the
hostsfile.- Windows:
C:\Windows\System32\drivers\etc\hosts - Linux/macOS:
/etc/hosts
- Windows:
- Example: Add entries to map your desired local subdomains to your loopback address (
127.0.0.1):127.0.0.1 tenant1.localhost 127.0.0.1 tenant2.localhost - Accessing the App: After saving the
hostsfile (you might need administrator privileges), you can access your MVC application in the browser using URLs likehttp://tenant1.localhost:44302(or your configured MVC development port, e.g., fromlaunchSettings.json).
Development Web Server Configuration (ASP.NET Core MVC)
launchSettings.json:- Configure the
applicationUrlin yourYourProjectName.Web.Mvc/Properties/launchSettings.jsonfile to include the hostnames you've defined in yourhostsfile. - When you run the project, Kestrel (or IIS Express if configured) will listen on these specified URLs. You can then browse to
http://tenant1.localhost:44302orhttps://tenant1.localhost:44302.
- Configure the
Local SSL with Subdomains
- Standard
localhostdevelopment certificates provided bydotnet dev-certs httpswill not be valid for custom local subdomains liketenant1.localhost. This will result in browser SSL warnings. - Solutions:
- HTTP Locally: For simplicity, you can develop and test the subdomain logic using HTTP locally. Add HTTP versions of your tenant localhost URLs to
launchSettings.json. mkcertTool: Use a tool likemkcertto create a locally trusted Certificate Authority (CA) and then generate wildcard certificates (e.g.,*.localhost). You would then configure Kestrel to use these certificates. This provides a more accurate simulation of a production HTTPS environment.- Trust Self Signed Certificate (IIS Express): If using IIS Express and it generates a certificate for
tenant1.localhost, you might still need to manually trust it in your browser or system.
- HTTP Locally: For simplicity, you can develop and test the subdomain logic using HTTP locally. Add HTTP versions of your tenant localhost URLs to
Interaction with Tenant Switch Dialog
- When subdomains are correctly configured and resolved (even in a local development environment using the
hostsfile), ASP.NET Zero should automatically identify the tenant from the URL's subdomain. - In such cases, the manual 'Tenant Switch' dialog becomes less relevant for requests made to these subdomain URLs, as the tenant context is already established.
3. Tenant Resolution Flow Clarification
A clear understanding of the tenant resolution process is essential to ensure accurate tenant identification and proper request routing in a multi tenant architecture. This step determines which tenant context should be applied based on the incoming request, typically using elements like the subdomain, header, or query string.
Backend (ASP.NET Core)
- An incoming HTTP request arrives at the ASP.NET Core MVC application.
- ASP.NET Zero's middleware, specifically implementations of
ITenantResolveContributor(likeDomainTenantResolveContributor), inspects the request's host header (e.g.,tenant1.mydomain.com). - If the host matches the configured subdomain pattern (derived from
WebSiteRootAddresswith the{TENANCY_NAME}placeholder), the middleware extracts the tenancy name (tenant1in this example). - It then attempts to find this tenant in the database.
- If found, the current tenant context is set for the duration of that request. This ensures data isolation and that tenant specific settings, services, and views (if customized per tenant) are used.
MVC Application UI & URL Generation
- The MVC application is accessed via a URL like
https://tenant1.mydomain.com/SomePage. - The backend resolves the tenant (
tenant1) as described above. - When server side code (Controllers, Views, Tag Helpers, Razor Pages) generates URLs (e.g., for links, form actions, redirects), ASP.NET Core's routing and URL generation mechanisms are aware of the current request's scheme (
https), host (tenant1.mydomain.com), and path base. - Therefore, URLs generated by helpers like
@Url.Action("Index", "Home")or<a asp-action="Index" asp-controller="Home">Link</a>will correctly form fully qualified or path relative URLs that maintain the tenant's subdomain (e.g.,/Home/Indexontenant1.mydomain.comorhttps://tenant1.mydomain.com/Home/Index). - This ensures that navigation within the tenant's site stays on the correct subdomain.
4. Troubleshooting Common Subdomain Multi Issues
Here are some common problems and how to address them:
DNS Not Resolving
- Propagation Time: DNS changes (especially for new wildcard records) can take time to propagate globally (minutes to hours).
- Record Verification: Double check your DNS provider's settings. Ensure the
Arecord orCNAMErecord for the wildcard (e.g.,*.mydomain.com) correctly points to your web server's public IP address. - Local
hostsFile: For local development, ensure yourhostsfile entries are correctly spelled, saved, and that your browser or OS is not caching old DNS lookups aggressively (try clearing cache or an incognito window).
CORS Errors (Contextualized for MVC)
- While less common for a self contained MVC application serving its own views and assets, CORS errors can arise if:
- Your MVC application makes client side (JavaScript) AJAX requests to a different domain (e.g., a separate
YourProjectName.Web.HostAPI for specific tasks, though less typical if MVC is the primary UI). - You use a CDN for static assets that requires specific CORS headers.
- Your MVC application makes client side (JavaScript) AJAX requests to a different domain (e.g., a separate
- If such errors occur, check the
App:CorsOriginssetting in theappsettings.jsonof the project receiving the request (e.g.,Web.Hostif it's the API being called). - Inspect the browser's developer console (Network tab) for detailed CORS error messages.
SSL Certificate Errors
- Certificate Name Mismatch: This means the SSL certificate presented by the server is not valid for the domain requested by the browser.
- Ensure your certificate is a true wildcard (e.g.,
*.mydomain.com) or a SAN certificate that explicitly lists all required tenant subdomains or the relevant wildcard.
- Ensure your certificate is a true wildcard (e.g.,
- Untrusted Certificate:
- For production, ensure your certificate is issued by a reputable CA.
- For local development with self signed or
mkcertgenerated certificates, ensure the root CA certificate used to sign them is trusted by your operating system and browser.
- Mixed Content: Ensure all resources (CSS, JS, images, etc.) are loaded over HTTPS if your site is served via HTTPS.
Incorrect Tenant Loaded or Redirected to Host
WebSiteRootAddressConfiguration Check:- Verify the
App:WebSiteRootAddressinYourProjectName.Web.Mvc/appsettings.json. - Ensure it correctly uses the
{TENANCY_NAME}placeholder and reflects your actual domain structure.
- Verify the
PreventNotExistingTenantSubdomains:- Check this setting in
YourProjectConsts.cs(in theCore.Sharedproject). - If
true(which is the default and recommended for subdomain tenancy), requests to subdomains for tenants that don't exist will typically result in a "not found" or a redirect to a host/error page, rather than defaulting to the host tenant's content under the unrecognized subdomain.
- Check this setting in
- Tenant Existence: Ensure the tenancy name being extracted from the URL (e.g.,
tenant1fromtenant1.mydomain.com) actually exists in your application's database and is active. - ASP.NET Core Logging: Increase logging verbosity for ASP.NET Core, especially for categories like
Microsoft.AspNetCore.Hostingand ASP.NET Zero's tenancy services, to see how the tenant is being identified (or failing to be identified) from the host header.