Managing DbContext scope in wcf service without IOC? - c#

We are implementing ntier architecture for one of the project which uses EF6 ORM. DbContext scope is managed by ContextStoreFactory. Based on configuration ContextStoreFactory uses HttpContextStore/StaticContextStore to create DbContext. For console app its working fine. Now we planning for implemnting a wcf service with net.msmq binding which uses underneath services to process incoming request.
public class TestService : ITestService
{
public void ProcessPerson(Person person)
{
var repo = GetRepository();
var personService = new PersonService(repo);
personService.Process(person);
}
private IRepository GetRepository()
{
var context = ContextStoreFactory.GetContextStore().GetContext();//Calls OperationcontextStore
return new Repository(context);
}
}
I would like to manage the DbContext scope in wcf service. I come across many articles which says its best to use DBContext per call/operation. My sample OperationContextStore looks like follows. Please feel free to correct if it requires any correction.
public class OperationContextStore
{
public static readonly string ITEM_NAME = "DBCONTEXT-INSTANCES";
public DBContext GetContext()
{
if(!OperationContext.Current.OutgoingMessageProperties.ContainsKey(ITEM_NAME))
OperationContext.Current.OutgoingMessageProperties.Add(ITEM_NAME, new DBContext());
return (DBContext)OperationContext.Current.OutgoingMessageProperties[ITEM_NAME];
}
public void Dispose()
{}
}
I would like to know Is DbContext scope per call is valid in my scenario?
Is the approach to create Repository in my service method is valid?
Are there any best practices to wire this up without using IOC?

I know it's late to answer my own question and I will try to recollect what I did
I would like to know Is DbContext scope per call is valid in my scenario?
Yes,It was valid in my scenario.
Is the approach to create Repository in my service method is valid?
I ended up having IRepository as a property in my service class and did a property injection.
Are there any best practices to wire this up without using IOC?
I ended up writing my own utility. Please search for poor man's dependency injection.

Related

NET 5 and EF: how to use AddPooledDbContextFactory in liu of DbContext in services

