Base solution for your next web application
Open Closed

Dependency Injection Strategy #8758


User avatar
0
murat.yuceer created

Hello, I need some advice for best practice sulution about dependecy resolving. I have one interface is IEdmModelProvider Multiple classes could consume this interface but these classes could contain some diffirent signature constructure parameters When client consume IEdmModelProvider, it could want to pass strategy in runtime (also client will need to pass constructure parameters), also client could select strategy when application starting (will need to pass constructure parameters)

I implemented it with factory pattern but i need to see your sulutions with boilerplate infrastructure.

Thank you

public interface IEdmModelProvider
{
    IEdmModel GetModel();
}

public class EdmModelDBContextProvider : IEdmModelProvider
{
    private readonly IServiceProvider _serviceProvider;

    public EdmModelDBContextProvider(IServiceProvider serviceProvider)
    {
        _serviceProvider = serviceProvider;
    }

    public IEdmModel GetModel()
    {
        var odataBuilder = new ODataConventionModelBuilder(_serviceProvider, true);
        odataBuilder.EntitySet<UserTask>("UserTasks");
        return odataBuilder.GetEdmModel();
    }
}

public class EdmModelODataUriProvider : IEdmModelProvider
{
    private readonly Uri _oDataUri;

    public EdmModelODataUriProvider(Uri oDataUri)
    {
        _oDataUri = oDataUri;
    }
    
    public IEdmModel GetModel()
    {
        var request = WebRequest.CreateHttp(_oDataUri);
        .....
        return model;
    }

}


12 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team

    abp uses Castle Windsor as DI, you can use more advanced features of Castle Windsor. Such as named components.

    https://github.com/aspnetboilerplate/aspnetboilerplate/issues/805

  • User Avatar
    0
    murat.yuceer created

    Hi,

    How would you do if you wanted to resolve that with factory pattern, also if i register some interface with native .net core provider could i resolve back with castle windsor container (i mean could i work mix them)

  • User Avatar
    0
    maliming created
    Support Team

    How would you do if you wanted to resolve that with factory pattern,

    https://stackoverflow.com/questions/25062673/why-would-you-use-windsor-asfactory/25066327 https://stackoverflow.com/questions/11726663/passing-part-of-constructor-parameters-to-castle-windsor-container/11734671

    For more information you can check Windsor's documentation.

    https://github.com/castleproject/Windsor/blob/master/docs/README.md



    also if i register some interface with native .net core provider could i resolve back with castle windsor container (i mean could i work mix them)

    In asp net core will be taken over by the castle windsor for DI work.

    In other words, dependency injection of asp net core is extensible and replaceable.

    https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1#default-service-container-replacement

  • User Avatar
    0
    murat.yuceer created

    Thank you for informations

  • User Avatar
    0
    maliming created
    Support Team

    There is also an article about dependency injection you can check out.

    https://volosoft.com/blog/ASP.NET-Core-Dependency-Injection-Best-Practices,-Tips-Tricks

  • User Avatar
    0
    murat.yuceer created

    After read documents i designed like that i hope its right way, Firstly my purpose is, giving options to who consume interface (client can decide which class will inject interface or client can decide to inject it with default behaviour for application)

    This interface could implement with multiple classes

    public interface IEdmModelProvider
    {
        IEdmModel GetModel();
    }
    

    Implemented classes as follows

    public class EdmModelDBContextProvider : IEdmModelProvider
    {
        private readonly IServiceProvider _serviceProvider;
    
        public EdmModelDBContextProvider(IServiceProvider serviceProvider)
        {
            _serviceProvider = serviceProvider;
        }
    
        public IEdmModel GetModel()
        {
            var odataBuilder = new ODataConventionModelBuilder(_serviceProvider, true);
            odataBuilder.EntitySet<UserTask>("UserTasks");
            return odataBuilder.GetEdmModel();
        }
    }
    

    Important, this class have constructor parameter

    public class EdmModelODataUriProvider : IEdmModelProvider
    {
        private readonly Uri _oDataUri;
        private readonly IEdmModel _edmModel;
    
        public EdmModelODataUriProvider(Uri oDataUri)
        {
            _oDataUri = oDataUri;
    
            _edmModel = InitModel();
        }
    
        private IEdmModel InitModel()
        {
            .......
        }
    
        public IEdmModel GetModel()
        {
            return _edmModel;
        }
    }
    

    I created factory class, Create method default option maybe will come from config flile

        public interface IEdmModelProviderFactory
    {
        IEdmModelProvider Create();
    
        IEdmModelProvider CreateODataUriProvider(Uri odataUri);
    
        IEdmModelProvider CreateDBContextProvider();
    }
    
    public class EdmModelProviderFactory : IEdmModelProviderFactory
    {
        private readonly IIocResolver _iocResolver;
    
        public EdmModelProviderFactory(IIocResolver iocResolver)
        {
            _iocResolver = iocResolver;
        }
    
        public IEdmModelProvider Create()
        {
            //return CreateDBContextProvider();
            return CreateODataUriProvider(new Uri("https://services.odata.org/Experimental/Northwind/Northwind.svc/$metadata"));
        }
    
        public IEdmModelProvider CreateODataUriProvider(Uri odataUri)
        {
            using (var provider = _iocResolver.ResolveAsDisposable<EdmModelODataUriProvider>(new { odataUri = odataUri }))
            {
                return provider.Object;
            }
        }
    
        public IEdmModelProvider CreateDBContextProvider()
        {
            using (var provider = _iocResolver.ResolveAsDisposable<EdmModelDBContextProvider>())
            {
                return provider.Object;
            }
        }
    }
    

    And i register them as follow (I didnt register IEdmModelProvider, because i want resolve it only from factory)

            public static void AddODataServices(this IIocManager iocManager)
        {
            iocManager.Register<EdmModelODataUriProvider>(DependencyLifeStyle.Transient);
            iocManager.Register<EdmModelDBContextProvider>(DependencyLifeStyle.Transient);
            iocManager.Register<IEdmModelProviderFactory, EdmModelProviderFactory>(DependencyLifeStyle.Transient);
          } 
           
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi,

    CreateDBContextProvider is creating provider in a using statement, so it will be disposed before returning the value. Using a factory is a good way to handle this.

  • User Avatar
    0
    murat.yuceer created

    Hi @ismcagdas, if it will be disposed before returning the value, how it is not return null value?

  • User Avatar
    0
    maliming created
    Support Team

    hi @murat.yuceer

    I think garbage collection may recycle it at any time. Do not use objects returned by ResolveAsDisposable outside the scope of using.

  • User Avatar
    0
    murat.yuceer created

    I saw that in ExternalLoginInfoManagerFactory, i guess its most logical way

        public IDisposableDependencyObjectWrapper<IExternalLoginInfoManager> GetExternalLoginInfoManager(string loginProvider)
        {
            if (loginProvider == "WsFederation")
            {
                return _iocManager.ResolveAsDisposable<WsFederationExternalLoginInfoManager>();
            }
    
            return _iocManager.ResolveAsDisposable<DefaultExternalLoginInfoManager>();
        }
    
  • User Avatar
    0
    ismcagdas created
    Support Team

    But, this is not in a using statement. GetExternalLoginInfoManager will be used in a using statement as we do here

  • User Avatar
    0
    murat.yuceer created

    Yes, i saw i will use "using" when i consume factory method from manager. Thanks