Inject IOwinContext with Web API and Ninject - asp.net-web-api

Using Web API 2 and OWIN hosting with Ninject.
I would like to inject the current IOwinContext into certain services (so I can get at the Request to get the principal to do some data filtering).
With Web Hosting I would, in the old days, simply have used HttpContext.Current but that is not an option with OWIN hosting (and good riddance).
This SO question explains how to do it with Autofac. Essentially, you create a Dependency Scope and then, on each request, calls Autofac's Registerinstance to register the current IOwinContext into that dependency scope like so:
app.Use(async (ctx, next) =>
{
// this creates a per-request, disposable scope
using (var scope = container.BeginLifetimeScope(b =>
{
// this makes owin context resolvable in the scope
b.RegisterInstance(ctx).As<IOwinContext>();
}))
{
// this makes scope available for downstream frameworks
ctx.Set<ILifetimeScope>("idsrv:AutofacScope", scope);
await next();
}
});
That is very elegant. With Ninject and the Ninject.Web.WebApi.OwinHosting I already get a named scope for each request so that plumbing is taken care of. However, I haven't been able to find any way in ninject to mirror AutoFac's RegisterInstance method: The key here is that this binding is only valid within this particular dependency scope.
I have read up on the various options around Scope but everything I have found relies on being able to declare constants or ToMethod. What I am looking to do here is to say, "okay, I now have a ninject dependency scope and if anyone asks for an IOwinContext from this scope, give them this instance that I already have.
Note
I do understand that I can get the current context from within my controller and pass it on, but that rather defeats the purpose of what I am trying to do; I want my DbContext to understand who the user is so it can filter the data. And, of course, once I can get the IOwinContext I won't actually pass that to the DbContext, rather I will use a ToMethod or similar to extract the ClaimsPrincipal but that is out of scope of this question.

DISCLAIMER: This is a hack. It works, but it feels very unclean. Use at your peril.
In essence, you can create an OwinContextHolder class, bind it InRequestScope and use a DelegatingHandler to populate it on each request. Something like this:
public class OwinContextHolder
{
public IOwinContext OwinContext { get; set; }
}
public class OwinContextHolderModule : NinjectModule
{
public override void Load()
{
// Instead of a NinjectModule you can of course just register the service
this.Kernel.Bind<OwinContextHolder>().ToSelf().InRequestScope();
}
}
Your delegating handler:
public class SetOwinContextHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var holder = request.GetDependencyScope().GetService(typeof(OwinContextHolder)) as OwinContextHolder;
if (holder != null)
{
holder.OwinContext = request.GetOwinContext();
}
return base.SendAsync(request, cancellationToken);
}
}
Finally add the DelegatingHandler to your Startup class:
public void Configuration(IAppBuilder app)
{
var webApiConfiguration = new HttpConfiguration();
webApiConfiguration.Routes.MapHttpRoute(...);
webApiConfiguration.MessageHandlers.Add(new SetOwinContextHandler());
app.UseNinjectMiddleware(CreateKernel);
app.UseNinjectWebApi(webApiConfiguration);
}
You can now inject OwinContextHolder into your classes.
Note that if you have your API in a separate assembly from your host, you may have problems with InRequestScope silently not working (as in, you get a different object every time you request one and no errors). If you do, see https://groups.google.com/forum/#!topic/ninject/Wmy83BhhFz8.

Related

accessing dbcontext within an Authroization Policy Requirement Handler

