2016-08-21 4 views
1

저는 Asp.net core의존성 주입으로 시작하고 있습니다. 내 개념이 부정확 할 수 있습니다. This docs.asp.net post 컨트롤러에 컨텍스트를 주입하는 방법을 설명합니다. 나는 테스트 관점에서 주입에 관한 혼란이 거의 없다. core이 같은 내장 기능이 제공 무엇 asp.net의존성을 프로그래밍 방식으로 프로그래밍 asp.net 코어

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

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

우리는 의존성을 등록 할 수 있습니다 :로

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

이제 컨트롤러 컨텍스트를 주입하기 위해, 우리는 그것을 설계 : 우리는 다음과 같은 시나리오를 가정 기동 클래스 주입으로 다음과이 논리에 따르면

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

TaskRepositoryFake 컨트롤러에 주입한다. 지금까지 모든 것이 명확합니다.

질문 : 나는 몇 가지 논리를 사용하여 컨텍스트를 주입하는이 내장 된 DI 기능을 사용할 수 있습니다 어떻게

  • 다음과 같이이에 대한 내 질문/혼란은? 프로그래밍 방식 또는 구성 기반 또는 환경 기반 일 수 있습니까? (예 : '테스트'환경을 사용할 때 가짜 컨텍스트를 삽입하십시오.)
  • 심지어 가능합니까? StartUp 클래스에서이 값을 수동으로 변경해야한다면 DI 내장 기능이 어떻게 작동합니까? 왜냐하면 우리는이 기능없이 컨트롤러에서 간단하게 할 수 있었기 때문입니다.

답변

3

첫 번째 질문에 대답 : 예, 프로그래밍 방식으로 종속성을 주입 할 수 있습니다. 팩토리를 사용하여 런타임 값을 기반으로 종속성을 주입하는 경우는 항상 그렇습니다. 더 나은

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

것 :

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에 대한 코드의 관련된 라인의 모습 다음 AddSingleton는 implementationfactory을 취하고 있으므로 사용 사례에 대한 기본적인 예처럼 보이는 과부하가 있습니다 (내 예를 다시) 공장에 넣어 수 :

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

을 나는 당신이 당신이 기준으로 설정 그것을 설정하는 데 도움이 방법을 볼 희망, 환경 기반, 또는 방법 이제까지 너는 원한다. 관심이 있으십니까? 추상적 인 공장을 통해 런타임 값을 기반으로 DI에 대해 더 자세히 썼습니다 here.

그런데 단위 테스트를 통해 테스트중인 클래스에 가짜 코드를 삽입하기 만하면됩니다. 단위 테스트는 여전히 코드가 의도 한대로 작동한다는 것을 자신과 동료에게 증명합니다. 그리고 통합 테스트를 통해 모든 가짜로 특수 StartUp 클래스를 만들고 ASP.NET Core에서 수행 할 수 있도록 테스트 호스트에 제공했습니다. 테스트 호스트에 대한 자세한 내용은 여기를 참조하십시오. https://docs.asp.net/en/latest/testing/integration-testing.html

희망이 있습니다.

업데이트 터너리 조건부에 알림이 없기 때문에 인터페이스에 캐스트를 추가했습니다. 또한 몇 가지 기본 샘플을 추가했습니다.

+0

감사 대니 :

public IConfigurationRoot Configuration { get; set; } public Startup() { var builder = new ConfigurationBuilder() .SetBasePath(env.ContentRootPath) .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) .AddEnvironmentVariables(); Configuration = builder.Build(); } public void ConfigureServices(IServiceCollection services) { var isFakeMode= Configuration["ServiceRegistrationMode"] == "Fake"; if (isFakeMode) { // register other fake dependencies services.AddSingleton<ITasksRepository, TasksRepositoryFake>(); } else { // register other real dependencies services.AddSingleton<ITasksRepository, TasksRepository>(); } } 

옵션 3 구성 기준으로합니다. 제안을 구현하려고하지만 이상한 오류가 발생합니다. (아마 당신의 논리에 있지는 않지만 내 편이라.) 일단 성공하면, 대답을 표시 할 것입니다. 그리고 오류는 : .. .. TaskRepositoryFake와 TaskRepository' 사이에 암묵적인 변환이 없습니다. 나는 정확히 내가 말한 것과 같은 구현을 가지고있다. 나는이 특정한 시나리오에서 이것을 허락한다면 내 말을 들으면서 다시 한번 확인해 볼 수있다. – Zeeshan

+0

이제 ITaskRepository가 클래스라는 것을 알았습니다. 인터페이스라고하셨습니까? 그것보다 위의 코드를 정확히 복사하지 않은 것 같습니다. 왜냐하면 내 코드 라인에서는 결코 TaskRepository를 TaskRepositoryFake (또는 그 반대로)로 변환하려고 시도하지 않기 때문입니다. 따라서 신중히 확인하십시오. –

+0

여기에는 오타가 있습니다. 'ITaskRepository'는 실제로 인터페이스입니다. 그렇지 않으면 클래스는 메서드 시그니처뿐만 아니라 정의도 가질 수 없으므로 컴파일 오류가 발생합니다. 난 정확히 당신이 제공 한 논리를 사용하고 있지만 여전히 오류 :(.. 기술적으로, 거기에 'TaskRepository'과'TaskRepositoryFake', 모두'ITaskRepository' 인터페이스를 구현하는 등의 오류가 있어서는 안됩니다. – Zeeshan

2

기반 또는 환경 기반 또는 둘 모두로 종속성 구성을 주입 할 수 있습니다.

옵션 1 : 환경 기반은

public IHostingEnvironment env{ get; set; } 
    public Startup(IHostingEnvironment env) 
    { 
     this.env = env; 
    } 
    public void ConfigureServices(IServiceCollection services) 
    { 
     if (env.IsDevelopment()) 
     { 
      // register other fake dependencies 
      services.AddSingleton<ITasksRepository, TasksRepositoryFake>(); 
     } 
     else 
     { 
      // register other real dependencies 
      services.AddSingleton<ITasksRepository, TasksRepository>(); 
     } 
    } 

옵션 2 : 환경 기반 + 구성 기반

public IConfigurationRoot Configuration { get; set; } 
    public IHostingEnvironment env{ get; set; } 
    public Startup(IHostingEnvironment env) 
    { 
     this.env = env; 
     var builder = new ConfigurationBuilder() 
      .SetBasePath(env.ContentRootPath) 
      .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true) 
      .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true) 
      .AddEnvironmentVariables(); 
     Configuration = builder.Build(); 
    } 
    public void ConfigureServices(IServiceCollection services) 
    { 
     var isFakeMode = Configuration["ServiceRegistrationMode"] == "Fake"; 
     if (env.IsDevelopment() && isFakeMode) 
     { 
      // register other fake dependencies 
      services.AddSingleton<ITasksRepository, TasksRepositoryFake>(); 
     } 
     else 
     { 
      // register other real dependencies 
      services.AddSingleton<ITasksRepository, TasksRepository>(); 
     } 
    } 
+0

'ConfigureServices'는 둘 이상의 params를 가질 수 없으며, 예외를 던진다. : 메시지가있는'System.InvalidOperationException' 'ConfigureServices 메소드는 매개 변수가 없거나 IServiceCollection 유형의 매개 변수 하나만 가져야합니다. ' – Zeeshan

+0

죄송합니다, 고정 코드 –

+0

Adem에게 감사하지만, 여전히 옵션 1과 옵션에는 문제가 있습니다. 3. 당신은 어디에서 변수'env'를 얻었습니까? 범위에 정의되어 있지 않으므로 예외를줍니다. – Zeeshan

관련 문제