I use Virtual Assistant . I am going to use Entity Framework Core for saving state. I met a problem. IStorage interface injects like a singleton because other objects which use this interface injects as a singleton.
services.AddSingleton<IStorage>(new MyDbStorage()); //<-- my storage with dbcontext
services.AddSingleton<UserState>(); //This class has ctor with IStorage param
services.AddSingleton<ConversationState>(); //And this class has ctor with IStorage param
services.AddSingleton(sp =>
{
var userState = sp.GetService<UserState>();
var conversationState = sp.GetService<ConversationState>();
return new BotStateSet(userState, conversationState);
});
See on github for details. I know, the global dbcontext is a bad idea . Could you suggest me some options for creating dbcontext? I think about DbContextFactory, but I don't know how exactly create it.
UPDATE I have updated code. See the first line.
First of all do not abstract MyDbContext
with interface, otherwise you won't be able to access EF fetures or will try hard to hide EntityFramework
namespace. Use AddDbContext extension. This way DbContext
will be registered as Scoped
what is the best lifetime for it.
Inject IServiceProvider
into your singleton UserState
and ConversationState
, then create scope and resolve MyDbContext
instance within this scope on demand only .
public class UserState
{
private readonly IServiceProvider _provider;
public UserState(IServiceProvider provider)
{
_provider = provider;
}
public async Task DoWorkAsync()
{
using (var scope = _provider.CreateScope())
using (var ctx = scope.ServiceProvider.GetService<MyDbContext>())
{
// do work
await ctx.SaveChangesAsync();
}
}
}
But if work done by UserState
and ConversationState
should be performed as single transaction (that's mean on same DbContext
instance), it's better to resolve MyDbContext
in BotStateSet
and pass in as argument into methods of UserState
and ConversationState
.
I'm not familiar with Virtual Assistant, but if it possible to use Transient
lifetime for your state classes (at least for UserState
and ConversationState
) it will allow you to inject MyDbContext
into constructor avoiding passing it as argument.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.