in a previous posting from a few years ago - Can Policy Based Authorization be more dynamic?
one of the answers offers up the following code:
Then define the handler.
public class MinimumAgeHandler : AuthorizationHandler<DataDrivenRequirement>
{
protected override void Handle(AuthorizationContext context,
DataDrivenRequirement requirement)
{
// Do anything here, **interact with DB**, User, claims, Roles, etc.
// As long as you set either:
// context.Succeed(requirement);
// context.Fail();
}
}
I am using .NET Core 3 MVC with EntityFrameworkCore. I wish to interact with a database in the Handler. The Handler is not passed a dbcontext like a Controller is. I have tried several ways to do it without any success. Does anyone know how to access a dbcontext from here?
Just so you know, the closest I came was using the following code from another post - How to access dbcontext & session in Custom Policy-Based Authorization
public class CheckAuthorizeHandler : AuthorizationHandler<CheckAuthorizeRequirement>
{
MyContext _context;
public CheckAuthorizeHandler(MyContext context)
{
_context = context;
}
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
MyRequirement requirement)
{
// Do something with _context
// Check if the requirement is fulfilled.
return Task.CompletedTask;
}
}
but got the following error: InvalidOperationException: Cannot consume scoped service 'NASAppsAdmin.Models.NASAppsDbContext' from singleton 'Microsoft.AspNetCore.Authorization.IAuthorizationHandler'.
InvalidOperationException: Cannot consume scoped service 'NASAppsAdmin.Models.NASAppsDbContext' from singleton 'Microsoft.AspNetCore.Authorization.IAuthorizationHandler'. Entity Framework contexts are usually added to the service container using the scoped lifetime, if you'd like to use database context from your handler, plese make sure your handler is not registered as singleton. – Fei Han

ObjectId Model Binding with Web Api 2

