Reputation: 183
I have an ASP.NET Core Web API application, I want to serve two Angular apps, one for admin and one for users.
In production, I don't use angular CLI tools so there is only some static files of two angular web applications.
Admin files are in /angular/admin
and user files are in /angular/user
.
So, how can I serve them?
I tried multiple calls to IServiceCollection.AddSpaStaticFiles
but they override each other. [From source repository I found this is Singleton services]
Upvotes: 12
Views: 13121
Reputation: 310
I wanted to serve up an Outlook Addin from within my dotnet React based application. This is how I was able to get it to work for both development and production.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
...
app.Map("/addin",
addin =>
{
var sfo = new StaticFileOptions()
{
OnPrepareResponse = ctx =>
{
var resp = ctx.Context.Response;
resp.Headers[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate";
resp.Headers[HeaderNames.Expires] = "0";
resp.Headers[HeaderNames.Pragma] = "no-cache";
}
};
if (!env.IsDevelopment())
{
var dir = Path.Combine(Directory.GetCurrentDirectory(), "OutlookAddinApp/dist");
sfo.FileProvider = new PhysicalFileProvider(dir);
}
addin.UseSpaStaticFiles(sfo);
addin.UseSpa(spa =>
{
spa.Options.SourcePath = "OutlookAddinApp";
spa.Options.DefaultPage = "/taskpane.html";
spa.Options.DefaultPageStaticFileOptions = sfo;
if (env.IsDevelopment())
{
spa.Options.StartupTimeout = TimeSpan.FromMinutes(2);
spa.UseProxyToSpaDevelopmentServer("https://localhost:3000");
}
});
})
.Map("",
root =>
{
var sfo = new StaticFileOptions()
{
OnPrepareResponse = ctx =>
{
var resp = ctx.Context.Response;
resp.Headers[HeaderNames.CacheControl] = "no-cache, no-store, must-revalidate";
resp.Headers[HeaderNames.Expires] = "0";
resp.Headers[HeaderNames.Pragma] = "no-cache";
}
};
if (!env.IsDevelopment())
{
var dir = Path.Combine(Directory.GetCurrentDirectory(), "ClientApp/build");
sfo.FileProvider = new PhysicalFileProvider(dir);
}
root.UseSpaStaticFiles(sfo);
root.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
spa.Options.DefaultPageStaticFileOptions = sfo;
if (env.IsDevelopment())
{
spa.Options.StartupTimeout = TimeSpan.FromMinutes(2);
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
});
}
Upvotes: 1
Reputation: 3459
another tip: I'm using react and the react-router cannot handle path in URL correctly. So I use a different port for different spa. Use "app.MapWhen(o => o.Request.Host == 6000, ...)" to handle this case.
In production, should be something like : MapWhen(o => o.Request.Host.Host == "a.com"...
Upvotes: 1
Reputation: 8947
You have to branch the application middleware pipeline into two and register the SPAs after setting up MVC
...
app.UseMvc(...)
app.Map("/admin",
adminApp =>
{
adminApp.UseSpa(spa =>
{
spa.Options.SourcePath = "angular/admin";
spa.Options.DefaultPageStaticFileOptions = new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "angular", "admin"))
};
if (env.IsDevelopment())
spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
});
});
app.Map("/user",
userApp =>
{
userApp.UseSpa(spa =>
{
spa.Options.SourcePath = "angular/user";
spa.Options.DefaultPageStaticFileOptions = new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(Path.Combine(Directory.GetCurrentDirectory(), "angular", "user"))
};
if (env.IsDevelopment())
spa.UseProxyToSpaDevelopmentServer("http://localhost:4201");
});
});
```
Upvotes: 25