I'm trying to implement Unit of Work and Generic Repository by following this great article. Only difference is that I have multiple databases context in my app. I came up with the below implementation but it seems awkward to say the least. What's the best way to do it ?
public class UnitOfWork : IDisposable
{
private MainDBDataContext MainDBDataContext = new MainDBDataContext();
private ReferenceDBDataContext ReferenceDBDataContext = new ReferenceDBDataContext();
private ProjectDBDataContext projectDBDataContext = new ProjectDBDataContext();
private VehicleRepository vehicleRepository;
private AccountRepository accountRepository;
public VehicleRepository VehicleRepository
{
get
{
if (this.vehicleRepository == null)
{
this.vehicleRepository = new VehicleRepository(projectDBDataContext,ReferenceDBDataContext);
}
return vehicleRepository;
}
}
public AccountRepository AccountRepository
{
get {
if (this.accountRepository == null)
{
this.accountRepository = new AccountRepository(projectDBDataContext);
}
return accountRepository;
}
}
public void Save()
{
projectDBDataContext.SubmitChanges();
ReferenceDBDataContext.SubmitChanges();
MainDBDataContext.SubmitChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
projectDBDataContext.Dispose();
MainDBDataContext.Dispose();
ReferenceDBDataContext.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
Related
When I call IKernel.Dispose() in the [TestCleanup] method of my DataTest, my application is crashing because the first object to be disposed is still in use by another object.
This code reproduces the issue:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ninject;
using Ninject.Modules;
[TestClass]
public class NinjectDisposeIssue
{
private IKernel kernel;
[TestInitialize]
public void TestInitialize()
{
kernel = new StandardKernel(new Module());
}
[TestCleanup]
public void TestCleanup()
{
kernel.Dispose();
}
[DataTestMethod]
[DataRow]
[DataRow]
public void DataTestMethod()
{
var parent = kernel.Get<Parent>();
parent.Run();
}
}
public class Module : NinjectModule
{
public override void Load()
{
Bind<Parent>().ToSelf().InSingletonScope();
Bind<Service>().ToSelf().InSingletonScope();
Bind<Database>().ToSelf().InSingletonScope();
// create 2 workers
Bind<Worker>().ToSelf().InSingletonScope();
Bind<Worker>().ToSelf().InSingletonScope();
}
}
public class Parent
{
private readonly Service service;
private readonly IEnumerable<Worker> workers;
public Parent(Service service, IEnumerable<Worker> workers)
{
this.service = service;
this.workers = workers;
}
public void Run()
{
for (var i = 0; i < 2; i++)
{
foreach (var worker in workers)
{
worker.StartWork();
}
service.DoSomething();
}
}
}
public class Service
{
private readonly Database database;
public Service(Database database)
{
this.database = database;
}
public void DoSomething()
{
var value = database.Get();
// do something with the value
}
}
public class Worker : IDisposable
{
private readonly Database database;
private Task workTask;
private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
private bool disposedValue;
public Worker(Database database)
{
this.database = database;
}
public void StartWork()
{
if (workTask == null)
{
workTask = Task.Run(WorkLoop);
}
}
private void WorkLoop()
{
while (!cancellationTokenSource.Token.IsCancellationRequested)
{
var value = database.Get();
// do some work with the value...
}
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
cancellationTokenSource.Cancel();
workTask.Wait();
workTask.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
public class Database : IDisposable
{
private readonly ThirdPartyDb thirdPartyDb = new ThirdPartyDb();
private bool disposedValue;
public string Get()
{
return thirdPartyDb.Get("foo");
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
thirdPartyDb.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
public class ThirdPartyDb : IDisposable
{
private bool isDisposed = false;
public void Dispose()
{
isDisposed = true;
}
public string Get(string key)
{
if (isDisposed)
{
throw new ObjectDisposedException(nameof(ThirdPartyDb));
}
return "bar";
}
}
The Dispose() method of the Database object is being called before the Dispose() method of the 2 Workers.
Question: Is there something I can do in the bindings to force the Workers to be disposed before the Database or is the way I have this configured fundamentally wrong?
As a simple solution, you can just add another CancellationTokenSource to your Database. This way you'll make sure that the thirdPartyDb is not getting called after disposal.
public class Database : IDisposable
{
private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
private readonly ThirdPartyDb thirdPartyDb = new ThirdPartyDb();
private bool disposedValue;
public string Get()
{
if (cancellationTokenSource.Token.IsCancellationRequested) return ""; //Return anything acceptable for you
return thirdPartyDb.Get("foo");
}
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
cancellationTokenSource.Cancel();
thirdPartyDb.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
}
I have a sealed class. It has a property
'
private IObservable<AnotherClass> observable
'.
I want to make this class as an observer and monitor the change in the above property.
I want to call onNext() whenever there is a change in this property.
I want to call a custom method1() in .onNext(). like onNext( call Method1(pass the observable data)).
Since this is a sealed class, I cannot use Virtual onNext() as I found in many examples.
How do I achieve these?
Implement IObserver<AnotherClass> and subscribe to the observable?
public sealed class AnObserver : IObserver<AnotherClass>
{
private readonly IObservable<AnotherClass> observable;
public AnObserver()
{
observable = ...;
observable.Subscribe(this);
}
void IObserver<AnotherClass>.OnCompleted() { }
void IObserver<AnotherClass>.OnError(Exception error) { }
void IObserver<AnotherClass>.OnNext(AnotherClass value)
{
Method1(value);
}
public void Method1(AnotherClass value)
{
...
}
}
Here's how I would tackle this situation.
public sealed class ThisClass : IDisposable
{
private readonly IObservable<AnotherClass> observable;
private readonly IDisposable subscription;
public ThisClass()
{
observable = ...;
subscription = observable.Subscribe(x => Method1(x));
}
private void Method1(AnotherClass value)
{
...
}
private bool disposedValue = false;
void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing)
{
subscription.Dispose();
}
disposedValue = true;
}
}
public void Dispose()
{
Dispose(true);
}
}
This doesn't expose anything unnecessary to the outside world and it cleans up on dispose.
I implemented an observer pattern using events and delegates. The program is receiving and processing big amounts of data (around 3000 messages per second) but at some point, it starts sending messages with a delayed timestamp, which I am trying to fix. I have 3 main classes that do the job in my opinion:
public class MessageTracker : IObservable<MessageEventArgs>
{
private List<IObserver<MessageEventArgs>> observers;
public MessageTracker()
{
observers = new List<IObserver<MessageEventArgs>>();
}
private static readonly MessageTracker mInstance = new MessageTracker();
private static MessageTracker getInstance() => mInstance;
private class Unsubscriber : IDisposable
{
private List<IObserver<MessageEventArgs>> _observers;
private IObserver<MessageEventArgs> _observer;
public Unsubscriber(List<IObserver<MessageEventArgs>> observers, IObserver<MessageEventArgs> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (! (_observer == null)) _observers.Remove(_observer);
}
}
public IDisposable Subscribe(IObserver<MessageEventArgs> observer)
{
if (! observers.Contains(observer))
observers.Add(observer);
return new Unsubscriber(observers, observer);
}
public void MessageTrack(MessageEventArgs msg) {
observers.AsParallel().ForAll(observer =>
{
if (msg is null)
observer.OnError(new ArgumentException("MessageError."));
else
observer.OnNext(msg);
});
}
public void EndMessageTrans(){
foreach(var observer in observers.ToArray())
if (observers.Contains(observer))
observer.OnCompleted();
observers.Clear();
}
}
public class MessageReporter : IObserver<MessageEventArgs>
{
private IDisposable unsubscriber;
public MessageReporter()
{ }
public event EventHandler<MessageEventArgs> OnNextMessage;
public virtual void Subscribe(IObservable<MessageEventArgs> provider)
{
if (provider != null)
unsubscriber = provider.Subscribe(this);
}
public void OnCompleted()
{
this.Unsubscribe();
}
public void OnError(Exception error)
{
}
public void OnNext(MessageEventArgs value)
{
if (OnNextMessage != null)
{
OnNextMessage?.Invoke(this, value);
}
}
public virtual void Unsubscribe()
{
unsubscriber.Dispose();
}
}
public sealed class MessageDataWorker
{
private readonly bool mSubscribeAll;
private readonly IEnumerable<string> mMessages;
public MessageDataWorker(IEnumerable<string> messages)
{
mMessages = messages;
if ((mMessages?.Count() ?? 0) == 0)
mSubscribeAll = true;
}
public override void DoWork()
{
var messageReporter = new MessageReporter();
messageReporter.OnNextMessage += OnNewMessageReceived;
messageReporter.Subscribe(MessageTracker.GetInstance());
while (!mShouldStop.WaitOne(100)) ;
MessageReporter.Unsubscribe();
}
private void OnNewMessageReceived(object sender, MessageEventArgs e)
{
if (!mSubscribeAll && !mMessages.Contains(e.Message))
return;
string message = "Message|" +
$"{e.Time}|" +
$"{e.Text};
try
{
Console.WriteLine(message);
}
catch { }
}
}
What I am trying to achieve is skipping notifications or receiving data for X milliseconds after sending the last message and afterward send the newest received message. I tried sleeping the observers and the provider but it just increased the delay. I think I am missing something and any suggestion would be appreciated.
From what I can tell from your code you could write the three classes with this code:
var messageTrack = new Subject<MessageEventArgs>();
var query =
from e in messageTrack
where !mMessages.Contains(e.Message)
select $"Message|{e.Time}|{e.Text}";
query.Throttle(TimeSpan.FromMilliseconds(X)).Subscribe(Console.WriteLine);
You should never need to implement IObservable<> or IObserver<> yourself. It almost always ends in disaster.
The above code handles the throttling you wanted.
I have a simple FeatureToggle class that uses FilesSystemWatcher to watch app.config file. If there is a change in the .config file it will reload settings from appSettings section. I made it implement IDisposable, however I can't use using {} statement because I want .config files to be watched while the program is running, however I do want Dispose() to be called when the process ends, and I can't add finally() block to the main program. How can I call Dispose(). Would I use a finalizer here?
FeatureToggle:
public sealed class FeatureToggle : IDisposable
{
private static readonly FeatureToggle instance = new FeatureToggle();
private static FeatureWatcher featureWatcher = new FeatureWatcher();
private static ConcurrentDictionary<string, bool> features = new ConcurrentDictionary<string, bool>();
private bool disposed;
static FeatureToggle()
{
}
private FeatureToggle()
{
}
public static FeatureToggle Instance
{
get
{
return instance;
}
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
public bool Enabled(string featureName)
{
string path = this.GetAssemblyPath();
if (featureWatcher.GetWatcher(path) == null)
{
FileSystemWatcher watcher = featureWatcher.AddWatcher(path);
if (watcher != null)
{
watcher.Changed += this.OnChanged;
this.Refresh(path);
}
}
return this.Get(featureName);
}
private void Add(string key, bool value)
{
features.AddOrUpdate(key, value, (k, v) => value);
}
private void Dispose(bool disposing)
{
if (this.disposed)
{
return;
}
if (disposing)
{
featureWatcher.Dispose();
featureWatcher = null;
features = null;
}
}
private bool Get(string key)
{
bool value;
if (features.TryGetValue(key, out value))
{
return value;
}
return false;
}
private string GetAssemblyPath()
{
return AppDomain.CurrentDomain.SetupInformation.ConfigurationFile;
}
private IEnumerable<KeyValuePair<string, bool>> LoadConfig(string path)
{
ExeConfigurationFileMap configMap = new ExeConfigurationFileMap { ExeConfigFilename = path };
Configuration config = ConfigurationManager.OpenMappedExeConfiguration(
configMap,
ConfigurationUserLevel.None);
var settings =
config.AppSettings.Settings.Cast<KeyValueConfigurationElement>()
.Where(x => x.Key.StartsWith("FeatureToggle."))
.ToDictionary(o => o.Key.ToString(CultureInfo.InvariantCulture), o => Convert.ToBoolean(o.Value));
return settings;
}
private void OnChanged(object source, FileSystemEventArgs e)
{
// app.config changed - run update
this.Refresh(e.FullPath);
}
private void Refresh(string path)
{
foreach (var kv in this.LoadConfig(path))
{
this.Add(kv.Key, kv.Value);
}
}
}
FileWatcher:
public class FeatureWatcher : IDisposable
{
private static ConcurrentDictionary<string, FileSystemWatcher> watchers;
private bool disposed;
public FeatureWatcher()
{
watchers = new ConcurrentDictionary<string, FileSystemWatcher>();
}
public FileSystemWatcher AddWatcher(string path)
{
if (this.GetWatcher(path) == null)
{
var parentPath = Path.GetDirectoryName(path);
var watcher = new FileSystemWatcher
{
Path = parentPath,
NotifyFilter = NotifyFilters.LastWrite,
Filter = "*.config"
};
watchers.TryAdd(path, watcher);
watcher.EnableRaisingEvents = true;
return watcher;
}
return null;
}
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
public FileSystemWatcher GetWatcher(string path)
{
FileSystemWatcher watcher;
if (!watchers.TryGetValue(path, out watcher))
{
return null;
}
return watcher;
}
protected virtual void Dispose(bool disposing)
{
if (this.disposed)
{
return;
}
if (disposing)
{
// Clean up managed resources
if (watchers != null)
{
foreach (var watcher in watchers.Values)
{
watcher.EnableRaisingEvents = false;
watcher.Dispose();
}
watchers = null;
}
this.disposed = true;
}
}
}
Whether you have a WPF app, a WinForms app or a Service, all of these have events Initialized, which is a good place to initialize your class, and Closed, which is a good place to dispose it. (In a console app you can simply put everything in a try..finally)
I'm defining my DbConntextObj
_container.RegisterType<IDbConntextObj, DbConntextObj>(new HttpContextLifetimeManager<DbConntextObj>());
Unity is not calling the RemoveValue() on the lifetimemanager
I have one Dbcontext for multiple repositories.
My lifetimemanager looks like this:
public class HttpContextLifetimeManager<T> : LifetimeManager, IDisposable
{
private readonly string _itemName = typeof(T).AssemblyQualifiedName;
public override object GetValue()
{
return HttpContext.Current.Items[_itemName];
}
public override void RemoveValue()
{
var disposable = GetValue() as IDisposable;
HttpContext.Current.Items.Remove(_itemName);
if (disposable != null)
disposable.Dispose();
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[_itemName] = newValue;
}
public void Dispose()
{
RemoveValue();
}
}
Is it a bad thing that DbContext Dispose is not being called?
Is there a workaround For Unity and MVC3?
Try this.
public class MvcApplication : HttpApplication
{
private IUnityContainer unityContainer;
private HttpContextDisposableLifetimeManager ContextLifeTimeManager;
/// <summary>
/// The start method of the application.
/// </summary>
protected void Application_Start()
{
unityContainer = new UnityContainer();
ContextLifeTimeManager = new HttpContextDisposableLifetimeManager();
//for some reason this event handler registration doesn't work, meaning we have to add code to
//Application_EndRequest as below...
//this.EndRequest += new EventHandler(ContextLifeTimeManager.DisposingHandler);
unityContainer.RegisterType<IUnitOfWork, EFUnitOfWork>(ContextLifeTimeManager);
unityContainer.RegisterType<IRepository<ShoppingCart>, ShoppingCartRepository>(new ContainerControlledLifetimeManager());
}
//this seems hackish, but it works, so whatever...
protected void Application_EndRequest(Object sender, EventArgs e)
{
if (ContextLifeTimeManager != null)
{
ContextLifeTimeManager.RemoveValue();
}
}
}
Then in your LifeTimeManager implementation.
public class HttpContextDisposableLifetimeManager : LifetimeManager, IDisposable
{
const string _itemName = typeof(T).AssemblyQualifiedName;
public void DisposingHandler(object source, EventArgs e)
{
RemoveValue();
}
public override object GetValue()
{
return HttpContext.Current.Items[_itemName];
}
public override void RemoveValue()
{
Dispose();
HttpContext.Current.Items.Remove(_itemName);
}
public override void SetValue(object newValue)
{
HttpContext.Current.Items[_itemName] = newValue;
}
public void Dispose()
{
var obj = (IDisposable)GetValue();
obj.Dispose();
}
}