I'm using MongoDB with an ASP.NET Web Api (2) application, and want to accept ObjectId arguments in the Web Api methods.
I've written a custom model binder for the ObjectId type, and it when adding it to the Get method of a controller, everything works.
[Route("{id}")]
public HttpResponseMessage Get(String type, [ModelBinder(typeof(ObjectIdModelBinder))]ObjectId id) {
But I need to do this in several methods and controllers, so I would rather put it somewhere central. I've read that I can register the binder centrally like this:
public static void Register(HttpConfiguration config) {
var provider = new SimpleModelBinderProvider(typeof(ObjectId), new ObjectIdModelBinder());
config.Services.Insert(typeof(ModelBinderProvider), 0, provider);
}
But that's not working!
Any ideas? Not really sure what the config.Services collection should contain, but I'm having a hard time locating the binder I insert.
With WebAPI even if you register a model binder, you still need to attach the [ModelBinder] to the input parameter, you just don't have to specify the type anymore so your method now looks like this:
[Route("{id}")]
public HttpResponseMessage Get(String type, [ModelBinder]ObjectId id) {
If you want to skip adding the attribute every time you declare a parameter of this type, then you have to look at writing a custom IActionValueBinder (which can be made very simple if you just extend the DefaultActionValueBinder) which is the default implementation. You might want to look at this post for pointers:
http://www.strathweb.com/2013/04/asp-net-web-api-parameter-binding-part-1-understanding-binding-from-uri/

Problems After Disposing DbContext

I recently made changes to my MVC3 Application in attempt to properly dispose of the DbContext objects [1]. This worked great in development, but once the application was pushed to my production server, I started intermittently getting some funny exceptions which would persist until the AppPool was recycled. The exceptions can be traced back to code in my custom AuthorizeAttribute and look like:
System.InvalidOperationException: The 'Username' property on 'User' could not be set to a 'Int32' value. You must set this property to a non-null value of type 'String'.
System.InvalidOperationException: The 'Code' property on 'Right' could not be set to a 'String' value. You must set this property to a non-null value of type 'Int32'.
(Database schema looks like this: Users: [Guid, String, ...], Rights: [Guid, Int32, ...])
It is as if some "wires are getting crossed", and the application is mixing up results from the database: trying to materialize the Right result as a User and vise versa.
To manage the disposal of DbContext, I put code in to store this at a per-controller level. When the controller is disposed, I dispose the DbContext as well. I know it's hacky, but the AuthorizeAttribute uses the same context via filterContext.Controller.
Is there something wrong with handling the object lifecycle of DbContext in this manor? Are there any logical explanations as to why I am getting the crisscross exceptions above?
[1] Although I understand that it is not necessary to dispose of DbContext objects, I recently came across a number of sources stating that it was best practice regardless.
Edit (per #MikeSW's comment)
A property of the AuthorizeAttribute representing the DbContext is being set in the OnAuthorization method, when the AuthorizationContext is in scope. This property is then later used in the AuthorizeCore method.
Do you actually need to dispose the context?
According to this post by Jon Gallant who has been in touch with the Microsoft ADO.NET Entity Framework team:
Do I always have to call Dispose() on my DbContext objects? Nope
Before I talked with the devs on the EF team my answer was always a resounding “of course!”. But it’s not true with DbContext. You don’t need to be religious about calling Dispose on your DbContext objects. Even though it does implement IDisposable, it only implements it so you can call Dispose as a safeguard in some special cases. By default DbContext automatically manages the connection for you.
First i recommend that you get "really" familiar with
ASP.NET Application Life Cycle Overview for IIS 7.0 as it's fundamental to good MVC application design.
Now to try and "mimic" your code base
Let's say you have a similar custom MembershipProvider as described here https://stackoverflow.com/a/10067020/1241400
then you would only need a custom Authorize attribute
public sealed class AuthorizeByRoles : AuthorizeAttribute
{
public AuthorizeByRoles(params UserRoles[] userRoles)
{
this.Roles = AuthorizationHelper.GetRolesForEnums(userRoles);
}
}
public static class AuthorizationHelper
{
public static string GetRolesForEnums(params UserRoles[] userRoles)
{
List<string> roles = new List<string>();
foreach (UserRoles userRole in userRoles)
{
roles.Add(GetEnumName(userRole));
}
return string.Join(",", roles);
}
private static string GetEnumName(UserRoles userRole)
{
return Enum.GetName(userRole.GetType(), userRole);
}
}
which you can use on any controller or specific action
[AuthorizeByRoles(UserRoles.Admin, UserRoles.Developer)]
public class MySecureController : Controller
{
//your code here
}
If you want you can also subscribe to the PostAuthorizeRequest event and discard the results based on some criteria.
protected void Application_PostAuthorizeRequest(Object sender, EventArgs e)
{
//do what you need here
}
As for the DbContext, i have never run into your situation and yes per request is the right approach so you can dispose it in the controller or in your repository.
Of course it's recommended that you use filters and then add [AllowAnonymous] attribute to your actions.

Is it possible to have multiple dependency resolvers in ASP.NET MVC 3?

Is it possible to have more than one dependency resolver in ASP.NET MVC 3 (similar to the case of ModelBinders and Providers)?
There is one scenario that I could think of where having multiple 'containers' or 'resolvers' is useful and that is multi-tenancy. With multi tenancy you run multiple customers (organizations, with their own set of users) in the same web application, and dynamically switch based on the login, request info, or domain info.
Still, DependencyResolver.Current is -as Darin noted- static, so there's nothing you can (or should do about this). However, you could hide multiple containers behind a single IDependencyResolver abstraction and return an implementation based on some criteria. It might look like this:
public class MultiTenantDependencyResolver
: IDependencyResolver
{
Func<int> tenantIdSelector,;
IDictionary<int, IDependencyResolver> tenantResolvers;
public MultiTenantDependencyResolver(
Func<int> tenantIdSelector,
IDictionary<int, IDependencyResolver> tenantResolvers)
{
this.tenantIdSelector = tenantIdSelector;
this.tenantResolvers= tenantResolvers;
}
private IDependencyResolver CurrentResolver
{
get { return this.tenantResolvers[tenantIdSelector()]; }
}
public object GetService(Type serviceType)
{
return this.CurrentResolver.GetService(serviceType);
}
public IEnumerable<object> GetServices(Type serviceType)
{
return this.CurrentResolver.GetAllInstances(serviceType);
}
}
The following code snippet shows the usage of this MultiTenantDependencyResolver:
var tenantResolvers = new Dictionary<int, IDependencyResolver>
{
{ Tenants.AbcId, BuildResolver(RegisterForTenantAbc) },
{ Tenants.KlmId, BuildResolver(RegisterForTenantKlm) },
{ Tenants.XyzId, BuildResolver(RegisterForTenantXyz) },
};
var multiTenantResolver = new MultiTenantResolver(
() => GetTenantIdFromUrl(), tenantResolvers);
DependencyResolver.SetResolver(multiTenantResolver);
private static int GetTenantIdFromUrl()
{
// TODO: return tenant id
}
private static IDependencyResolver BuildResolver(
Action<IKernel> tenantSpecificRegistrations)
{
var kernel = new Kernel();
// TODO: Tenant agnostic registrations. For instance
kernel.Bind<ITimeProvider>().To<SystemTimeProvider>();
tenantSpecificRegistrations(kernel);
return new NinjectDependencyResolver(kernel);
}
private static void RegisterForTenantAbc(IKernel kernel)
{
// TODO: regisrations for ABC tenant. For instance
kernel.Bind<ILogger>().To<AbcTenantLogger>();
}
Is it possible to have more than one dependency resolver in ASP.NET
MVC 3 (similar to the case of ModelBinders and Providers)?
No, this isn't possible. The DependencyResolver.Current is a static property that could be assigned only one resolver. This being said having more than one dependency resolver in an application hardly makes any sense. The idea is that all your dependencies are managed by a dependency injection framework such as Unity, Ninject or StructureMap. You would then have a custom dependency resolver wrapping your DI framework of choice that will be used by ASP.NET MVC to inject dependencies in various objects of the execution pipeline.
You are comparing it with model binders in your question but this comparison is unfair because a model binder is related to a specific type that it is designed to bind. Basically you could have many custom model binders for multiple view models.
You also seem to have mentioned some providers in your question but unfortunately you haven't beeen very specific so it's a bit harder to comment on this one.

Property Injection into Web API's `System.Web.Http.Filters.ActionFilterAttribute`

Where is the recommended place to perform property injection into action filter attributes in an ASP.NET web api project? In MVC 3 land, we could set our own implementation for ControllerActionInvoker at the point of resolving our controllers from our IoC container, and override its GetFilters() method to inject components resolved from the container.
Is there a similar place to do this in an ASP.NET Web API project? I have a controller factory that resolves controllers from the container, with the CreateController method as so:
public IHttpController CreateController(HttpControllerContext controllerContext, string controllerName)
{
var controller = _kernel.Resolve<IHttpController>(controllerName);
controllerContext.Controller = controller;
controllerContext.ControllerDescriptor = new HttpControllerDescriptor(_configuration, controllerName, controller.GetType());
return controllerContext.Controller;
}
I've had a look at HttpControllerDescriptor to see if there is somewhere to do the injection, but I can't see a suitable place. Any pointers in the right direction?
You need to implement IHttpControllerSelector and register your selector in the (Services property) DefaultServices of the HttpConfiguration.
Or alternatively, to use your own resolver/DI framework, you need to replace the resolver. See here for an example.
You need to Implement your own IFilterProvider. Have a look at the source for ActionDescriptorFilterProvider. This is where you can inject properties.
Here is ActionDescriptorFilterProvider implementation:
public IEnumerable<FilterInfo> GetFilters(HttpConfiguration configuration, HttpActionDescriptor actionDescriptor)
{
if (configuration == null)
{
throw Error.ArgumentNull("configuration");
}
if (actionDescriptor == null)
{
throw Error.ArgumentNull("actionDescriptor");
}
IEnumerable<FilterInfo> controllerFilters = actionDescriptor.ControllerDescriptor.GetFilters().Select(instance => new FilterInfo(instance, FilterScope.Controller));
IEnumerable<FilterInfo> actionFilters = actionDescriptor.GetFilters().Select(instance => new FilterInfo(instance, FilterScope.Action));
return controllerFilters.Concat(actionFilters);
}
All you have to do is to use instance lambda parameter and inject properties.
Registration As you have figured out, the filter provider needs to be registered against the HttpConfiguration. Or alternatively, to use your own resolver/DI framework, you need to replace the resolver. See here for an example.

Resources