.NET Core 2.0 Modular Dependency Injection

2019-06-09 07:40发布

I am trying to build a library that has core and extensions packages like Entity Framework and its database providers.

What I am trying to do is when I register that library with dependency injection, I want to give specific implementation as a parameter.

Think EF. In order to use sql provider on EF we need to register it with SQL provider passed as option parameter like the following.

services.AddDbContext<ApplicationDbContext>(options =>
{
   options.UseSqlServer(Configuration["ConnectionString"]);
});

I would like to build similar structure. Lets say my framework will provide film producer. It will have producer.core package for framework related classes and two extensions package called Producer.Extensions.Hollywood and Producer.Extensions.Bollywood.

If I want to use Hollywood provider, I need to install core package and Hollywood extension package. On registration it should look like

services.AddFilmProducer(options =>
{
   options.UseHollywoodProducer();
});

I could not find even a keyword that will point me a direction. I tried to read entity framework's source code but it is too complicated for my case.

Is there anyone who could point me a direction?

Thanks in advance.

1条回答
ゆ 、 Hurt°
2楼-- · 2019-06-09 08:01

I'm not sure if I completely understand your requirements, but DI and extensions are an easy thing in .net core.

Let's say you want this in your Startup.cs

services.AddFilmProducer(options =>
{
   options.UseHollywoodProducer();
});

To implements this, create your library and add a static extension class

public static class FilmProducerServiceExtensions
{
    public static IServiceCollection AddFilmProducer(this IServiceCollection services, Action<ProducerOptions> options)
    {
        // Create your delegate
        var producerOptions = new ProducerOptions();
        options(producerOptions);

        // Do additional service initialization
        return services;
    }
}

where your ProducerOptions implementation might look like

public class ProducerOptions
{
    public void UseHollywoodProducer() 
    { 
        // Initialize hollywood
    }

    public void UseBollywoodProducer() 
    { 
        // Initialize bollywood
    }
}

If you wish to use the passed ProducerOptions in your service, there are two ways to do it. Either use dependency injection again, or directly access the service by using service provider in your extension method

var serviceProvider = services.BuildServiceProvider()
IYourService service = sp.GetService<IYourService>();

And now you have the original Use piece of initialization working.

Hope it helps.

Edit:

To clarify. To inject your options in the service, you can use

services.Configure(ProducerOptions);

in your extension method, and pass to your service constructor via

public YourService(IOptions<ProducerOptions>)

You can then simplify or complicate your options as much as you want.

A useful link for this kind of extensions might be the CORS repository for .net core: https://github.com/aspnet/CORS

Edit after comments:

I think I've got it now. You want packages to extend and implement specific options, kind of like what serilog does with different sinks. Piece of cake.

Scrap the ProducerOptions implementation.

Lets say you have a base package with initial empty structures (BaseProducer library) and an interface

public interface IProducerOptions
{
    // base method signatures
}

Your service extension now becomes

public static class FilmProducerServiceExtensions
{
    public static IServiceCollection AddFilmProducer(this IServiceCollection services, Action<IProducerOptions> options)
    {
        // Do additional service initialization
        return services;
    }
}

Now you create a new package with specific "Hollywood producer" options and you want to extend the base option set

public static class HollyWoodExtensions
{
    public static void UseHollywoodProducer(this IProducerOptions options)
    {
        // Add implementation
    }
}

Create as many packages and IProducerOptions extensions as you like, and the added methods will start appearing in your Startup.cs

services.AddFilmProducer(options =>
{
   options.UseHollywoodProducer();
});
查看更多
登录 后发表回答