I have a class with a method performing some database actions.
I want to allow an existing (open) context to be sent in the method call to be used for the database access.
However if a context is not sent, I create a new one.
I just want to make sure the object is not disposed if included in the method call.
Is the object disposed when a using-scope is used in the called method?
// DbService class
class DbService
{
private void SomeDbAction(SomeDbContextObject backendContext = null)
{
using (var context = backendContext ?? CreateNewContextObject())
{
// Some actions using the context
}
}
}
// Call from another class
class Temp
{
void DoSomeThing()
{
var existingContext = new SomeDbContextObject();
dbService.SomeDbAction(existingContext);
// Is dbService disposed here?
UseContextForSomethingElse(existingContext);
}
}
// Is dbService disposed here?
Yes, it is disposed. This is a case where optional arguments work against you - better to have two specific overloads:
class DbService
{
public void SomeDbAction(SomeDbContextObject backendContext)
{
// Some actions using the context
}
public void SomeDbAction()
{
using (var context = CreateNewContextObject())
{
SomeDbAction(context);
}
}
}
You should not dispose of the backendContext object if it has been passed in, but should do so if you created it in the method:
private void CoreSomeDbAction(SomeDbContextObject backendContext) {
//TODO: Some actions using the context
}
private void SomeDbAction(SomeDbContextObject backendContext = null) {
if (null == backendContext) {
// created context should be disposed
using (SomeDbContextObject context = new SomeDbContextObject(...)) {
CoreSomeDbAction(context);
}
}
else
CoreSomeDbAction(backendContext); // passed context should be prevent intact
}
Related
Lets say I want to use, for example, a new DbContext object whenever a method is called in a class but without getting it by a parameter. Like so
class MyClass {
public virtual void MethodOne() {
// Having automatically a new instance of DbContext
}
public virtual void MethodTwo() {
// Also having automatically a new instance of DbContext
}
}
What I was really hoping for was a DI way of doing this. Like public void Method(IMyWayOfContext context).
class MyClass {
public virtual void MethodOne(IMyWayOfContext context)) {
}
public virtual void MethodTwo(IMyWayOfContext context) {
}
}
Other classes inheriting from this class must be provided with a new instance of dbcontext. That's why I don't want to create a new instance inside of the function
You could do something like this (generic interface, plus a wrapper with multiple constraints):
class DBContext{ }
interface IDoesMethods<TContext> where TContext : new()
{
void MethodOne(TContext context = default(TContext));
void MethodTwo(TContext context = default(TContext));
}
class MyClass : IDoesMethods<DBContext>
{
public void MethodOne(DBContext context)
{
}
public void MethodTwo(DBContext context)
{
}
}
class MyContextWrapper<TClass, TContext> : IDoesMethods<TContext> where TContext : new() where TClass : IDoesMethods<TContext>, new()
{
public void MethodOne(TContext context = default(TContext))
{
instance.MethodOne(new TContext());
}
public void MethodTwo(TContext context = default(TContext))
{
instance.MethodTwo(new TContext());
}
private TClass instance = new TClass();
}
class Program
{
static void Main(string[] args)
{
var wrapper = new MyContextWrapper<MyClass, DBContext>();
wrapper.MethodOne();
wrapper.MethodTwo();
}
}
Make a property with only getter that will return new instance every time
protected DbContext MyDBContext
{
get
{
return new DbContext();
}
}
EDIT: If you want some kind of dependency injection you can make your class generic and pass to instance of the class what type of context you want
class MyClass<T> {
protected DbContext MyDBContext
{
get
{
return Activator.CreateInstance<T>();
}
}
public void MethodOne() {
// Having automatically a new instance of DbContext
}
public void MethodTwo() {
// Also having automatically a new instance of DbContext
}
}
Your simple solution can work this way:
class MyClass {
protected DbContext InternalContext {
return new DbContext();
}
public virtual void MethodOne(DbContext dc = null) {
if(dc == null)
dc = InternalContext;
// do your work
}
public virtual void MethodTwo(DbContext dc = nnull) {
if(dc == null)
dc = InternalContext;
// do your work
}
}
In that case, you have to take care of disposing InternalContext
While answer here looks valid, they don't seem to fulfill perfectly your requirement of having a solution that rely on DI.
DI in it's simplest expression is most of the time achieve with Constructor Injection.
Your design was already good and DI ready.
Indeed, asking for dependencies via the constructor is good.
It is at the composition root of your application that you need to decide what implementation you need to pass.
Using a DI library can help (but it is not required to enable DI).
With your actual class design:
class MyClass {
public virtual void MethodOne(IMyWayOfContextFactory contextFactory)) {
using(var context = contextFactory.Create()){
//play with context
}
}
public virtual void MethodTwo(IMyWayOfContextFactory contextFactory) {
using(var context = contextFactory.Create()){
//play with context
}
}
}
public ContextFactory : IMyWayOfContextFactory {
IMyWayOfContext Create(){
return new MyWayOfContext();
}
}
Without a factory and with a DI container like SimpleInjector, you could have:
class MyClass {
public virtual void MethodOne(IMyWayOfContext context)) {
//play with context
}
public virtual void MethodTwo(IMyWayOfContext context) {
//play with context
}
}
And register your component once at the composition root with configurable Lifestyle management:
container.Register<IMyWayOfContext, MyWayOfContext>(Lifestyle.Transient);
The latter approach is simpler if you want to configure when to inject what instance of your context. Indeed, such configuration is built in an DI Container library. For instance, see: Lifestyle of component with SimpleInjector
Error message:
The operation cannot be completed because the dbcontext has been disposed.
Can somebody explain why and where my DbContext is getting disposed while I perform the update?
Context file:
using System.Data.Entity;
namespace OnlineTest
{
internal class OnlineTestContext : DbContext
{
private OnlineTestContext() : base("name=OnlineTest")
{
}
private static OnlineTestContext _instance;
public static OnlineTestContext GetInstance
{
get
{
if (_instance == null)
{
_instance = new OnlineTestContext();
}
return _instance;
}
}
public DbSet<User> Users { get; set; }
}
}
Business logic:
public int UpdateUser(User user)
{
user.ModifiedOn = DateTime.Now;
using (var context = OnlineTestContext.GetInstance)
{
context.Entry(user).State = EntityState.Modified;
return context.SaveChanges();
}
}
public User GetUserByEmailId(string emailId)
{
using (var context = OnlineTestContext.GetInstance)
{
return context.Users.First(u => u.EmailId == emailId);
}
}
Unit test:
[TestMethod]
public void UpdateUserUnitTest()
{
User user = onlineTestBusinessLogic.GetUserByEmailId("test#test");
user.PhoneNumber = "+91 1234567890";
int changes = onlineTestBusinessLogic.UpdateUser(user);
User Modifieduser = onlineTestBusinessLogic.GetUserByEmailId("test#test");
Assert.AreEqual(Modifieduser.PhoneNumber, "+91 0987654321");
}
Thank you.
It is disposed by the second time you call a method on a repository. A timeline is like that:
GetUserByEmailId is called, _instance is null, so it is initialized
GetUserByEmailId is completed, and context is disposed. But the object still exists in _instance field
UpdateUser is called, _instance is not null, so the old context is returned in using
context.SaveChanges is called, but since this object of context is already disposed, the exception is thrown
This is generally a good idea to avoid caching db context like this. Basic rule of thumb is "one context object per unit of work". You can find some more information about why is it so in this thread (starring Jon Skeet!).
The using keyword is you specifically saying "when the scope closes, call .Dispose() on the object I passed in". Which is not what you want, because you want to re-use the object over and over.
Remove the using and you will get stop getting this issue. e.g.
var context = OnlineTestContext.GetInstance;
context.Entry(user).State = EntityState.Modified;
return context.SaveChanges();
How can one set the TransactionHandler for ObjectContext?
I am checking this example: Handling of Transaction Commit Failures, but it only shows for DbContext.
TransactionHandler also works for ObjectContext. The only problem is that the code based configurations (DbConfiguration) are not evaluated before the first DbContext is instantiated.
Two possible workarounds
Dummy DbContext:
public class MyDbConfiguration : DbConfiguration
{
public MyDbConfiguration()
{
SetTransactionHandler(SqlProviderServices.ProviderInvariantName,
() => new CommitFailureHandler());
}
}
public class TestContext : DbContext { }
static void Main(string[] args)
{
// instantiate DbContext to initialize code based configuration
using (var db = new TestContext()) { }
using (var db = new TransactionHandlerDemoEntities()) {
var handler = db.TransactionHandler; // should be CommitFailureHandler
db.AddToDemoTable(new DemoTable { Name = "TestEntiry1" });
db.SaveChanges();
}
}
Or DbConfiguration.Loaded event
static void Main(string[] args)
{
DbConfiguration.Loaded += DbConfiguration_Loaded;
using (var db = new TransactionHandlerDemoEntities()) {
var handler = db.TransactionHandler;
db.AddToDemoTable(new DemoTable { Name = "TestEntiry1" });
db.SaveChanges();
}
}
static void DbConfiguration_Loaded(object sender, DbConfigurationLoadedEventArgs e)
{
e.AddDependencyResolver(new TransactionHandlerResolver(
() => new CommitFailureHandler(),
SqlProviderServices.ProviderInvariantName,
null),true);
}
TransactionHandlerDemoEntities is an ObjectContext.
This is exclusively for DbContext. If you can, refactor your ObjectContext-based application into DbContext as soon as possible. I think that many more new features will appear that only work with the DbContext API. Maybe ObjectContext will even get deprecated as a public API some day.
You can create a DbContext from an ObjectContext, but I don't think that's of much help to you. The main problem is undoubtedly that the rest of the data logic currently expects ObjectContext.
We're using a library that uses pooled objects (ServiceStack.Redis's PooledRedisClientManager). Objects are created and reused for multiple web requests. However, Dispose should be called after each use to release the object back into the pool.
By default, Ninject only deactivates an object reference if it has not been deactivated before.
What happens is that the pool instantiates an object and marks it as active. Ninject then runs the activation pipeline. At the end of the request (a web request), Ninject runs the deactivation pipeline which calls Dispose (and thus the pool marks the object as inactive). The next request: the first pooled instance is used and the pool marks it as active. However, at the end of the request, Ninject does not run its deactivation pipeline because the ActivationCache has already marked this instance as deactivated (this is in the Pipeline).
Here's a simple sample that we've added in a new MVC project to demonstrate this problem:
public interface IFooFactory
{
IFooClient GetClient();
void DisposeClient(FooClient client);
}
public class PooledFooClientFactory : IFooFactory
{
private readonly List<FooClient> pool = new List<FooClient>();
public IFooClient GetClient()
{
lock (pool)
{
var client = pool.SingleOrDefault(c => !c.Active);
if (client == null)
{
client = new FooClient(pool.Count + 1);
client.Factory = this;
pool.Add(client);
}
client.Active = true;
return client;
}
}
public void DisposeClient(FooClient client)
{
client.Active = false;
}
}
public interface IFooClient
{
void Use();
}
public class FooClient : IFooClient, IDisposable
{
internal IFooFactory Factory { get; set; }
internal bool Active { get; set; }
internal int Id { get; private set; }
public FooClient(int id)
{
this.Id = id;
}
public void Dispose()
{
if (Factory != null)
{
Factory.DisposeClient(this);
}
}
public void Use()
{
Console.WriteLine("Using...");
}
}
public class HomeController : Controller
{
private IFooClient foo;
public HomeController(IFooClient foo)
{
this.foo = foo;
}
public ActionResult Index()
{
foo.Use();
return View();
}
public ActionResult About()
{
return View();
}
}
// In the Ninject configuration (NinjectWebCommon.cs)
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<IFooFactory>()
.To<PooledFooClientFactory>()
.InSingletonScope();
kernel.Bind<IFooClient>()
.ToMethod(ctx => ctx.Kernel.Get<IFooFactory>().GetClient())
.InRequestScope();
}
The solutions that we've come up with thus far are:
Mark these objects as InTransientScope() and use other deactivation mechanism (like an MVC ActionFilter to dispose of the object after each request). We'd lose the benefits of Ninject's deactivation process and require an indirect approach to disposing of the object.
Write a custom IActivationCache that checks the pool to see if the object is active. Here's what I've written so far, but I'd like some one else's eyes to see how robust it is:
public class PooledFooClientActivationCache : DisposableObject, IActivationCache, INinjectComponent, IDisposable, IPruneable
{
private readonly ActivationCache realCache;
public PooledFooClientActivationCache(ICachePruner cachePruner)
{
realCache = new ActivationCache(cachePruner);
}
public void AddActivatedInstance(object instance)
{
realCache.AddActivatedInstance(instance);
}
public void AddDeactivatedInstance(object instance)
{
realCache.AddDeactivatedInstance(instance);
}
public void Clear()
{
realCache.Clear();
}
public bool IsActivated(object instance)
{
lock (realCache)
{
var fooClient = instance as FooClient;
if (fooClient != null) return fooClient.Active;
return realCache.IsActivated(instance);
}
}
public bool IsDeactivated(object instance)
{
lock (realCache)
{
var fooClient = instance as FooClient;
if (fooClient != null) return !fooClient.Active;
return realCache.IsDeactivated(instance);
}
}
public Ninject.INinjectSettings Settings
{
get
{
return realCache.Settings;
}
set
{
realCache.Settings = value;
}
}
public void Prune()
{
realCache.Prune();
}
}
// Wire it up:
kernel.Components.RemoveAll<IActivationCache>();
kernel.Components.Add<IActivationCache, PooledFooClientActivationCache>();
Specifically for ServiceStack.Redis's: use the PooledRedisClientManager.DisposablePooledClient<RedisClient> wrapper so we always get a new object instance. Then let the client object become transient since the wrapper takes care of disposing it. This approach does not tackle the broader concept of pooled objects with Ninject and only fixes it for ServiceStack.Redis.
var clientManager = new PooledRedisClientManager();
kernel.Bind<PooledRedisClientManager.DisposablePooledClient<RedisClient>>()
.ToMethod(ctx => clientManager.GetDisposableClient<RedisClient>())
.InRequestScope();
kernel.Bind<IRedisClient>()
.ToMethod(ctx => ctx.Kernel.Get<PooledRedisClientManager.DisposablePooledClient<RedisClient>>().Client)
.InTransientScope();
Is one of these approaches more appropriate than the other?
I have not use Redis so far so I can not tell you how to do it correctly. But I can give you some input in general:
Disposing is not the only thing that is done by the ActivationPipeline. (E.g. it also does property/method injection and excuting activation/deactivation actions.) By using a custom activation cache that returns false even though it has been activated before will cause that these other actions are executed again (E.g. resulting in property injection done again.)
I'm working in WinRt calling a WinRt Class Library from a Windows Store App using C# and SQLite... objects are returning null reference errors at unexpected times...
I'm trying to implement a logon service that checks to see if the current user is already logged in by checking if the data file exists, then checking if the user is the current user logged in...
The user can simply enter their ID and click a logon button. It creates a DataService object that wraps a SQLite database and is then "injected" into the UserStartupService.
The UserStartupService uses Dependency Injection, singleton and implements IDisposable.
Issue 1) if the user clicks the logon button a second time, the UserStartupService object constructor does not run and when internal objects are used they throw null reference errors even though it runs through the dispose method after it exits the using block, which forces me to deactivate the logon button, which is a kluge fix at best. A new user has to exit the program to log in as a new user. (The original code did not implement IAsyncOperationWithProgress, but that should not matter...)
Issue 2) I'm now trying to implement IAsyncOperationWithProgress to relay progress back to the UI and it gets a null reference error the instant it tries to use _dataFeedService on the line:
var json = await _dataFeedService.ValidateUser(userId);
Even though it runs the constructor at the top of the using statement as expected...
I think there is a scope/thread issue that I'm missing here. Maybe something obvious...
Any ideas? Thanks!
// logon button pressed...
private void LogOn_Click(object sender, RoutedEventArgs e)
{
// Create database service for DI
DataService _dataService = new DataService("MyData.sqlite");
// using statement for scope control
using (UserStartupService uss = UserStartupService.GetInstance(_dataService))
{
// progress bar...
CurrentProgress.Visibility = Windows.UI.Xaml.Visibility.Visible;
// create op and call...
IAsyncOperationWithProgress<string, int> op;
op = uss.SetUpUser(txtUserId.Text);
op.Progress = (info, progress) =>
{
CurrentProgress.Value = progress;
};
op.Completed = (info, status) =>
{
var results = info.GetResults();
// when completed...
if (status == AsyncStatus.Completed)
{
txtMessage.Text = "Current user data already loaded...";
CurrentProgress.Value = 100;
} // if cancelled...
else if (status == AsyncStatus.Canceled)
{
// Operation canceled - not implemented...
}
};
}
btnLogon.IsEnabled = false;
}
public sealed class UserStartupService : IDisposable
{
#region properties
// services
private static DataService _dataService;
private static DataFeedService _dataFeedService;
private static SqliteService _sqlMAFService;
private static SerialiseDeserialiseService _serializeService;
private string _token = String.Empty;
#endregion properties
#region constructors with DI and singleton pattern
// use this code to implement singleton patter...
// private constructor = can't instance without GetInstance...
private UserStartupService(DataService dataService)
{
// guard clause...
if (dataService == null)
{
throw new ArgumentNullException("DataService");
}
_dataService = dataService;
_dataFeedService = new DataFeedService();
_sqlMAFService = new SqliteService(_dataService);
_serializeService = new SerialiseDeserialiseService();
}
// implement singleton
public static UserStartupService GetInstance(DataService dataService)
{
_dataService = dataService;
return MyNestedSingletonClass.singleton;
}
class MyNestedSingletonClass
{
internal static readonly UserStartupService singleton = new UserStartupService(_dataService);
static MyNestedSingletonClass() { }
}
#endregion constructors with DI and singleton pattern
public IAsyncOperationWithProgress<string, int> SetUpUser(string userId)
{
return AsyncInfo.Run<string, int>((token, progress) =>
Task.Run<string>(async () =>
{
progress.Report(1);
try
{
// validate user against server REST feed and get token
var json = await _dataFeedService.ValidateUser(userId);
// ... it never gets here due to _dataFeedService null exception
// ...more code ... never gets here...
}
catch (Exception ex)
{
return ex.Message;
}
progress.Report(100);
return "";
}, token));
}
#region implement IDisposable
public void Dispose()
{
_serializeService = null;
_sqlMAFService.Dispose();
_sqlMAFService = null;
_dataFeedService.Dispose();
_dataFeedService = null;
_dataService.CloseConnection();
_dataService = null;
}
#endregion implement IDisposable
}
The using block will dispose uss before it is done executing, so that's where your null reference exceptions are coming from (for both issues).
If UserStartupService is a singleton, and it could be used multiple times, then don't dispose it.
Also, I would recommend using await rather than callbacks (it's usually simpler), so something like this should work:
private async void LogOn_Click(object sender, RoutedEventArgs e)
{
btnLogon.IsEnabled = false;
// Create database service for DI
DataService _dataService = new DataService("MyData.sqlite");
var uss = UserStartupService.GetInstance(_dataService);
// progress bar...
CurrentProgress.Visibility = Windows.UI.Xaml.Visibility.Visible;
// create op and call...
var op = uss.SetUpUser(txtUserId.Text)
.AsTask(progress => { CurrentProgress.Value = progress; });
var result = await op;
txtMessage.Text = "Current user data already loaded...";
CurrentProgress.Value = 100;
btnLogon.IsEnabled = true;
}