以编程方式注入asp.net核心的依赖项 [英] Injecting Dependency programmatically asp.net core

查看:73
本文介绍了以编程方式注入asp.net核心的依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只是从 Asp.net核心 依赖注入开始,我的概念可能不准确.这篇docs.asp.net帖子解释了如何向控制器注入上下文.从测试的角度来看,我对注入几乎没有困惑.假设我们有以下情形:

I'm just starting with Asp.net core Dependency Injection, and my concept could be inaccurate. This docs.asp.net post explains how to inject context to a controller. I have little confusion regarding injection, in testing perspective. Assume we have following scenario:

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;
   }
}

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

Now in order to inject context in controller, we design it as:

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

    public TodoController(ITaskRepository taskItems)
    {
        TaskItems = taskItems;
    }
    //other logic
 }

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

What asp.net core provides as builtin feature is, we can register the dependency injection in startup class as follows:

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

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

According to this logic, my TaskRepositoryFake will be injected to the controller. So far, everything is clear. My questions/confusions regarding this are as follows:

问题:

  • 如何使用此内置的DI功能通过一些逻辑注入上下文?可能是基于程序的,还是基于配置的,还是基于环境的?(例如,在使用测试"环境时,总是注入伪造的上下文吗?等)
  • 有可能吗?如果我们总是必须在 StartUp 类中手动更改此设置,那么此内置DI功能如何为我们服务?因为我们可以简单地在控制器中完成此操作,而无需此功能.
  • How can I use this builtin DI feature to inject the context using some logic? May be programatically, or configuration based, or environment based? (for example, always inject fake context, when using 'test' environment? etc.)
  • Is it even possible? If we always have to change this manually in StartUp class, then how does this builtin DI feature serve us? Because we could have simply done that in controller, without this feature.

推荐答案

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

First to answer your question: Yes, you can inject the dependency programmatically. By using factories, as is always the case with injecting dependencies based on run-time values. The AddSingleton has an overload which takes an implementationfactory and so a basic example for your use case looks like:

   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);
}

与TasksRepository有关的代码行如下所示:

The concerning line of code for your TasksRepository would look like:

services.AddSingleton<ITaskRepository>(sp => isTesting?(ITasksRepository)new TasksRepositoryFake(): (ITasksRespository)new TasksRepository() );

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

Even better would be to put it in a factory (again with my example):

services.AddSingleton<ISomeRepository>(sp => SomeRepositoryFactory.CreatSomeRepository(IsTesting));

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

I hope you see how this helps you setting it up config based, environment based, or however you want. I you are interested I wrote more about DI based on run-time values via abstract factories here.

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

Having said that, with unit tests I would simply inject my fakes in the classes that are under test. Unit tests are there to still prove to yourself and your co-workers that the code still does as intended. And with integration tests I would make a special StartUp class with all my fakes and give it to the test host as ASP.NET Core allows you to do. You can read more about the test host here: https://docs.asp.net/en/latest/testing/integration-testing.html

希望这会有所帮助.

更新,因为三元条件无法说明,所以将强制类型转换添加到接口.另外还添加了一些基本示例.

Update Added cast to interface because the ternary conditional has no way of telling. Plus added some basic samples.

这篇关于以编程方式注入asp.net核心的依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