以编程方式注入asp.net核心的依赖项

Zee*_*han 5 c# dependency-injection asp.net-core

我只是从Asp.net core Dependency Injection开始,我的概念可能不准确。这篇docs.asp.net帖子介绍了如何将上下文注入控制器。从测试角度看,我对注入几乎没有困惑。假设我们有以下情形:

public interface ITasksRepository
{ 
   public void Create();
}

//This is fake implementation, using fake DbContext for testing purpose
public class TasksRepositoryFake : ITasksRepository
{
   public void Create()
   {
     FakeDbContext.Add(sometask);
     //logic;
   }
}

//This is actual implementation, using actual DbContext
public class TasksRepository : ITasksRepository
{
   public void Create()
   {
     DbContext.Add(someTask);
     //logic;
   }
}
Run Code Online (Sandbox Code Playgroud)

现在,为了在控制器中注入上下文,我们将其设计为:

public class TasksController : Controller
{
    public ITasksRepository TaskItems { get; set; }

    public TodoController(ITaskRepository taskItems)
    {
        TaskItems = taskItems;
    }
    //other logic
 }
Run Code Online (Sandbox Code Playgroud)

asp.net core提供的内置功能是,我们可以在启动类中注册依赖项注入,如下所示:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddMvc();
    services.AddSingleton<ITasksRepository, TasksRepositoryFake>();
}
Run Code Online (Sandbox Code Playgroud)

根据此逻辑,我TaskRepositoryFake将被注入控制器。到目前为止,一切都很清楚。我对此的疑问/困惑如下:

问题:

  • 如何使用此内置的DI功能使用某些逻辑来注入上下文?可能是编程方式,还是基于配置,还是基于环境?(例如,在使用“测试”环境时,总是注入伪造的上下文吗?等)
  • 可能吗 如果我们总是必须在StartUp类中手动更改此设置,那么此内置的DI功能如何为我们服务?因为我们可以简单地在控制器中完成此操作,而无需此功能。

Dan*_*aan 5

首先回答您的问题:是的,您可以通过编程方式注入依赖项。通过使用工厂,通常会基于运行时值注入依赖项。AddSingleton有一个需要执行工厂的重载,因此您的用例的基本示例如下:

   public class Startup
{
    public bool IsTesting { get; }

    public Startup(IHostingEnvironment env)
    {
        IsTesting = env.EnvironmentName == "Testing";
    }

    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit http://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddSingleton<ISomeRepository>(sp => IsTesting ? (ISomeRepository)new SomeRepository() : (ISomeRepository) new FakesomeRepository());
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, ISomeRepository someRepository)
    {
        app.UseIISPlatformHandler();

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync($"Hello World from {nameof(someRepository)}!");
        });
    }

    // Entry point for the application.
    public static void Main(string[] args) => WebApplication.Run<Startup>(args);
}
Run Code Online (Sandbox Code Playgroud)

您的TasksRepository的代码行如下所示:

services.AddSingleton<ITaskRepository>(sp => isTesting?(ITasksRepository)new TasksRepositoryFake(): (ITasksRespository)new TasksRepository() );
Run Code Online (Sandbox Code Playgroud)

更好的方法是将其放入工厂(同样以我的示例为例):

services.AddSingleton<ISomeRepository>(sp => SomeRepositoryFactory.CreatSomeRepository(IsTesting));
Run Code Online (Sandbox Code Playgroud)

我希望您能看到它如何帮助您将其设置为基于配置,基于环境或您想要的设置。如果您有兴趣,我在这里通过抽象工厂撰写了更多有关基于运行时值的DI的文章。

话虽如此,通过单元测试,我只是将伪造品注入正在测试的类中。在那里进行单元测试仍然可以向您自己和您的同事证明代码仍然按预期运行。并通过集成测试,我将使用所有假货创建一个特殊的StartUp类,并将其提供给测试主机,因为ASP.NET Core允许您这样做。您可以在此处阅读有关测试主机的更多信息:https : //docs.asp.net/en/latest/testing/integration-testing.html

希望这可以帮助。

更新将强制类型转换添加到接口,因为三元条件无法分辨。加上添加了一些基本示例。