I'm using WebApi on top of Owin, and I'm getting 404 on routes that are mapped with http attribute routes where middleware runs first, although the middleware is running correctly. I would have thought the call to UseWebApi happening last would sign up those routes to run as the last middleware in the pipeline. What am I missing?
- Calls to "/token" work.
- Calls with missing or incorrect X-Auth-Token to /user/domainid/{id} get 403'd as expected.
- Calls with correct X-Auth-Token to /user/domainid/{id} get 404'd (This is what I can't figure out.)
Here is my startup:
public void Configuration(IAppBuilder app)
{
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
var container = new Container();
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
container.RegisterSingleton<IADSearchService>(new ADSearchService());
container.RegisterWebApiControllers(config);
container.Verify();
config.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
app.Use(async (context, next) =>
{
using (AsyncScopedLifestyle.BeginScope(container))
{
await next();
}
});
app.MapWhen(
context => !context.Request.Uri.PathAndQuery.StartsWith("/token"),
builder => builder.UseAuthorizationMiddleware());
app.UseWebApi(config);
}
Authorization middleware:
class AuthorizationMiddleware : OwinMiddleware
{
public AuthorizationMiddleware(OwinMiddleware next) : base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
var auth = context.Request.Headers.Get("X-Auth-Token");
if (auth == null || auth != "12345")
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
return;
}
// Edit: I've discovered that Next is null here when
// calling /user/domainid/{id} with the right X-Auth-Token.
await Next.Invoke(context);
}
}
WebApi Controller that doesn't run:
[RoutePrefix("user")]
public class UserController : ApiController
{
private readonly IADSearchService adSearch;
public UserController(IADSearchService iADSearch)
{
this.adSearch = iADSearch;
}
[Route("domainid/{id}")]
[HttpGet]
public IHttpActionResult GetUserByDomainID(string id)
{
var user = adSearch.GetUserBySAM(id).ToDomainUser();
if (user == null)
{
return NotFound();
}
return Json(user);
}
}
But this controller does run:
[Route("token")]
public class TokenController : ApiController
{
[HttpGet]
public IHttpActionResult Authenticate()
{
return Ok("This is a token!");
}
}
Edit: I've discovered that Next in the AuthorizationMiddleware implementation is null during correct calls to /user/domainid/{id}.
How can I ensure the webapi routes get registered as Next in preceding middleware layers?
Edit2: I've managed to get it working by adding another call to UseWebApi within the app.MapWhen. I feel like this shouldn't be necessary and am still wondering what the correct solution is here. I'd expect to be able make conditional branches on the IAppBuilder without duplicating calls to UseWebApi, maybe not though.
app.MapWhen(
ctx => !ctx.Request.Uri.PathAndQuery.StartsWith("/token"),
builder =>
{
builder.UseAuthorizationMiddleware();
builder.UseWebApi(config);
});
app.UseWebApi(config);