I have created a new solution using the template in Visual Studio 2019 (Blazor App->Blazor WebAssembly App with ASP.NET Core hosed ticked), refernced OrchardCore.Application.Mvc.Targets in the Server project and added the tenants using the sample from https://github.com/OrchardCMS/OrchardCore.Samples/blob/master/MultiTenantApplication/appsettings.json
Moving UseEndpoints from StartUp.Configure to OrchardCoreBuilder.Configure allows me to inject ShellSettings into the constructor of WeatherForecastController and correctly retrieve tenant specific information such as CustomTitle.
When running the solution the Blazor client app can't resolve the page returns a 404 however https://localhost:44338/WeatherForecast and https://localhost:44338/customer-a/WeatherForecast work as expected.
My Setup.cs looks as follows:
````
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
services.AddOrchardCore().WithTenants().Configure(app =>
{
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseOrchardCore();
}
}
````
Is it possible to add multi tenant functionality to the Server project?
Try
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services
.AddOrchardCore()
.AddMvc()
.WithTenants();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseWebAssemblyDebugging();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseOrchardCore(a =>
a.UseEndpoints(e => e.MapFallbackToFile("index.html"))
);
}
}
The following delegate will be executed before the tenant pipeline
app.UseOrchardCore(a =>
a.UseEndpoints(e => e.MapFallbackToFile("index.html"))
If it needs to be executed after
services.AddOrchardCore()
.AddMvc()
.WithTenants()
.Configure((app, endpoints) => endpoints.MapFallbackToFile("index.html"));
@jtkech are static files tenant aware?
Not really as /module1/file1, /tenant1/module1/file1 and /tenant2/module1/file1 will serve the same embedded static file (unless the related tenant doesn't exist or is disabled). For static files we use ~/ to resolve the full url including an eventual virtual folder, so, because it is resolved in a tenant context the full url contains the tenant segment.
So yes all is resolved and requested in a tenant context but as said module / theme static files are shared acrross tenants.
Note: The above is related to our custom module static file providers.
We also have a TenantFileProvider to serve specific static files per tenant from the related site folder under app_data
Finally app.UseStaticFiles() at the app level allows to serve app level static files in a regular way. Notice that because the app behaves as a module, an app level static file can be served with /appfile1 or /OrchardCore.Cms.Web/appfile1 or /tenant1/OrchardCore.Cms.Web/appfile1 and so on.
@jtkech /appfile1 works for default tenant but /tenant1/appfile1 doesn't. However /tenant1/OrchardCore.Cms.Web/appfile1 works.
for above case /OrchardCore.Cms.Web/index.html doesn't work in dev but if you run after publish then it works.
I wish /tenant1/OrchardCore.Cms.Web/index.html should just resolve to /tenant1/index.html
/appfile1 works for default tenant but /tenant1/appfile1 doesn't.
You're right i didn't say it was working, through the regular app level static file provider that is not tenant aware only /appfile1 works, to make /tenant1/appfile1 working you would need another file wwwroot/tenant1/appfile1.
Then through the module static file providers the rule is {tenant}/{module}/{file} where module can be the app name.
for above case /OrchardCore.Cms.Web/index.html doesn't work in dev but if you run after publish then it works.
Just tried in dev mode it works on my side, take care of any character, it is case sensitive for the module = area
I wish /tenant1/OrchardCore.Cms.Web/index.html should just resolve to /tenant1/index.html
Maybe but the first works because it uses the {tenant}/{module}/{file} pattern and then is served by the module static file provider that is tenant aware. The second will be served by the app level static file provider where /index.html and /tenant1/index.html are 2 distinct files.
through the regular app level static file provider that is not tenant aware only
/appfile1works, to make/tenant1/appfile1working you would need another filewwwroot/tenant1/appfile1
It's confusing. If Module embedded static files are resolved to same file for different tenant then why static files placed in wwwroot of app are not resolved to same file for different tenants?
Yes i understand, this is because we let the app level static file provider working as it is intended to work
Maybe we could also serve files as /appfile1 through our module static file provider that is executed before, and if no module segment is provided we could fallback to the app's module, so that /appfile1 and /tenant1/appfile1 would serve the same file.
Yes i understand, this is because we let the app level static file provider working as it is intended to work
Maybe we could also serve files as
/appfile1through our module static file provider that is executed before, and if no module segment is provided we could fallback to the app's module, so that/appfile1and/tenant1/appfile1would serve the same file.
That would be nice as here Blazor app content are in separate project - referenced to web project and not be embedded in assembly - instead when published these files are published as content to wwwroot that needs to be resolved to same file for all tenants.
Just tried in dev mode it works on my side, take care of any character, it is case sensitive for the module = area
This doesn't work in dev if static file index.html is referenced from blazor web assembly project. It only works in dev if static file is in wwwroot of web project.
However it works when published, as wwwroot contents are combined when published
That would be nice as here Blazor app content are in separate project - referenced to web project and not be embedded in assembly - instead when published these files are published as content to wwwroot that needs to be resolved to same file for all tenants.
Fixed on my side with 2 lines of code so that /appfile1 and /tenant1/appfile1 serve the same file (unless the tenant1 doesn't exist). Maybe file an issue so that we could track it and then i will do a PR.
This doesn't work in dev if static file index.html is referenced from blazor web assembly project.
Here i have no obvious solution
/appfile1and/tenant1/appfile1serve the same file (unless the tenant1 doesn't exist)
I think while creating tenant, it should validate tenant name doesn't match with any folder within wwwroot
Yes i thought about this ;) will see
With the upcoming release of .NET 5, which offers lots of improvements for Blazor, I am looking to create a fully functional multitenant Blazor WASM application.
Are there any plans to move this issue (or #6505) forward?
I think some folks have started experimenting with blazor here: https://github.com/BlazingOrchard
Most helpful comment
Fixed on my side with 2 lines of code so that
/appfile1and/tenant1/appfile1serve the same file (unless the tenant1 doesn't exist). Maybe file an issue so that we could track it and then i will do a PR.Here i have no obvious solution