I recently came across AddPooledDbContextFactory concept as part of my NET 5 self-education piece and am keen to implement it properly. However, I am not sure how to use it with generics that I generally use.
Example of my current setup:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<TestDbContext>(
(s, o) => o.UseNpgsql(Configuration.GetConnectionString("DatabaseConnection"))
.UseLoggerFactory(s.GetRequiredService<ILoggerFactory>()));
// other code //
}
my repository generic:
public class Repository<T> : IRepository<T> where T
{
private readonly TestDbContext _dbContext;
public Repository(TestDbContext dbContext)
{
_dbContext = dbContext;
}
public async Task Create(T entity)
{
await _dbContext.Set<T>().AddAsync(entity);
await _dbContext.SaveChangesAsync();
}
// other methods //
}
this is invoked in following manner as example:
public class WeatherForecastController : ControllerBase
{
private readonly IRepository<Test> testRepo;
public WeatherForecastController(IRepository<Test> testRepo)
{
this.testRepo= testRepo;
}
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> GetAsync()
{
await testRepo.Create(new Test { Name = "Superman" });
// other code
}
}
I would like to convert this to use the new AddPooledDbContextFactory concept but cannot find enough documentation to figure out how to do this.
Atm only thing that comes to mind is using statements at each method but that doesn't make sense.
Any advice on this?
Documentation is not yet complete and is in progress, you track this issue
https://github.com/dotnet/EntityFramework.Docs/issues/2523
You can also a look at the tests for AddPooledDbContextFactory to see how to register DbContext with
https://github.com/dotnet/efcore/search?q=AddPooledDbContextFactory
for example to register DbContext:
services.AddPooledDbContextFactory<TContext>(ob =>
ob.UseSqlServer("ConnectionString").EnableServiceProviderCaching(false), poolSize: 32)
Then in your class, inject an IDbContextFactory<TContext> and use it like this:
using(var context = _factory.CreateDbContext())
{
var orders = await context.Orders.Where(o => o.Id > 3).ToListAsync();
}
According to this post:
Note that the DbContext instances created in this way are not managed
by the application's service provider and therefore must be disposed
by the application
You can also check out this post to see how to use IDbContextFactory:
https://learn.microsoft.com/en-us/aspnet/core/blazor/blazor-server-ef-core?view=aspnetcore-5.0
#Aeseir your code looks good to me. You are following best practices and you don't need to change it.
You are using the Repository Pattern, so your Repository class has all of your query logic which helps create loosely coupled and maintainable code.
In your ConfigureServices, calling: services.AddDbContext<TestDbContext>() registers TestDbContext with Scoped service lifetime. This is the way that DbContext is designed to work, and it will also work well with ASP.NET controllers, since they have a Scoped lifetime as well.
You did not show your code for registering IRepository, but that service lifetime should be Scoped as well. Btw, you can tell BuildServiceProvider() to validate scope registrations:
builder.Services.BuildServiceProvider(validateScopes: true);
Since DbContext is designed to have a Scoped service lifetime, and since your IRepository and Controller services are Scoped as well, every request gets brand new:
Controller
IRepository
DbContext
Those services are used for the request and then Diposed. This is how ASP.NET is intended to work.
Apparently at some point, DbContext pooling has been introduced to improve performance. In this case, EF Core manages a pool of context instances for you and resets them after each request. This can improve performance, although in some situations, the benefit might be small. See MSDN documentation for more details.
I think for use with ASP.NET controllers (i.e. the code you posted above) all you need to do to take advantage of EF Core context pooling is call AddDbContextPool():
builder.Services.AddDbContextPool<ApplicationDbContext>(/* ... */);
However, if you needed to use DbContext in services registered with Singleton lifetime, then the pattern above would not work well. Because when a Scoped service gets used in a Singleton service, the Scoped service is essentially a Singleton. Each request would not get a new DbContext, nor a reset one from the pool. (See QUESTION below.)
In that case, you might want to use the DbContext factory pattern instead:
builder.Services.AddDbContextFactory<ApplicationDbContext>(/* ... */);
Or, if you want to use context pooling with a factory pattern:
builder.Services.AddPooledDbContextFactory<ApplicationDbContext>(/* ... */);
The DbContextFactory can then be used in other services through constructor injection. For example:
private readonly IDbContextFactory<ApplicationDbContext> _contextFactory;
public MyController(IDbContextFactory<ApplicationDbContext> contextFactory)
{
_contextFactory = contextFactory;
}
The injected factory can then be used to construct DbContext instances in the controller code. For example:
public void DoSomething()
{
using (var context = _contextFactory.CreateDbContext())
{
// ...
}
}
Keep in mind that when you call CreateDbContext(), context instances are not managed by the service provider and therefore must be disposed by the application. Hence you need to Dispose of them yourself, such as in the example above which does so with the using statement.
QUESTION
I am doing my best to understand this stuff and explain it, but I might be wrong, so please call out an inaccuracies in my post.
When using AddDbContextPool(), does the DbContext get registered as a Singleton or Scoped?
I found in MSDN documentation that it's effectively registered as a Singleton:
Context pooling works by reusing the same context instance across requests; this means that it's effectively registered as a Singleton, and the same instance is reused across multiple requests (or DI scopes). This means that special care must be taken when the context involves any state that may change between requests.
However, I have found that if AddDbContextPool() is used along with true for validatedScopes:
builder.Services.BuildServiceProvider(validateScopes: true)
When DbContext is consumed from another service which is registered as a Singleton, the following exception is thrown:
System.InvalidOperationException: 'Cannot consume scoped service 'ApplicationDbContext' from singleton 'IRepository'.'
Hence why I stated above that DbContext still gets Scoped service lifetime.

What is the best approach to define an HttpClient instance in a base class of a class library project?

