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.
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 want to Override base class methods in derived class and then do something in derived class. therefore the base class method be invoked with its generic type . Then I aim to fire the derived class method which is overridden.
I have below codes :
public class Service<T> : Interface.IService<T> where T : class
{
public virtual event System.EventHandler<EntitySavingEventArgs<T>> BeforeSavingRecord;
public Service()
{
}
public virtual void OnBeforeSavingRecord(object sender, EntitySavingEventArgs<T> e)
{
}
private readonly DbContext _dbContext;
public Service(DbContext dbContext)
{
_dbContext = dbContext;
}
public virtual void Create(T item)
{
if (item == null)
throw new ArgumentNullException("item");
BeforeSavingRecord?.Invoke(this, new EntitySavingEventArgs<T>() { SavedEntity = item });
_dbContext.Set(typeof(T)).Add(item);
_dbContext.SaveChanges();
}
}
and in its derrived classes I have something like this :
[Service]
public partial class BankBusiness : Service<Bank>, IBankBusiness
{
public BankBusiness()
: base(ContainerManager.Container.Resolve<MyContext>())
{
}
public override void OnBeforeSavingRecord(object sender, EntitySavingEventArgs<Bank> e)
{
//Do something with entity item before saving
base.OnBeforeSavingRecord(sender, e);
}
}
And then in my controllers when I call
bankBiz.Create(new Bank() { ... });
I want to fire bankBiz (derrived class) overridden method (OnBeforeSavingRecord) which is registered to BeforeSavingRecord event.
I donot know if my scenario is correct and if it is right how i can fire it.
if it is not correct what I should do.
I had a similar pattern implemented in the base class I did it in a way like this:
Base:
public virtual void OnBeforeSavingRecord(object sender, EntitySavingEventArgs<T> e)
{ }
and in the derived class I had exactly the call that you use:
Derivied:
public override void OnBeforeSavingRecord(object sender, EntitySavingEventArgs<Bank> e)
{
//Do something with entity item before saving
base.OnBeforeSavingRecord(sender, e);
}
To fire the event in my case it was sufficient to just call
OnBeforeSavingRecord(this, new EntitySavingEventArgs<T>() { SavedEntity = item });
and the whole scenario worked for me.
EDIT:
Calling OnBeforeSavingRecord will executed the code in the overriden method of the derived class if you call it from an instance of the derived class!
If I understand you right you want to fire the event in the method Create but want the event code of the derived class executed. It will be if the event is overridden like in your case. You could test it with this simple Console application: (just copy paste and run)
public class Service
{
public virtual event System.EventHandler<EventArgs> BeforeSavingRecord;
public virtual void OnBeforeSavingRecord(object sender, EventArgs e)
{
Console.WriteLine("Base: OnBeforeSavingRecord method call");
}
public virtual void Create(object item)
{
Console.WriteLine("Base: Create method call");
// this will call the method of the derived class! if you call it from an instance of the derived class
OnBeforeSavingRecord(this, new EventArgs());
}
}
public partial class BankBusiness : Service
{
public override void OnBeforeSavingRecord(object sender, EventArgs e)
{
//Do something with entity item before saving
Console.WriteLine("Derived Class OnBeforeSavingRecord CALL");
base.OnBeforeSavingRecord(sender, e);
}
}
static void Main(string[] args)
{
BankBusiness bankBiz = new BankBusiness();
bankBiz.Create(new object());
Console.ReadKey();
}
#Mong Zhu your solution works but not for my scenario . I came up with the below solution
public class Service<T> : Interface.IService<T> where T : class
{
Interface.IService<T> implementation;
public virtual event System.EventHandler<EntitySavingEventArgs<T>> BeforeSavingRecord;
public virtual event System.EventHandler<EntitySavingEventArgs<T>> SavingRecord;
public virtual event System.EventHandler<EntitySavingEventArgs<T>> RecordSaved;
public void PopulateEvents(Interface.IService<T> _implementation)
{
implementation = _implementation;
implementation.BeforeSavingRecord += new System.EventHandler<EntitySavingEventArgs<T>>(this.OnBeforeSavingRecord);
implementation.SavingRecord += new System.EventHandler<EntitySavingEventArgs<T>>(this.OnSavingRecord);
implementation.RecordSaved += new System.EventHandler<EntitySavingEventArgs<T>>(this.OnRecordSaved);
}
public virtual void OnBeforeSavingRecord(object sender, EntitySavingEventArgs<T> e)
{
}
public virtual void OnSavingRecord(object sender, EntitySavingEventArgs<T> e)
{
}
public virtual void OnRecordSaved(object sender, EntitySavingEventArgs<T> e)
{
}
private readonly DbContext _dbContext;
public Service(DbContext dbContext)
{
_dbContext = dbContext;
}
public virtual void Create(T item)
{
if (item == null)
throw new ArgumentNullException("item");
BeforeSavingRecord?.Invoke(this, new EntitySavingEventArgs<T>() { SavedEntity = item });
_dbContext.Set(typeof(T)).Add(item);
SavingRecord?.Invoke(this, new EntitySavingEventArgs<T>() { SavedEntity = item });
_dbContext.SaveChanges();
RecordSaved?.Invoke(this, new EntitySavingEventArgs<T>() { SavedEntity = item });
}
}
and the derived class :
[Service]
public partial class BankBusiness : Service<Bank>, IBankBusiness
{
public BankBusiness()
: base(ContainerManager.Container.Resolve<MyContext>())
{
base.PopulateEvents(this);
}
public override void OnBeforeSavingRecord(object sender, EntitySavingEventArgs<Bank> e)
{
base.OnBeforeSavingRecord(sender, e);
}
}
which the point is
base.PopulateEvents(this);
I am just looking into implementing an MVVMCross Messenger solution that will enable me to upload information to Google Analytics when published from either the iOS application or the PCL.
The problem I have the is that the subscription delgates are not fired after I publish. Can you subscribe to MVVMCross Messenger subscriptions from a static class?
Subscriptions in static class
public static class GoogleAnalyticsWrapper //: IDisposable
{
private const string TrackingId = "xxxxxxxxxxx";
private static readonly IMvxMessenger messenger;
private static readonly MvxSubscriptionToken screenNameToken;
private static readonly MvxSubscriptionToken eventToken;
private static readonly MvxSubscriptionToken exceptionToken;
private static readonly MvxSubscriptionToken performanceToken;
private static readonly MvxSubscriptionToken publishToken;
private static bool disposed = false;
private static SafeHandle handle;
static GoogleAnalyticsWrapper()
{
Gai.SharedInstance.DispatchInterval = 60;
Gai.SharedInstance.TrackUncaughtExceptions = true;
Gai.SharedInstance.GetTracker(TrackingId);
messenger = new MvxMessengerHub();// Mvx.Resolve<IMvxMessenger>();
screenNameToken = messenger.Subscribe<GaScreenNameMessage>((m) => SetScreenName(m));
int count = messenger.CountSubscriptionsFor<GaScreenNameMessage>();
eventToken = messenger.Subscribe<GaEventMessage>(CreateEvent);
exceptionToken = messenger.Subscribe<GaExceptionMessage>(CreateException);
performanceToken = messenger.Subscribe<GaPerformanceTimingMessage>(CreatePerformanceMetric);
publishToken = messenger.Subscribe<GaPublishMessage>(PublishAll);
}
public static string Dummy { get; set; }
public static void SetScreenName(GaScreenNameMessage message)
{
System.Diagnostics.Debugger.Break();
Gai.SharedInstance.DefaultTracker.Set(GaiConstants.ScreenName, message.ScreenName);
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateScreenView().Build());
}
public static void CreateEvent(GaEventMessage message)
=> Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateEvent(message.Category, message.Action, message.Label, message.Number).Build());
private static void CreateException(GaExceptionMessage message)
=> Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateException(message.ExceptionMessage, message.IsFatal).Build());
private static void CreatePerformanceMetric(GaPerformanceTimingMessage message)
=> Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateTiming(message.Category, message.Milliseconds, message.Name, message.Label).Build());
private static void PublishAll(GaPublishMessage message)
=> Gai.SharedInstance.Dispatch();
public static void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
// Dispose managed resources.
if (handle != null)
{
handle.Dispose();
}
}
// Dispose unmanaged managed resources.
disposed = true;
}
}
}
Publication
messengerService.Publish<GaEventMessage>(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
The problem is, that you are creating a new MvxMessengerHub in your static class, but (I guess) inject IMvxMessenger in your consuming classes, which is created by MvvMCross during the initialization lifecycle and so a different instance.
The easy solution would be to initialize it in your App.cs like
public class App : Cirrious.MvvmCross.ViewModels.MvxApplication
{
public override void Initialize()
{
// ...
var m = Cirrious.CrossCore.Mvx.Resolve<IMvxMessenger>();
GoogleAnalyticsWrapper.Initialize(m);
// ...
}
}
With a wrapper like this
public static class GoogleAnalyticsWrapper
{
static void Initialize(IMvxMessenger messenger)
{
Gai.SharedInstance.DispatchInterval = 60;
Gai.SharedInstance.TrackUncaughtExceptions = true;
Gai.SharedInstance.GetTracker(TrackingId);
screenNameToken = messenger.Subscribe<GaScreenNameMessage>((m) => SetScreenName(m));
int count = messenger.CountSubscriptionsFor<GaScreenNameMessage>();
eventToken = messenger.Subscribe<GaEventMessage>(CreateEvent);
exceptionToken = messenger.Subscribe<GaExceptionMessage>(CreateException);
performanceToken = messenger.Subscribe<GaPerformanceTimingMessage>(CreatePerformanceMetric);
publishToken = messenger.Subscribe<GaPublishMessage>(PublishAll);
}
// ...
}
Advanced Hint
But as far as I see, you don't even need messaging for this case, because it's one to one "communication". I think it would be nice, if you move the functionality of your GoogleAnalyticsWrapper into a well defined Service like:
interface ITrackingService
{
void SetScreenName(GaScreenNameMessage message);
void CreateEvent(GaEventMessage message);
void CreateException(GaExceptionMessage message);
void CreatePerformanceMetric(GaPerformanceTimingMessage message);
void PublishAll(GaPublishMessage message);
}
public class GoogleAnalyticsTrackingService : ITrackingService
{
private const string TrackingId = "xxxxxxxxxxx";
public GoogleAnalyticsTrackingService()
{
Gai.SharedInstance.DispatchInterval = 60;
Gai.SharedInstance.TrackUncaughtExceptions = true;
Gai.SharedInstance.GetTracker(TrackingId);
}
public void SetScreenName(GaScreenNameMessage message)
{
Gai.SharedInstance.DefaultTracker.Set(GaiConstants.ScreenName, message.ScreenName);
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateScreenView().Build());
}
public void CreateEvent(GaEventMessage message)
{
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateEvent(message.Category, message.Action, message.Label, message.Number).Build());
}
private void CreateException(GaExceptionMessage message)
{
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateException(message.ExceptionMessage, message.IsFatal).Build());
}
private void CreatePerformanceMetric(GaPerformanceTimingMessage message)
{
Gai.SharedInstance.DefaultTracker.Send(DictionaryBuilder.CreateTiming(message.Category, message.Milliseconds, message.Name, message.Label).Build());
}
private void PublishAll(GaPublishMessage message)
{
Gai.SharedInstance.Dispatch();
}
}
That has to be registered in your App
Mvx.LazyConstructAndRegisterSingleton<ITrackingService, GoogleAnalyticsTrackingService>();
And can be consumed with constructor injection or manual resolves
class MyViewModel : MvxViewModel
{
public MyViewModel(ITrackingService tracking)
{
tracking.CreateEvent(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
}
}
// or
class MyViewModel : MvxViewModel
{
public MyViewModel()
{
var tracking = Mvx.Resolve<ITrackingService>();
tracking.CreateEvent(new GaEventMessage(this, "Event", "Publish Event", "Publish Event From First View Model", 123));
}
}
There is still one Problem: The interface has still a dependency to google analytics. But the dependency can be easily removed by using multiple parameters instead of a parameter object.
interface ITrackingService
{
void CreateEvent(string eventName, string title, string message, params object[] additionalParams);
// ...
}
// call:
tracking.CreateEvent("Event", "Publish Event", "Publish Event From First View Model", 123);
With this, you are able to unit test it and exchange the tracking service with litte effort, if your stakeholders decide to switch to adobe omniture or whatever.
We all know about the singleton pattern.
How do you implement a singleton "method"? - a method that is called only once and any other call will do nothing.
I can think a few ways (including Lazy - if (!.IsValueCreated) {... value.method();}) but how would you implement it?
I don't think so there is something like a singleton method.
If you want your method to do execute the block of code only once then you can do that. This can be done in several ways, one of them could be as follows-
public class Foo
{
private static bool _isInitialied;
public void Initialize()
{
if(_isInitialied)
return;
//TODO: Initialization stups.
_isInitialied = true;
}
}
You could achieve this using actions:
public class Test
{
private Action _action;
private void DoSomething()
{
// Do something interesting
_action = DoNothing;
}
private void DoNothing()
{
}
public Test()
{
_action = DoSomething;
}
public void Call()
{
_action();
}
} // eo class Test
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();
}
}