Cześć,
Jakiś czas temu postanowiłem przyjrzeć się nieco technologii .NET Core. W związku z tym podjąłem decyzję o zrealizowaniu pewnego projektu ww. technologii. Na chwilę obecną chciałbym utworzyć sobie jakiś test integracyjny. Oto fragmenty mojego kodu:
public class CustomWebApplicationFactory: WebApplicationFactory<MyApp.Startup>
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
var dbContextOptionsServiceDescriptors = services
.Where(sd => sd.ServiceType.BaseType == typeof(DbContextOptions))
.ToList();
foreach (var sd in dbContextOptionsServiceDescriptors)
{
services.Remove(sd);
}
var databaseName = "MyAppInMemoryDatabaseForTests";
services.AddDbContext<MainDbContext>(c => c.UseInMemoryDatabase(databaseName));
});
}
}
public class SampleTests:
IClassFixture<CustomWebApplicationFactory>
{
private readonly CustomWebApplicationFactory _factory;
public SampleTests(CustomWebApplicationFactory factory)
{
_factory = factory;
}
[Fact]
public void SampleTest()
{
using (var scope = _factory.Services.CreateScope())
{
var service = scope.ServiceProvider.GetRequiredService<IMyService>();
}
}
}
Klasa SampleTests
zawiera poniższy fragment kodu:
using (var scope = _factory.Services.CreateScope())
{
var service = scope.ServiceProvider.GetRequiredService<IMyService>();
}
Z tego co wiem, powinno się wywoływać metodę Dispose
na obiektach implementujących interfejs IDisposable
(bezpośrednio lub za pośrednictwem słowa kluczowego using
).
Problem jednak w tym, że property Service
zwraca obiekt implementujący IServiceProvider
, który akurat implementuje też interfejs IDisposable
, a metoda CreateScope
zwraca kolejny obiekt implementujący IServiceScope
, który również akurat implementuje interfejs IDisposable
(czyli razem mam dwa obiekty implementujące interfejs IDisposable
). W związku z powyższym mam pytanie czy powyższy kod jest poprawny czy należy raczej przekształcić go do poniższej postaci?
using (var serviceProvider = _factory.Services)
{
using (var scope = serviceProvider.CreateScope())
{
var service = scope.ServiceProvider.GetRequiredService<IMyService>();
}
}
Ponadto załóżmy na chwilę, że metoda CreateScope
zwraca obiekt implementujący IServiceScope
, który akurat nie implementuję interfejsu IDisposable
. Wtedy nie musiałbym używać słowa kluczowego using
. Jednak po jakimś czasie ktoś może zmienić kod źródłowy metody CreateScope()
w taki sposób aby metoda zwracała obiekt implementujący interfejs IDisposable
. Co wtedy? Zasoby nigdy się nie zwolnią? Zasoby zwolnią się ale nie wiadomo kiedy? Jak się przed czymś takim uchronić?