Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Alexandru Rustin 7 posts 87 karma points
    Mar 12, 2021 @ 16:08
    Alexandru Rustin
    1

    Dependency injection - DependencyResolver- service locator pattern while having a custom role prrovider.

    Hello everyone,

    First of all, thank you for reading and helping out.

    All the problems start with implementing a custom role provider in umbraco v8, previously in v7 this worked with no problems.

    Context/environment

    We have the config like this:

     <!-- Role Provider -->
    <roleManager enabled="true" defaultProvider="UmbracoRoleProvider">
      <providers>
        <clear/>
        <!--<add name="UmbracoRoleProvider" type="Umbraco.Web.Security.Providers.MembersRoleProvider" />-->
        <add name="UmbracoRoleProvider" type="Custom.Www.Security.CustomRoleProvider, Custom.Www.Security"/>
      </providers>
    </roleManager>
    

    where Custom.Www.Security is a simple project C# project with only two classes, overriding the MembershipProvider and RoleProvider.

    The problem is how to inject dependencies into these two classes.

    Previously, this was done in a "service locator anti-pattern" manner like this, using DependencyResolver:

    public CustomMembershipProvider() {
     _userService = DependencyResolver.Current.GetService<UserService>();
     _memberService = DependencyResolver.Current.GetService<IMembershipService>();}
    

    In the Composer class for umbraco, we register dependencies like this:

     var container = composition.Concrete as LightInject.ServiceContainer;
     IocConfig.RegisterIOC(container, null);   // IocConfig.Register is in another project
     RegisterSpecificServices(container);
    

    Previously, in the bootstrap of umbraco we had something like:

    DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    

    but after reading both the documentation for umbraco and lightInject, there's no need for this line anymore as this is done automatically in the container.EnableMvc() method of lightInject.

    Problem:

    When resolving dependencies via code like this

     _userService = DependencyResolver.Current.GetService<UserService>();
    

    we get the following error:

    System.InvalidOperationException: 'Attempt to create a scoped instance without a current scope.'
    

    LE: Solution:

    While writing this, I continued searching for a solution and stumbled on it. I'll leave it here in case it helps other people!

    I have read the following threads: https://stackoverflow.com/questions/57666457/outside-of-scope-when-use-a-service-in-configure-method

    and most importantly:

    https://stackoverflow.com/questions/24794778/custom-role-provider-dbcontext-disposed

    Short summary of the solution:

    Service locator anti-pattern in the constructor in the overridden classes will not work. Why is this the case?

    The lifetime of Asp.Net role providers are managed by the runtime and are tied to the lifetime of the application not an individual request. Hence if you resolve dependencies in the initialise method then this will only happen once leading to it hanging onto a disposed DbContext. Standard practice is to resolve once per method as per your fix.

    You will have to use property "injection", aka service locator on a property getter.

            privateIMembershipService CmsMembershipService => DependencyResolver.Current.GetService<IMembershipService>();
    
Please Sign in or register to post replies

Write your reply to:

Draft