I have a wpf application with dependency injection. I registered my context as service to use in app like below.
serviceCollection.AddDbContext<Context>(p => p.UseSqlServer(configuration.GetConnectionString("DefaultConnection")));
I have another service that should fetch data from database every 15 seconds to check for new entities added and i do it with an event service and start the service in MainWindow.xaml startup and it goes to another thread.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
Task newOrdersTask = _eventService.SubscribeToNewOrders();
}
But sometimes while working with appplication i get this error.
A second operation started on this context before a previous operation completed
How can i handle these scenarios?
It is a bad idea to have a singleton DbContext in your entire application, especially when working on different threads is being considered.
Passing ServiceLifetime.Transient as the second argument to AddDbContext will force
creation of a new DbContext every time it gets injected by the container.
However, by doing so, you are going to miss a lot of features EF Core DbContext provides by default. You may consider implementing something like "ambient context pattern" to somehow preserve these features.
Related
I am having some issues with context lifetime on my .NetCore 6 win forms application. In summary, I have a button that when clicked calls a repository which then retrieves a record from my DB and displays one value from that record in a text field. This works ok until that value changes in the database. Further clicks of the button continue to display the old value.
This is how I register my context in the winforms app
services.AddDbContext<MyContext>(b => b.UseSqlServer(connectionString));
I then register my services like this:
services.AddScoped<IMyRepo, MyRepo>();
I guess this is an issue where the form is long running and never disposes the context, hence why the result is always the same until the form is closed and reopened with a fresh context.
I am using this in my repo to force a new result each time, however is seems like a bit of a mission to do this for every request to the DB I make...
_entities.Entry(log).Reload();
Is there a cleaner way I can do this without having to do the reload?
Honestly, I wouldn't use the MS IoC AddDbContext for WinForms/WPF. There probably is a way to have it play nice with some form of lifetime scope, but I'm honestly not aware of one. I don't use it for web projects either, simply because it scopes the DbContext to the request and I like to have a bit more control over the lifetime of the DbContext in some situations. (Dealing with poisoned contexts for instance)
For web and WPF I've used a Unit of Work pattern called the DbContextScope to manage the DbContext and relationship with the Repositories. The idea being that the consumers use an injected DBContextScopeFactory to create a DbContextScope (wrapping one or more DbContext instances) and the Repositories accept an injected DbContexScopeLocator to gain access to a requested DbContextScope.
The original EF6 implementation was by Medhi El Gueddari (https://github.com/mehdime/DbContextScope || https://www.nuget.org/packages/Mehdime.Entity)
For EF Core 6: (https://www.nuget.org/packages/Zejji.DbContextScope.EFCore6)
Alternatively if the scope of a DbContext can be contained within the repository calls themselves (tracked entities don't need to be passed outside of the repository) then you could also just use an injected DbContextFactory class to provide DbContext instances on demand. The advantage of a UoW pattern like above is that you have control over the scope the DbContext instance(s) live so multiple operations can be committed together or rolled back. The DbContext instance is available between multiple repositories if needed.
What is better? Or maybe - is the following a good practice?
I use Spring.net to create an instance of DbContext and then inject it into every controller for use in actions. The object is a singleton. Sometimes I get an exception which says that the "The ObjectContext instance has been disposed.." I suspect that this might be the reason, however this is not repeatable, and so far my application is only used by me during the development.
Now, would it be better to create a DbContext in every controller class and reuse in it's actions; or maybe create the DbContext object in every action itself; or just set it in the Spring config not to be a singleton, so it is created every time it is being accessed?
It is best to inject your dbcontext using request scope. That way, the context is created on the start of a request and disposed at the end. During the request you'll have a db context available so that it can handle lazy loaded objects for you.
When you register as a singleton, the dbcontext is shared for all requests, which most of the time isn't what you want. For instance, it might be that it hold a reference to all your loaded objects, potentially loading the entire db into memory.
I'm used to work with StructureMap with Web Apps... but now, I'm working on a Windows Forms project and I'd like to use it, but I don't how to configure it.
In web, I'd have a bootstrapper class that is invoked on Application_Start on Global.asax, but I don't know how to do the same on WinForms.
Thanks!
You can initialize the container in the static main method that starts your application. Then retrieve your form instances from the container, so that any necessary dependencies can be injected. You could still put the initialization code in a Bootstrapper.
static class Program
{
[STAThread]
static void Main()
{
ObjectFactory.Initialize(...);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(ObjectFactory.GetInstance<Form1>());
}
}
For a Winforms application the counter part to Application_Start would be the main method that initializes the first Form.
When using ORM mappers with web applications you generally have the thumb rule of creating a data context/session per http request. For a Winforms application you tend to go for a context per operation or per form.
You'd structure the bootstrapping and IoC configuration in the same ways (though I'm not sure how you'd include the form classes themselves, I haven't worked with WinForms much). The only real difference that you'd need is when/where the initializer gets called. It just has to be in the startup of the application. For web applications, you do indeed call it from Application_Start. I think in WinForms apps it would be in the OnLoad event of the main form.
If you have a main method anywhere (similar to a console app) then that would work as well. This could be if the WinForms app was ported from a console app, for example.
I have a ViewModel where one of its functions is to talk to a service and get some data. However, if there is a problem, I would like a notify the user that the service could not run.
Currently what I am doing is firing an event which the view has subscribed to (my viewModel is created in the resources section of the view) and receiving the event in the view event handler I just do a Windows.Alert().
First, I am trying to reduce the amount of code in the code behind of the view and with the event firing, there must be a better way to do this?
Secondly, since my view knows about my view model (i.e. created in the resources section), I am sure this will cause problems in testing my view. Is this the correct way to do this?
JD.
Yes, I don't think subscribing to an event in the VM from the View is a good idea. Almost better to put the alert in the VM, but that puts UI in the VM and makes it hard to test. There are a couple of other ways to handle this.
Dialogs and ViewModel - Using Tasks as a Pattern
Decoupled ChildWindow Dialogs with Prism in Silverlight 3
Best to use a service here. A service just provides some function through an interface.
public interface IDialogService {
void ShowNotifictation(string message);
}
The ViewModel takes this service and uses it to display the notification. The implementation of this service is then specific to your solution, and can display the notification however you want.
The implementation of such a service might look like this:
[Export(typeof(IMessageService))]
public class MessageService : IMessageService
{
public void ShowMessage(string message)
{
MessageBox.Show(message);
}
...
It uses MEF as IoC Container. The service is registered via the Export attribute as IMessageService.
You might have a look at the WPF Application Framework (WAF) to see the full implementation and sample applications that are using this service.
Hope this helps.
jbe
I have come across a bit of a problem while using Unity and WPF. The scenario is I have a WPF application which follows the MVVM design pattern. A have a module called ViewKDI. Within this module I have a service called ViewKDIService, the ViewKDIService service utilises another service called UserService.
Every time I load the module ViewKDI I want Unity to return me a new instance of both the ViewKDIService and the UserService.
I have put the below in the shell bootstrapper:
Container.RegisterType<IUserService, UserService>();
In the ViewKDI module I have put the following:
Container.RegisterType<IViewKDIService, ViewKDIService>();
Each time the ViewKDI module loads the ViewKDIService constructor is called. However the UserService constructor is only called the first time, this means that I am not getting a new instance of UserService.
I require unity to give me a new instance of UserService too so that I can manage this session separately from the rest of the application.
Any ideas?
Thanks
Faisal
Unity's default behaviour is to create a new instance of each object each time one is requested, so you shouldn't be seeing this behaviour.
From what I can gather from the source code and MSDN documentation (this is a good read), you can specify a "lifetime manager" object when you register a type to tell Unity how the type should be constructed and cached. Using the TransientLifetimeManager (which essentially does no caching) will cause Unity to re-create the class each time. So try this:
Container.RegisterType<IUserService, UserService>(new TransientLifetimeManager());
... and see if it creates a new UserService each time.