There is an application which has 3 interfaces and whoever wants to use this app needs to implement these interfaces. I have created a class library project which has these interface implementations that I have inherited all from the same base class to be able to have a single HttpClient. Here is what I have done so far:
public class BaseProxy
{
protected static readonly HttpClient Client;
static BaseProxy()
{
Client = new HttpClient();
}
}
and I have used this Client in all derived classes to make GetAsync and PostAsync requests as follows:
public class XProxyImplementation
{
var response = Client.GetAsync(BaseUrl + "XXXApi/GetClientSettings/").Result;
response.EnsureSuccessStatusCode();
}
None of the methods in Web API are async by the way and I chose singleton solution because I don't want to use using block for each request. My question is should I go for a DI solution or is this code enough for an app which will be used internally? All suggestions for improvement are welcome.
I have read many answers regarding to using DI containers but this is just a class library with proxy implementations.
My other concern is even if I want to use DI, currently I am not able to introduce DI in my constructor classes because the other application that uses my implementations is looking for an empty constructor. When I try to pass HttpClient parameter to the constructor I get the following error:
The current type, System.Net.Http.HttpMessageHandler, is an abstract
class and cannot be constructed
The application which uses my dlls doesn't allow me to pass any parameters to constructor that uses any abstract classes. I guess this application uses Unity to make the handshake and in some way it looks for an empty constructor. Once I try to do the following changes I am getting the error:
public BaseProxy() : this(Service.HttpClient)
{
}
public XProxyImplementation(HttpClient client) : base(client)
{
}
That's why I actually prefered singleton instance to DI implementation.
DI? Yes
DI will enable testability of your proxy classes, whereas your current implementation cannot be unit-tested. It will also improve separation of concerns: remove the responsibility of controlling HttpClient lifetime from the proxy.
Typically, you would do something like this:
public abstract class BaseProxy
{
protected readonly HttpClient Client;
protected BaseProxy(HttpClient client)
{
Client = client;
}
// ... other members
}
public class XProxyImplementation : BaseProxy
{
public XProxyImplementation(HttpClient client) : base(client)
{
}
// ... other members
public Task SendRequest() // for example
{
return Client.GetAsync("....");
}
}
During the tests, you would initialize a different instance of HttpClient, injecting a test-friendly implementation of HttpMessageHandler:
// you implement TestHttpMessageHandler that aids your tests
var httpClient = new HttpClient(new TestHttpMessageHandler());
var proxyUnderTest = new XProxyImplementation(httpClient);
See this blog post for explanation of unit testing with HttpClient and HttpMessageHandler.
DI container? No
Now that we introduced dependency injection into your code, next question is, what injection mechanism should be used.
In your specific case, I would vote against coupling to any specific DI container, because you want your library to be consumed by many different applications, and you don't want to bloat their dependencies (an application might already be using a different DI container).
Moreover, since the code you posted is very simple, a full-blown DI container would be an overkill. In production code, you can just move your singleton HttpClient to a "service locator":
public static class SingletonServices
{
public static readonly HttpClient HttpClient;
static SingletonServices()
{
HttpClient = new HttpClient();
}
}
So that when you instantiate a proxy in production code, you do this:
var proxy = new XProxyImplementation(SingletonServices.HttpClient);
I would definitely go with a DI solution for this using the Microsoft.Extensions.DependencyInjection package.
https://dzone.com/articles/dependency-injection-in-net-core-console-applicati
And you should also be very aware how you use your async methods like GetAsync.
Using .Result almost never gives the desired result and you would be better off making the method async and using an await keyword like so:
var response = await Client.GetAsync(BaseUrl + "XXXApi/GetClientSettings/");
https://montemagno.com/c-sharp-developers-stop-calling-dot-result/
is a good resource for the whys and hows of this best practice
DI is the answer. If you do not want to use ID there is an HttpClientFactory that you can implement.
You can read more here
https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests

Dependency injection resolving by name

