The static file middleware has this feature builtin, MapFallBackToFile()
Example
app.MapFallbackToFile(“index.html”);
Be sure it’s the last route mapping
This browser is no longer supported.
Upgrade to Microsoft Edge to take advantage of the latest features, security updates, and technical support.
I have an aspnet core odata running in the root folder, and reactjs spa running in the webroot folder. It works swimmingly if I always go to index.html first...then take navigation over once its loaded....but if I try and go directly to any url other than index I get a 404. I am new to asp.net core and i'm thinking that some way to make this work.
The static file middleware has this feature builtin, MapFallBackToFile()
Example
app.MapFallbackToFile(“index.html”);
Be sure it’s the last route mapping
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.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"),
b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));
services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());
services.AddScoped((serviceProvider) =>
{
var config = serviceProvider.GetRequiredService<IConfiguration>();
return new SmtpClient()
{
Host = config.GetValue<String>("Email:Smtp:Host"),
Port = config.GetValue<int>("Email:Smtp:Port"),
Credentials = new NetworkCredential(
config.GetValue<String>("Email:Smtp:Username"),
config.GetValue<String>("Email:Smtp:Password")
)
};
});
#region Swagger
services.AddSwaggerGen(c =>
{
//c.IncludeXmlComments(string.Format(@"{0}\EFCore.CodeFirst.WebApi.xml", System.AppDomain.CurrentDomain.BaseDirectory));
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "xxxxx API",
});
var filePath = Path.Combine(AppContext.BaseDirectory, "xxx.xml");
c.IncludeXmlComments(filePath);
});
#endregion
services.AddCors();
services.AddControllers(mvcOptions => mvcOptions.EnableEndpointRouting = false);
services.AddOData();
services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
// configure DI for application services
services.AddTransient<IUserService, UserService>();
services.AddOptions();
SetOutputFormatters(services);
}
// 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();
}
DefaultFilesOptions options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("index.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
// global cors policy
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
// custom jwt auth middleware
app.UseMiddleware<JwtMiddleware>();
// localization
//app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
app.UseMvc(routeBuilder =>
{
routeBuilder.EnableDependencyInjection();
routeBuilder.Select().Filter().OrderBy();
routeBuilder.MapODataServiceRoute("api", "api", GetEdmModel());
});
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
#region Swagger
// Enable middleware to serve generated Swagger as a JSON endpoint.
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "EFCore.CodeFirst.WebApi");
});
#endregion
}
IEdmModel GetEdmModel()
{
var odataBuilder = new ODataConventionModelBuilder();
odataBuilder.EntitySet<User>("Users");
odataBuilder.EntitySet<UserProduct>("UserProducts");
odataBuilder.EntitySet<Product>("Products");
return odataBuilder.GetEdmModel();
}
private static void SetOutputFormatters(IServiceCollection services)
{
services.AddMvcCore(options =>
{
foreach (var outputFormatter in options.OutputFormatters.OfType<ODataOutputFormatter>().Where(_=> _.SupportedMediaTypes.Count == 0))
{
outputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/odata"));
}
foreach (var inputFormatter in options.InputFormatters.OfType<ODataInputFormatter>().Where(_ => _.SupportedMediaTypes.Count == 0))
{
inputFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("application/odata"));
}
});
}
}
The react navigation is supported by index.html file. So if you want to navigate to a route in the spa app, the server needs to return the index.html content in response to the request. Then the react code will inspect the url and execute the route.
Assume your spa has the route info and you want
https://my site.com/info
To work. In your .net core app you need to map info to the index.html file content (don’t use a redirect).
Note: you can use UseSpa middleware to do this for you.