하나의 인스턴스를 복수의 서비스 타입으로 주입 받기

아래와 같은 상속 구조가 있다고 할 때,

interface IModel{}
abstract BaseModel{}
class Model : BaseModel, IModel {}

scoped 범위로 등록된 Model 인스턴스를 IModel 로도, BaseModel 로도 받을 수 있는 방법이 있을까요?

예를 들면, 아래 두 객체는 scoped 범위에서 동일한 인스턴스를 주입받아야 합니다.

//A 클래스
IModel _model;
public A(IModel model) => _model = model;

//B 클래스
BaseModel _model;
public B(BaseModel model) => _model = model; 

아래와 같이 등록하면, 서로 다른 Model 인스턴스가 주입되어 원하는 방향이 아닙니다.

...services.AddScoped<IModel, Model>();
...services.AddScoped<BaseModel, Model>();

AddSingleton 은 조건 위반입니다. Factory 도 제가 원하는 것은 아닙니다.
닷넷의 서비스 컨테이너의 사용 법 중에 이런 용도에 부합하는 것이 존재하는 지를 여쭙는 것입니다.

고수님들의 고견 기다리겠습니다.

1개의 좋아요

검색을 해보니 이런 방법도 있네요

services.AddScoped<Model>();

services.AddScoped<IModel>(sp => sp.GetRequiredService<Model>());
services.AddScoped<BaseModel>(sp => sp.GetRequiredService<Model>());

예제를 봐도 도통 모르겠다는건 함정이네요!! :scream:

3개의 좋아요

.net clean architecture 오픈소스 코드 분석하다가 알게됐는데

위와 같이 서비스를 등록하면 Middleware 단에서 ICurrentUserInitializer를 DI 받아서 사용하고 CQRS 핸들러 단에서 ICurrentUser를 DI 받아서 같은 인스턴스로 사용을 할 수 있더라고요!

3개의 좋아요

보여주신 코드가 Factory 입니다.
Func 대리자 형식의 변수 명에 Factory 들어 간 거 보이시죠?

public static IServiceCollection AddScoped<TService>(
    this IServiceCollection services,
    Func<IServiceProvider, TService> implementationFactory)
    where TService : class

IServiceProvider는 서비스 컨테이너 객체를 의미하고, 그 객체의 GetRequiredService<T>()를 호출하면, 컨테이너에 등록된 T 형식의 인스턴스를 반환합니다.

답변 감사합니다.

1개의 좋아요

예 저 메서드도 Factory 를 사용한 것입니다.

        public static IServiceCollection AddScoped<TService>(
            this IServiceCollection services,
            Func<IServiceProvider, TService> implementationFactory)
            where TService : class
        {
            ThrowHelper.ThrowIfNull(services);
            ThrowHelper.ThrowIfNull(implementationFactory);

            return services.AddScoped(typeof(TService), implementationFactory);
        }

AddScoped<TService>에서 TService 가 생략된 것은, (Func<IServiceProvider, TService> implementationFactory) 에서 TService를 유추할 수 있기 때문입니다.

답변 감사합니다.

1개의 좋아요

위의 두분의 답변 처럼

Func<IServiceProvider, TService> 인자를 받아서 GetRequiredService()로 동일한 인스턴스를 사용하는 것이 가장 원하는 동작일텐데 이 방식을 지양하는 이유가 있나요?

1개의 좋아요

제가 모르는 좀 더 간편한 방법이 있는 지 여쭤 보는 것입니다.

1개의 좋아요