Subdomain Based Multi Tenancy in ASP.NET Zero (Angular)
Introduction
This document provides detailed guidance for configuring and troubleshooting subdomain based multi tenancy in ASP.NET Zero projects utilizing an Angular 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 Angular documentation.
1. Configuration for Subdomain Based Tenancy
This section involves SSL management, web server setup, and specific Angular 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
ClientRootAddressandServerRootAddress: If yourClientRootAddressfor tenants (e.g.,https://{TENANCY_NAME}.app.mydomain.com/) andServerRootAddress(e.g.,https://{TENANCY_NAME}.api.mydomain.com/) use different primary domains or distinct sets of subdomains, ensure your SSL certificate(s) cover all relevant wildcard domains (e.g.,*.app.mydomain.comand*.api.mydomain.com).
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 Angular application (typically
index.htmland other static assets from yourdistfolder) for all subdomain requests that point to the client application. - URL Rewrite (If Necessary): While ASP.NET Zero's framework 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.
Angular Application (appsettings.json) Specifics
- Dynamic Configuration with
{TENANCY_NAME}:- It is critical that the
{TENANCY_NAME}placeholder is used in theClientRootAddressandServerRootAddresswithin your Host application'sYourProjectName.Web.Host/appsettings.json(and potentiallyappsettings.Production.json). - Example:
{ "App": { "ServerRootAddress": "https://{TENANCY_NAME}.api.mydomain.com", "ClientRootAddress": "https://{TENANCY_NAME}.app.mydomain.com", //... Other Settings } }
- It is critical that the
- Tenant Resolution in Angular:
- ASP.NET Zero's client side infrastructure typically uses the
ServerRootAddress. The framework includes logic to dynamically replace the{TENANCY_NAME}placeholder based on the current browser URL's subdomain. - This ensures that API calls generated by
NSwagor other service proxies are directed to the correct tenant specific backend endpoints. - While largely abstracted, the Angular application inherently becomes tenant aware through these configured, dynamic URLs.
- ASP.NET Zero's client side infrastructure typically uses the
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. You can back up the file before making any changes.- 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 127.0.0.1 api.localhost # If testing backend with a similar local subdomain - Accessing the App: After saving the
hostsfile (you might need administrator privileges), you can access your Angular application in the browser using URLs likehttp://tenant1.localhost:4200(or your configured Angular development port).
Development Web Server Configuration
- Angular CLI (
npm run start):- The Angular CLI's development server (
npm run start) by default listens onlocalhost. To make it respond to custom hostnames liketenant1.localhost(which yourhostsfile now points to127.0.0.1), you might need to use:npm run start (ng serve --host 0.0.0.0): This makesng servelisten on all available network interfaces.--disable-host-check: In some cases, you might also need to add--disable-host-check(e.g.,ng serve --host 0.0.0.0 --disable-host-check). Use this flag with caution as it disables a security feature.
- The Angular CLI's development server (
- ASP.NET Core Host (
YourProjectName.Web.Host):- Similarly, ensure your Kestrel server (used by the ASP.NET Core backend) is configured to listen on the appropriate hostnames and ports if you are testing it with local subdomains. This can often be configured under the
applicationUrlproperty inlaunchSettings.jsonfor your development profile (e.g.,http://api.localhost:44301).
- Similarly, ensure your Kestrel server (used by the ASP.NET Core backend) is configured to listen on the appropriate hostnames and ports if you are testing it with local subdomains. This can often be configured under 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 and rely on the tenant switch dialog if HTTPS specific features are not being tested.
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 and potentially the Angular dev server to use these certificates. This provides a more accurate simulation of a production HTTPS environment.
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 application.
- ASP.NET Zero's middleware, specifically implementations of
ITenantResolveContributor(likeDomainTenantResolveContributor), inspects the request's host header (e.g.,tenant1.api.mydomain.com). - If the host matches the configured subdomain pattern (derived from
ServerRootAddresswith 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, ensuring data isolation and that tenant specific settings and services are used.
Frontend (Angular)
- The Angular application is loaded from a URL like
https://tenant1.app.mydomain.com. - The
ServerRootAddressinappsettings.json(e.g.,https://{TENANCY_NAME}.api.mydomain.com) is used by the generated service proxies. - ASP.NET Zero's client side JavaScript utilities dynamically replace the
{TENANCY_NAME}placeholder inServerRootAddresswith the actual tenancy name extracted from the current browser window's hostname (tenant1.app.mydomain.com). - All subsequent API calls made through these service proxies will correctly target the tenant specific backend API endpoints (e.g.,
https://tenant1.api.mydomain.com/api/services/app/User/GetUsers).
4. Troubleshooting Common Subdomain Multi Tenancy 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
- CorsOrigins Configuration: In the
appsettings.jsonof your*.Web.Hostproject, meticulously check theApp:CorsOriginssetting. It must accurately include the URLs of your Angular application, including the wildcard for subdomains.- Example:
"CorsOrigins": "https://*.app.mydomain.com,http://*.app.mydomain.com"(include both HTTP and HTTPS if applicable, and consider ports if non standard).
- Example:
- Browser Console: Always inspect the browser's developer console (Network tab) for detailed CORS error messages. The error often indicates which origin is being blocked and what headers are missing or mismatched from the preflight (OPTIONS) request.
- Scheme and Port: CORS is sensitive to scheme (HTTP vs. HTTPS) and port numbers. Ensure these match exactly in your
CorsOriginsconfiguration.
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 are loaded over HTTPS if your site is HTTPS.
Incorrect Tenant Loaded or Redirected to Host
- URL Configuration Check:
- Verify
ClientRootAddressandServerRootAddressinYourProjectName.Web.Host/appsettings.json. - Ensure they all correctly use the
{TENANCY_NAME}placeholder and reflect your actual domain structure.
- Verify
PreventNotExistingTenantSubdomains:- Check this setting in
YourProjectNameConsts.cs(in theCore.Sharedproject) for the API. - Check the equivalent setting in
AppConsts.tsfor the Angular application. - If
true, requests to subdomains for tenants that don't exist will be handled differently (often redirected or result in an error), rather than defaulting to the host.
- 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 around tenant resolution, to see how the tenant is being identified (or failing to be identified).