Reputation: 21217
I am building a prototype whereby I host my ASP.NET Core website (standard controllers/views etc) and the API within the same project.
I wish to use the following route scheme:
My approach thus far is to look at areas and the route config below works perfectly:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "areaDefault",
template: "{area:exists}/{controller=Values}/{action=Index}");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Now I want to expand this to use one set of middleware when accessing the API and another set when accessing the website. In reality this is to use different authentication setups between the areas. Google-fu lead me to the IApplicationBuilder.Map method and this is where my problem lies.
The config below works for the default route, Home/Index is executed but anything after /api returns 404.
// TODO: Add common middleware.
app.Map("/api", builder =>
{
// TODO: Add api specific middleware.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "apiDefault",
template: "api/{controller=Values}/{action=Index}");
});
});
// TODO: Add website specific middleware.
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Routes i have tried without success are:
The ValuesController is under the folder Areas/Api/Controllers and is defined as:
[Area("api")]
public class ValuesController : Controller
{
public IActionResult Index()
{
return Json(new { test = 1 });
}
}
The full source to reproduce this is available here: https://github.com/AntSwift/ApiRouteTest
Am I heading down the right path with this, is there something obvious I'm missing or is what I am attempting simply not possible.
Upvotes: 0
Views: 3451
Reputation: 3582
Check this, in the map section replace app.UseMvc
with builder.UseMvc
app.Map("/api", builder =>
{
// TODO: Add api specific middleware.
app.UseMvc(routes => // should be builder.UseMvc(routes
{
routes.MapRoute(
name: "apiDefault",
template: "api/{controller=Values}/{action=Index}");
});
});
Upvotes: 0
Reputation: 31
I suggest to do it differently and don't mix them together. Just create your api area or use api routing the way you want. Then create a middleware and name it "ApiAuthenticationMiddleware". Put it somewhere at the top of the configure pipeline. In that middleware look at the different properties in httpcontext . There are a lot of useful values in httpcontext. In your case you could use "path" property to find out where the request are going.
If the path has "/api/" in it. It means its going to your api's. Otherwise its going to your normal controllers. In that case you should short-circuit to next step in the pipeline.
Again in your case you could use below snippet in your middleware as an example. You should change it the way you want:
public async Task Invoke(HttpContext httpContext, YourDbContext dbContext)
{
string requestPath = httpContext.Request.Path.Value;
if(!requestPath.Contains("/api/"))
await _next.Invoke(httpContext);
string authHeader = httpContext.Request.Headers["Authorization"];
if (authHeader != null && authHeader.StartsWith("Basic"))
{
//Extract credentials
// other stuff
// example when no authorization header exists and want to reject.
httpContext.Response.StatusCode = 401; //Unauthorized
return;
// Call the next delegate/middleware in the pipeline
await _next.Invoke(httpContext);
}
}
Upvotes: 3