3

I think the specifics of my question are very much different than the other similar questions which I have red.

I know that when I have custom AuthorizeAttribute I can't inject dependencies with the constructor. This is because the constructor will take the parameters - in my case the permission strings.

 [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)]
    public class UserAllCSPermissionBasedAuthFilter : AuthorizeAttribute
    {

I am depending on authorization service, that's why I am injected that using property injection.

[Inject]
  public IAuthorizationService _authorizationService { get; set; }

The problem is that this service depends on another service - userservice which talks directly with repository and dbcontext. I have specify for my db context to live in request scope. This is cousing an exception - "The operation cannot be completed because the DbContext has been disposed." When I looked at the code this is happening when the autorization service calls userservice which asks the dbcontext for some data. How should I avoid this happening?

  public class AuthorizationService : IAuthorizationService
    {
        private readonly ICommonRepository _commonRepository;
        private readonly IRepositoryBase<UsersInRolesEntity> _repositoryUsersInRoles;
        private readonly IRepositoryBase<UserCustomerRolesEntity> _repositoryCurstomerRoleEntities;
        private readonly ISqlCustomersRepository _sqlCustomerRepository;
        private readonly IRoleService _roleService;
        private readonly IUserService _userService;
        private readonly IPermissionService _permissionService;

        public AuthorizationService(
            IRepositoryBase<UsersInRolesEntity> repositoryUsersInRoles,
            IRepositoryBase<UserCustomerRolesEntity> repositoryCurstomerRoleEntities,
            ICommonRepository commonRepository,
            ISqlCustomersRepository sqlCustomerRepository,
            IRoleService roleService,
            IUserService userService,
            IPermissionService permissionService
            )
        {
Lyubomir Velchev
  • 962
  • 2
  • 11
  • 30
  • Should I use Ninject conditional bindings in my case? Or have I done something wrongly? – Lyubomir Velchev Apr 30 '15 at 15:40
  • Prevent injecting dependencies into your attributes, as explained [here](https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=98) and [here](http://blog.ploeh.dk/2014/06/13/passive-attributes/). – Steven Apr 30 '15 at 21:29
  • Thanks for the links, I think they are helpful but it's difficult for me to digest them. The author is saying "The problem with this approach is that attribute instances are created by the run-time, so you can't use proper Dependency Injection (DI) patterns such as Constructor Injection. If an attribute defines behaviour (which many of the Web API attributes do), the most common attempt at writing loosely coupled code is to resort to a static Service Locator (an anti-pattern)." then his solution is "define attributes without behaviour.". In his solution I can't see how in the execution of the – Lyubomir Velchev May 01 '15 at 10:43
  • filter a call to service can be done which again is resolved by DI container (Ninject in my case) – Lyubomir Velchev May 01 '15 at 10:43
  • Take a look at this (related) q/a: https://stackoverflow.com/questions/29915192/unity-property-injection-on-authorizeattribute – Steven May 01 '15 at 10:46

1 Answers1

0

Steven, thanks for the support, I was looking at the articles you suggested and the Ninject manual. I totally agree with you that Property Binding is not a nice idea. But couldn't get why we are doing all of the things in the article (https://www.cuttingedge.it/blogs/steven/pivot/entry.php?id=98). I suppose that was written before the Ninject authors added a way to configure attribute binding using their framework (https://github.com/ninject/Ninject.Web.Mvc/wiki/Filter-configurations).

I had a look at my Ninject configuration. For my authorization filters I had something like this:

#region UserAllCSPermissionBasedAuthFilter

kernel.BindFilter<UserAllCSPermissionBasedAuthFilter>(FilterScope.Action, 0)
    .WhenActionMethodHas<UserAllCSPermissionBasedAuthFilter>()
    .WithConstructorArgumentFromActionAttribute<UserAllCSPermissionBasedAuthFilter>("permissionEnums", att => att.PermissionEnums);

kernel.BindFilter<UserAllCSPermissionBasedAuthFilter>(FilterScope.Controller, 0)
    .WhenActionMethodHas<UserAllCSPermissionBasedAuthFilter>()
    .WithConstructorArgumentFromControllerAttribute<UserAllCSPermissionBasedAuthFilter>("permissionEnums", att => att.PermissionEnums);

#endregion

I have a couple of these and then the light-bulb moment came :) I just saw a small mistake in my configuration. Instead of using:

kernel.BindFilter<UserAllCSPermissionBasedAuthFilter>(FilterScope.Controller, 0)
    .WhenActionMethodHas<UserAllCSPermissionBasedAuthFilter>()
    .WithConstructorArgumentFromControllerAttribute<UserAllCSPermissionBasedAuthFilter>("permissionEnums", att => att.PermissionEnums);

That should actually be:

kernel.BindFilter<UserAllCSPermissionBasedAuthFilter>(FilterScope.Controller, 0)
    .WhenControllerHas<UserAllCSPermissionBasedAuthFilter>()
    .WithConstructorArgumentFromControllerAttribute<UserAllCSPermissionBasedAuthFilter>("permissionEnums", att => att.PermissionEnums);

WhenActionMethodHas -> WhenControllerHas.

That miraculously fixed everything. Now works perfectly and the code looks fine to me without additional coding changes.

Marcos Dimitrio
  • 6,651
  • 5
  • 38
  • 62
Lyubomir Velchev
  • 962
  • 2
  • 11
  • 30