How can I inject different implementation of object for a specific class?
For example, in Unity, I can define two implementations of IRepository
container.RegisterType<IRepository, TestSuiteRepositor("TestSuiteRepository");
container.RegisterType<IRepository, BaseRepository>();
and call the needed implementation
public BaselineManager([Dependency("TestSuiteRepository")]IRepository repository)
As #Tseng pointed, there is no built-in solution for named binding. However using factory method may be helpful for your case. Example should be something like below:
Create a repository resolver:
public interface IRepositoryResolver
{
IRepository GetRepositoryByName(string name);
}
public class RepositoryResolver : IRepositoryResolver
{
private readonly IServiceProvider _serviceProvider;
public RepositoryResolver(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IRepository GetRepositoryByName(string name)
{
if(name == "TestSuiteRepository")
return _serviceProvider.GetService<TestSuiteRepositor>();
//... other condition
else
return _serviceProvider.GetService<BaseRepositor>();
}
}
Register needed services in ConfigureServices.cs
services.AddSingleton<IRepositoryResolver, RepositoryResolver>();
services.AddTransient<TestSuiteRepository>();
services.AddTransient<BaseRepository>();
Finally use it in any class:
public class BaselineManager
{
private readonly IRepository _repository;
public BaselineManager(IRepositoryResolver repositoryResolver)
{
_repository = repositoryResolver.GetRepositoryByName("TestSuiteRepository");
}
}
In addition to #adem-caglin answer I'd like to post here some reusable code I've created for name-based registrations.
UPDATE Now it's available as nuget package.
In order to register your services you'll need to add following code to your Startup class:
services.AddTransient<ServiceA>();
services.AddTransient<ServiceB>();
services.AddTransient<ServiceC>();
services.AddByName<IService>()
.Add<ServiceA>("key1")
.Add<ServiceB>("key2")
.Add<ServiceC>("key3")
.Build();
Then you can use it via IServiceByNameFactory interface:
public AccountController(IServiceByNameFactory<IService> factory) {
_service = factory.GetByName("key2");
}
Or you can use factory registration to keep the client code clean (which I prefer)
_container.AddScoped<AccountController>(s => new AccountController(s.GetByName<IService>("key2")));
Full code of the extension is in github.
You can't with the built-in ASP.NET Core IoC container.
This is by design. The built-in container is intentionally kept simple and easily extensible, so you can plug third-party containers in if you need more features.
You have to use a third-party container to do this, like Autofac (see docs).
public BaselineManager([WithKey("TestSuiteRepository")]IRepository repository)
After having read the official documentation for dependency injection, I don't think you can do it in this way.
But the question I have is: do you need these two implementations at the same time? Because if you don't, you can create multiple environments through environment variables and have specific functionality in the Startup class based on the current environment, or even create multiple Startup{EnvironmentName} classes.
When an ASP.NET Core application starts, the Startup class is used to bootstrap the application, load its configuration settings, etc. (learn more about ASP.NET startup). However, if a class exists named Startup{EnvironmentName} (for example StartupDevelopment), and the ASPNETCORE_ENVIRONMENT environment variable matches that name, then that Startup class is used instead. Thus, you could configure Startup for development, but have a separate StartupProduction that would be used when the app is run in production. Or vice versa.
I also wrote an article about injecting dependencies from a JSON file so you don't have to recompile the entire application every time you want to switch between implementations. Basically, you keep a JSON array with services like this:
"services": [
{
"serviceType": "ITest",
"implementationType": "Test",
"lifetime": "Transient"
}
]
Then you can modify the desired implementation in this file and not have to recompile or change environment variables.
Hope this helps!
First up, this is probably still a bad idea. What you're trying to achieve is a separation between how the dependencies are used and how they are defined. But you want to work with the dependency injection framework, instead of against it. Avoiding the poor discover-ability of the service locator anti-pattern. Why not use generics in a similar way to ILogger<T> / IOptions<T>?
public BaselineManager(RepositoryMapping<BaselineManager> repository){
_repository = repository.Repository;
}
public class RepositoryMapping<T>{
private IServiceProvider _provider;
private Type _implementationType;
public RepositoryMapping(IServiceProvider provider, Type implementationType){
_provider = provider;
_implementationType = implementationType;
}
public IRepository Repository => (IRepository)_provider.GetService(_implementationType);
}
public static IServiceCollection MapRepository<T,R>(this IServiceCollection services) where R : IRepository =>
services.AddTransient(p => new RepositoryMapping<T>(p, typeof(R)));
services.AddScoped<BaselineManager>();
services.MapRepository<BaselineManager, BaseRepository>();
Since .net core 3, a validation error should be raised if you have failed to define a mapping.

Recommendations for dependencies in Service Layer

What is recommended architectural approach for defining dependencies in a service class ?
Is this OK, when another class, ex. OrderService has dependencies to repository class ex. CartRepository instead of CartService? Should I always create one repository and one service per domain object ?
public class CartService : ICartService
{
private IBuyerRepository _buyerRepository;
private ICartRepository _cartRepository;
private IConfigService _configService;
private ISimpleDataService _simpleDataService;
public CartService(IBuyerRepository buyerRepository,
ICartRepository cartRepository,
IConfigService configService)
{
_buyerRepository = buyerRepository;
_cartRepository = cartRepository;
_configService = configService;
}
public void Save(Cart cart)
{
_cartRepository.Save(cart);
}
}
OrderService file:
public class OrderService : IOrderService
{
public OrderService(ICartRepository cartRepository)
{
}
}
Your implementation is good as a first step, and in a simple, not too big, domain.
A such implementation has avantages:
While just one service per http resquest manages all the repositories it needs, there is no difficulty to manage the sql transaction to maintain integrity.
It has too disadvantages:
You could write two times, or more, the same business rules... We all are lazy so it's a problem. But a major failure will come when someone, or you, 6 months later, will call the repository for the third time in its service implementation and forget a business rule... bye bye lovely domain...
My recommendation would be that a service just call its repository, and calls the other services that encapsulate their own logic, when needed.
The only trick to remember is to propagate the transaction to avoid odd things to happen.
Hope it helps,
Julien

ServiceStack - Unit of work and structure map

I am making a rest service using ServiceStack (http://www.servicestack.net). I'm using the unit of work pattern for my data access layer. I am using StructureMap to connect all my services and the unit of work together.
What I need to do is to create a single unit of work for each individual request that I receive and then dispose of it after.
I have a WCF Service which is using the mechanism here, http://andreasohlund.net/2009/04/27/unitofwork-in-wcf-using-structuremap.
Essentially resulting in something like this
ObjectFactory.Initialize(x =>
{
x.Scan(a =>
{
a.AssemblyContainingType<IUnitOfWork>();
a.WithDefaultConventions();
});
x.For<IUnitOfWork>().LifeCycleIs(new WcfOperationLifecycle());
}
I am looking for a similar 'Lifecycle' for ServiceStack.
[Solution]
The solution is in the comments of the accepted answer.
a) Set the StructureMap lifecycle to HttpContext
x.For<IUnitOfWork>().LifecycleIs(Lifecycles.GetLifecycle(InstanceScope.HttpContext));
b) Updated the structure map IOC adapter to extend the IRelease interface
class StructureMapContainerAdapter : IContainerAdapter, IRelease
{
public T Resolve<T>()
{
return ObjectFactory.GetInstance<T>();
}
public T TryResolve<T>()
{
return ObjectFactory.TryGetInstance<T>();
}
public void Release(object instance)
{
ObjectFactory.ReleaseAndDisposeAllHttpScopedObjects();
}
}
Sounds like you just want Request Scope?
Also check out the concrete Service base class on how you can use Lazy loading + Dispose() to get this behaviour.
As well as in ServiceStack's new API you can override your services OnBeforeExecute() OnAfterExecute() event hooks by using your own ServiceRunner (in the older API you would need to provide a custom service base class).

Categories