Reputation: 15175
I have been slowly but surely chipping away at a problem that has revealed itself overtime as application usage has risen. I have been using a repository'esque architecture using DI.
When the application was developed the singleton pattern was chosen for serving up data controllers as there would only be one fired up per session and only instantiated when needed.
However, user usage increased and I am running into threading issues.
I have 75 or so data controllers and they all were developed with the following pattern.
public class MyService : IMyServiceBase
{
internal MyServiceDataDataContext _dataContext = null;
protected IConfigurationService _systemService;
public MyService(IConfigurationService systemService)
{
_systemService = systemService;
_dataContext = new MyServiceDataDataContext(_systemService.GetCurrentSystem().WriteOnlyDatabase.ConnectionString);
_dataContext.ObjectTrackingEnabled = false;
}
public Domain.Data.MyObject GetSomething(int id)
{
return (
from s in _dataContext.MyObjects
select Mapper.Map<MyObject, Domain.Data.MyObject>(s)
).SingleOrDefault();
}
}
Now, after doing some research I have found I am running into slight concurrency issues with the most used controllers. I have been applying the fix below one by on to the most used and have found that is solving my problems on the production server. In a nutshell I am createing the datacontext per request on in each function call as the intended one time singleton way.
public class MyService : IMyServiceService
{
internal MyServiceDataDataContext _dataContext = null;
protected IConfigurationService _systemService;
public MyService(IConfigurationService systemService)
{
_systemService = systemService;
_dataContext = new DistrictDataDataContext(_systemService.GetCurrentSystem().WriteOnlyDatabase.ConnectionString);
_dataContext.ObjectTrackingEnabled = false;
}
public Domain.Data.MyObject GetSomething(int id)
{
using (_dataContext = new MyServiceDataDataContext(_systemService.GetCurrentSystem().WriteOnlyDatabase.ConnectionString))
{
Mapper.CreateMap<MyObject, Domain.Data.MyObject>();
return (from s in _dataContext.MyObjects
select Mapper.Map<MyObject, Domain.Data.MyObject>(s)).SingleOrDefault();
}
}
}
Now for the question...would it be better to go to all 75 data controllers and refactor all methods, some controllers have twenty methods, per the example above, or could I simply stop using singleton in the DI constructor.
Will changing the following snippet to something that is per call be the same as invoking the constructor in each method?
AppServiceFactory.Instance.RegisterTypeSingleton<IMyService>(typeof(My.Resources.Data.MyService), "MyService");
Thanks
Upvotes: 2
Views: 80
Reputation: 14580
You should make one change to all of the controllers - inject the DataContext
.
public class MyService : IMyServiceBase
{
private MyServiceDataDataContext dataContext;
public MyService(MyServiceDataDataContext dataContext)
{
this.dataContext = dataContext;
}
public Domain.Data.MyObject GetSomething(int id)
{
return (
from s in this.dataContext.MyObjects
select Mapper.Map<MyObject, Domain.Data.MyObject>(s))
.SingleOrDefault();
}
}
The responsibility of each objects's lifetime (DataContext
in your example) should be external to the consumer (MyService
) - your container can and should manage all object lifetimes.
Upvotes: 3