Scoped
수명을 사용하여 Entity Framework 컨텍스트 를 서비스 컨테이너에 추가 해야 합니다. 위와 같이 헬퍼 메서드를 사용하면 자동으로 처리됩니다. Entity Framework를 사용할 저장소는 동일한 수명을 사용해야합니다.
나는 항상 내가 처리해야하는 모든 단일 작업 단위에 대해 새로운 Context
를 만들어야한다고 생각했습니다. 이것은 내가 DbContext
의 다른 인스턴스를 DbContext
한다는 DbContext
에 다른 액션을 적용하는 ServiceA
와 ServiceB
가지고 있다고 생각합니다.
설명서 는 다음과 같이 읽습니다.
Transient
객체는 항상 다릅니다. 새로운 인스턴스가 모든 컨트롤러와 모든 서비스에 제공됩니다.
Scoped
개체는 요청 내에서 동일하지만 요청에 따라 다릅니다.
ServiceA
와 ServiceB
돌아 가면 나에게 들리지만 Transient
가 더 적합합니다.
컨텍스트가 HttpRequest
당 한 번만 저장되어야한다는 것을 조사했지만 실제로 어떻게 작동하는지 이해할 수 없습니다.
특히 우리가 하나의 서비스를 살펴 본다면 :
using (var transaction = dbContext.Database.BeginTransaction())
{
//Create some entity
var someEntity = new SomeEntity();
dbContext.SomeEntity.Add(someEntity);
//Save in order to get the the id of the entity
dbContext.SaveChanges();
//Create related entity
var relatedEntity = new RelatedEntity
{
SomeEntityId = someEntity.Id
};
dbContext.RelatedEntity.Add(relatedEntity)
dbContext.SaveChanges();
transaction.Commit();
}
여기서 우리는 방금 생성 한 다른 것과 관련된 Entity의 ID를 얻기 위해 컨텍스트를 저장해야합니다.
동시에 다른 서비스가 동일한 컨텍스트를 업데이트 할 수 있습니다. 읽은 DbContext
는 스레드로부터 안전하지 않습니다.
이 경우 Transient
를 사용해야합니까? 문서가 제안하는 이유는 무엇입니까? Scoped
를 사용해야합니까?
프레임 워크의 중요한 부분을 놓치고 있습니까?
다른 사람이 이미 설명한 바와 같이, 당신은 제대로 다시 사용됩니다 확인하기 위해 데이터베이스 컨텍스트에 대한 범위 의존성을 사용해야합니다. 병행성에 대해서도 데이터베이스를 비동기 적으로 쿼리 할 수 있으므로 실제 스레드가 필요하지 않을 수 있습니다.
당신이 스레드, 즉 배경 작업자를 필요로 한다면, 그것들은 요청보다 수명이 다를 가능성이 높습니다. 따라서 이러한 스레드는 요청 범위에서 검색 한 종속성을 사용 하지 않아야 합니다. 요청이 끝나고 종속성 범위가 닫히면 일회용 종속성이 적절히 처리됩니다. 다른 스레드의 경우 이는 종속성이 여전히 필요하지만 정리가 완료 될 수 있음을 의미합니다.
대신, 생성 한 모든 스레드에 대해 새 종속성 범위를 명시 적으로 열어야합니다. IServiceScopeFactory
를 삽입하고 CreateScope
사용하여 스코프를 생성하면됩니다. 결과 객체에는 종속성을 검색 할 수있는 서비스 공급자가 포함됩니다. 이것은 별도의 범위이기 때문에이 범위의 수명 동안 데이터베이스 컨텍스트와 같은 범위가 지정된 종속성이 다시 작성됩니다.
서비스 로케이터 패턴으로 들어가는 것을 피하려면 스레드가 실행하는 하나의 중앙 서비스를 가지고 모든 필요한 종속성을 함께 고려해야합니다. 스레드는 다음 작업을 수행 할 수 있습니다.
using (var scope = _scopeFactory.CreateScope())
{
var service = scope.ServiceProvider.GetService<BackgroundThreadService>();
service.Run();
}
BackgroundThreadService
와 그 모든 의존성은 종속성을받는 일반적인 의존성 주입 방법을 따를 수 있습니다.
나는 스코프 된 (scoped) 수명을 사용할 때 대부분의 경우 동시성 문제에 직면하지 않을 것이라고 생각한다. 예를 들어 게시하더라도 현재 요청의 서비스가 이후에 호출되므로 동시성 문제는 없습니다. 하나의 HTTP 요청 (범위)의 컨텍스트에서 2 개 이상의 서비스를 병렬로 실행할 수있는 경우를 상상해보십시오.
평생 동안 데이터를 저장하는 방법 (여기서는 간단 함). 인기있는 DI 프레임 워크의 평생 매니저를 살펴보면, 모두 똑같이 작동합니다. 이것은 일회용 패턴을 구현하는 객체와 같은 사전입니다. Transient 사용하기 get 객체 메소드는 항상 null을 반환하므로 DI는 요청할 때마다 DI가 새 인스턴스를 생성합니다. SingleInstance는 static concurrent dictionary와 같은 객체에 객체를 저장하므로 컨테이너는 인스턴스를 한 번만 생성 한 다음 기존 인스턴스를 수신합니다.
범위 지정은 일반적으로 범위 개체 가 생성 된 개체를 저장하는 데 사용됩니다. asp 순수한 파이프 라인에서는 일반적으로 요청 당 (파이프 라인을 통해 범위를 전달할 수 있음)
짧게하기 - 범위를 사용하는 것을 걱정하지 마십시오. 안전하며 요청에 따라 호출 할 수 있습니다.
제 설명에서 매우 단순 해 보였습니다. 소스 코드를보고 원하는 세부 정보를 찾을 수 있습니다. https://github.com/aspnet/DependencyInjection