(apologies for the Wall Of Text... :) )
Summary
Using Dependency Injection with my Winfor application is creating a large number of Repository Context's. I'm not sure if the way i'm using this is right or wrong, or what the common practice is.
Details
In the last 6 odd months, I've been making ASP.NET MVC applications that impliment the Unit O fWork pattern with the Repository Pattern. On top of this, I've been using an Dependency Injection on all of these web applications with some success.
So this is an example of me wiring up my repository.
public EntityFrameworkRepositoryRegistry()
{
For<IUnitOfWork>()
.HybridHttpOrThreadLocalScoped() // Lifecycle of the object.
.Use<SqlServerContext>() // My EF Context.
.Ctor<string>("connectionString").Is("name=SqlServer_EF")
.Ctor<string>("defaultContainerName").Is("Entities");
// Ayende's EFProf application :)
EntityFrameworkProfiler.Initialize();
Scan(x =>
{
x.TheCallingAssembly();
x.ExcludeNamespaceContainingType<Fake.FakeContext>();
x.WithDefaultConventions();
}
);
}
Ok - works great. Main thing to note here is that
- I'm assuming the Lifecycle is the correct one for a Web scenario.
- The context will only exists once, per REQUEST that hits the webserver.
kewl.
Now, for my WinForm application, i initially created a single Unit Of Work object (no dependency injection, just yet) and kept passing that baby around to all the services (and then to the repositories).
For this win application, it hits the DB to find out all the text files it needs to parse. (eg. 25 files). Then, for each file, it creates a new Parser, reads each line and chucks the parsed data into a db table. Fine.
Problem was, this concext was being shared amoungst ALL Parsers, which was seriously throwing up errors all over the shop.
So then i added some Dependency Injection and uses that registry code above. Sorta same thing - lots of serious errors. This is because ONE context was again created for the single thread -> the winform.
So, i now tweaked the Registry of the Context to following :-
public EntityFrameworkRepositoryRegistry(bool isForTheWeb)
{
if (isForTheWeb)
{
For<IUnitOfWork>()
.HybridHttpOrThreadLocalScoped()
.Use<SqlServerContext>()
.Ctor<string>("connectionString").Is("name=SqlServer_EF")
.Ctor<string>("defaultContainerName").Is("Entities");
}
else
{
For<IUnitOfWork>()
.Use<SqlServerContext>()
.Ctor<string>("connectionString").Is("name=SqlServer_EF")
.Ctor<string>("defaultContainerName").Is("Entities");
}
EntityFrameworkProfiler.Initialize();
Scan(x =>
{
x.TheCallingAssembly();
x.ExcludeNamespaceContainingType<Fake.FakeContext>();
x.WithDefaultConventions();
});
}
So for a WinForm application, it now doesn't set the Lifecycle. This then created around 160 or so context's i think! (But it didn't really error, either).
So, i'm not sure if this is the right way to do things.
So my app, in effect, has 25 different timers going, to check a file every .. say .. 10 secs. If there's new data, it parsers it. Otherwise, come back in 10 secs.
Should each one of these files that gets parsed, be it's own thread? and then create a context per thread? (which i feel is similar to the web scenario). Or is this fine? I know it's a lot of context's, but each context doesn't mean a live connection to the db .. and with connection pooling, this shouldn't really be a problem.
The reason it has so many contexts, is becuase of the following code... (and these are seperate Constructors for some of the Repository classes...)
public SqlServerContext(string, string);
public GameFileRepository (IUnitOfWork);
public LogEntryRepository(IUnitOfWork);
public AlertRepository(IUnitOfWork);
... etc..
and for the main Service...
public PunkBusterParser(IUnitOfWork, IGameFileRepositry,
ILogEntryRepository, ILoggingService);
so the service requires an UoW and each repository also requires one ..which means a new one is getting created for each one.
I'm sure i haven't structured this correctly...
Any suggestions would be sincerely grateful!