아래와 같은 상속 구조가 있다고 할 때,
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 Like
검색을 해보니 이런 방법도 있네요
services.AddScoped<Model>();
services.AddScoped<IModel>(sp => sp.GetRequiredService<Model>());
services.AddScoped<BaseModel>(sp => sp.GetRequiredService<Model>());
예제를 봐도 도통 모르겠다는건 함정이네요!!
3 Likes
.net clean architecture 오픈소스 코드 분석하다가 알게됐는데
: services.AddJwtAuth();
}
internal static IApplicationBuilder UseCurrentUser(this IApplicationBuilder app) =>
app.UseMiddleware<CurrentUserMiddleware>();
private static IServiceCollection AddCurrentUser(this IServiceCollection services) =>
services
.AddScoped<CurrentUserMiddleware>()
.AddScoped<ICurrentUser, CurrentUser>()
.AddScoped(sp => (ICurrentUserInitializer)sp.GetRequiredService<ICurrentUser>());
private static IServiceCollection AddPermissions(this IServiceCollection services) =>
services
.AddSingleton<IAuthorizationPolicyProvider, PermissionPolicyProvider>()
.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();
}
위와 같이 서비스를 등록하면 Middleware 단에서 ICurrentUserInitializer를 DI 받아서 사용하고 CQRS 핸들러 단에서 ICurrentUser를 DI 받아서 같은 인스턴스로 사용을 할 수 있더라고요!
3 Likes
보여주신 코드가 Factory 입니다.
Func 대리자 형식의 변수 명에 Factory 들어 간 거 보이시죠?
public static IServiceCollection AddScoped<TService>(
this IServiceCollection services,
Func<IServiceProvider, TService> implementationFactory)
where TService : class
IServiceProvider는 서비스 컨테이너 객체를 의미하고, 그 객체의 GetRequiredService<T>()를 호출하면, 컨테이너에 등록된 T 형식의 인스턴스를 반환합니다.
답변 감사합니다.
1 Like
예 저 메서드도 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 Like
dimohy
September 3, 2023, 4:23am
6
위의 두분의 답변 처럼
Func<IServiceProvider, TService>
인자를 받아서 GetRequiredService()
로 동일한 인스턴스를 사용하는 것이 가장 원하는 동작일텐데 이 방식을 지양하는 이유가 있나요?
1 Like
제가 모르는 좀 더 간편한 방법이 있는 지 여쭤 보는 것입니다.
1 Like