I have a long running operation in my Winforms project. I am calling a long running synchronization operation from one to another class.
So, In Class1, I am performing a single run of the synchronization operation and calling synchronizer.Synchronize(); which is implemented in Class2.
Any type of MemberShipSynchronization service interupption or Stopped is disposed in Class1 in its Dispose().
From Class2, I am calling the populator.PopulateMembership(); which is implemented in Class3, So, the PopulateMembership() in class3 is long running process.
I want to make this operation Cancellable, means, I want to send the CancellableToken from Class1 to Class3 based on MemberShipSynchronization Service request ( i.e. Stop/Interuppted) and
when the long running operation in Class3 receive the Cancellation request that time I want to Cancel this operation.
So finally, I want to handle this operation gracefully in Class1.
Please suggest a better workaround to achieve this.
=>Class1.
public sealed class MembershipSynchronizationService : IDisposable
{
private readonly object _sync = new object();
/// <summary>
/// Performs a single run of the synchronization service.
/// </summary>
public void RunOnce()
{
lock (_sync)
{
var synchronizer = new MembershipSynchronizer(MembershipManagerUnsecured.SoleInstance.MembershipManager);
synchronizer.Synchronize();
}
}
#region Dispose pattern
/// <summary>
/// Finalizer. Cleans up resources.
/// </summary>
~MembershipSynchronizationService()
{
Dispose(false);
}
/// <summary>
/// Cleans up resources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
/// Cleans up resources.
/// </summary>
private void Dispose(bool disposing)
{
if (disposing)
{
lock (_sync)
{
// nothing to do
_ = this;
}
}
}
#endregion
}
=> Class2.
internal sealed class MembershipSynchronizer
{
/// <summary>
/// Performs a single run of the synchronization service.
/// </summary>
public void Synchronize()
{
try
{
TimeSpan elapsed;
var stopwatch = Stopwatch.StartNew();
var populator = _membershipPopulatorFactory.CreatePopulator();
populator.PopulateMembership(); // Time consuming operation.
}
catch (Exception e)
{
LoggingUtility.LogTrace(LoggingCategory.Membership, e);
}
}
=> Class3.
/// <summary>
/// The main implementation of the membership populator.
/// </summary>
public sealed class Populator : IDisposable, IMembershipPopulator
{
public void PopulateMembership()
{
// Code for some time consuming operations.
// ........................................
// ........................................
// ........................................
}
}
}
Related
I am currently developing a unit of work and repository pattern on top of NHibernate (As a remark: I didn't made the decision for one or another pattern, therefore please don't discuss the usefulness of the repository pattern in regards to am ORM that already implements one).
I first build per documentation a singleton (using IoC configuration) Sessionmanager that creates Units of Work instances (private methods removed for readability):
public sealed class SessionManager : ISessionManager
{
#region Members
/// <summary>
/// lock to manage thread safe access to the dictionary.
/// </summary>
private readonly ReaderWriterLockSlim _lock;
/// <summary>
/// NHibernate sessionfactory to create sessions.
/// </summary>
private readonly ISessionFactory _factory;
/// <summary>
/// Units of Work that are already in use.
/// </summary>
private readonly Dictionary<string, IUnitOfWork> _units;
/// <summary>
/// Flag indicating if the manager got disposed.
/// </summary>
private bool _disposed;
#endregion
#region Constructors
/// <summary>
/// Creates a new Manager with the given Config.
/// </summary>
/// <param name="config"></param>
public SessionManager(NHibernate.Cfg.Configuration config)
{
_lock = new ReaderWriterLockSlim();
_units = new Dictionary<string, IUnitOfWork>();
_factory = config
.Configure()
.AddAssembly(typeof(SessionManager).Assembly.FullName)
.BuildSessionFactory();
_disposed = false;
}
#endregion
#region Methods
/// <summary>
/// Either creates or returns an existing unit of work.
/// </summary>
/// <param name="identifier">identifier of the uow</param>
/// <param name="access">the data access that is needed for this uow.</param>
/// <returns></returns>
public IUnitOfWork Create(string identifier, DataAccess access)
{
Throw.IfNull(identifier, nameof(identifier));
if (TryGetUnitOfWork(identifier, out var unit))
return unit;
return CreateOrReturn(identifier, access);
}
/// <summary>
/// Disposes the given instance.
/// </summary>
/// <param name="unitOfWork">The unit of work that should get disposed.</param>
public void DisposeUnitOfWork(IUnitOfWork unitOfWork)
{
Throw.IfNull(unitOfWork, nameof(unitOfWork));
try
{
_lock.EnterWriteLock();
if (_units.ContainsValue(unitOfWork))
{
var key = _units.FirstOrDefault(x => x.Value.Equals(unitOfWork)).Key;
if (!string.IsNullOrWhiteSpace(key))
_units.Remove(key);
}
unitOfWork.Dispose();
}
finally
{
_lock.ExitWriteLock();
}
unitOfWork.Dispose();
}
/// <summary>
/// Disposes managed and unmanaged ressources.
/// </summary>
/// <param name="disposing">Flag indicating if the call happened in the public <see cref="Dispose"/> method or the Finalizer.</param>
void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
foreach (var unit in _units)
unit.Value.Dispose();
_factory.Dispose();
_lock.Dispose();
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
_disposed = true;
}
}
/// <summary>
/// Disposes managed and unmanaged ressources.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
}
}
The unit of work contains either a ISession or a IStatelessSession to create Transactions or the needed repositories.
public sealed class UnitOfWork : IUnitOfWork
{
#region Members
private bool _disposed;
public string Identifier { get; }
public DataAccess Access { get; }
private readonly ISession _session;
private readonly IStatelessSession _statelessSession;
#endregion
#region Constructors
private UnitOfWork(DataAccess access, string identifier)
{
Access = access;
Identifier = identifier;
_disposed = false;
}
internal UnitOfWork(DataAccess access, string identifier, ISession session)
: this(access, identifier)
{
_session = session;
}
internal UnitOfWork(DataAccess access, string identifier, IStatelessSession session)
: this(access, identifier)
{
_statelessSession = session;
}
#endregion
#region Methods
public void CloseTransaction(IGenericTransaction transaction)
{
transaction.Dispose();
}
public IGenericTransaction OpenTransaction()
{
if (_session != null)
return new GenericTransaction(_session.BeginTransaction());
if (_statelessSession != null)
return new GenericTransaction(_statelessSession.BeginTransaction());
throw new InvalidOperationException("You tried to create a transaction without having a vaild session.");
}
public IGenericTransaction OpenTransaction(IsolationLevel level)
{
if (_session != null)
return new GenericTransaction(_session.BeginTransaction(level), level);
if (_statelessSession != null)
return new GenericTransaction(_statelessSession.BeginTransaction(level), level);
throw new InvalidOperationException("You tried to create a transaction without having a vaild session.");
}
public bool Equals(IUnitOfWork other)
{
if (other == null)
return false;
return Access == other.Access;
}
public IRepository<T> GetRepository<T>() where T : Entity<T>
{
switch (Access)
{
case DataAccess.Statefull:
return new StatefullRepository<T>(_session);
case DataAccess.Stateless:
return new StatelessRepository<T>(_statelessSession);
default:
throw new ArgumentException("Cannot determine which repository is needed.", nameof(Access));
}
}
#region IDisposable Support
void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (_session != null)
_session.Dispose();
if (_statelessSession != null)
_statelessSession.Dispose();
}
// TODO: free unmanaged resources (unmanaged objects) and override a finalizer below.
// TODO: set large fields to null.
_disposed = true;
}
}
// TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources.
// ~UnitOfWork() {
// // Do not change this code. Put cleanup code in Dispose(bool disposing) above.
// Dispose(false);
// }
// This code added to correctly implement the disposable pattern.
public void Dispose()
{
// Do not change this code. Put cleanup code in Dispose(bool disposing) above.
Dispose(true);
// TODO: uncomment the following line if the finalizer is overridden above.
// GC.SuppressFinalize(this);
}
#endregion
#endregion
}
As one can see the Repositories get created using either the ISession or the IStatelessSession. Both of these Interfaces implement the IDisposable interfaces meaning they should get disposed. Therefore my repositories implement IDisposable as well. Here however is the problem. In theory I can create as many repositories as I want from one unit of work e.g. :
public void UpdatePets(List<Cat> felines, List<Dog> carnines, ISessionManager manager)
{
var uow = manager.Create("Pets", DataAccess.Statefull);
using (var t = uow.OpenTransaction())
{
using (var catRepo = uow.GetRepository<Cat>())
{
catRepo.Add(felines);
t.Commit();
}
}
//Some Businesslogic that forbids using one Transaction to mitigate the problem of an already disposed ISession or IStatelessSession.
using(var t = uow.OpenTransaction())
{
using (var dogRepo = uow.GetRepository<Dog>())
{
dogRepo.Add(carnines);
t.Commit();
}
}
}
If that would be the service consuming my unit of work and I would use the "standard" IDisposable Pattern like this:
private void Dispose(bool disposing)
{
if (!_disposed)
{
if (disposing)
{
if (_session != null)
_session.Dispose();
}
_disposed = true;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
The second Repository would throw an ObjectDisposedexception because the ISession I reference in the second one is coming from my unit of work and that one was already disposed when my first repository left the using block. So to overcome this Problem I would do the following in my repository:
public void Dispose()
{
_session = null;
GC.SuppressFinalize(this);
}
This however feels wrong because instead of properly disposing the reference to an object that I should dispose I just "close my Eyes and forget about it" which is probably never to good of a solution in programming.
So my question is basically: "Is there a good way to properly dispose objects that might live longer than the object holding the reference?"
You need to establish ownership, and use that to determine which class is responsible for cleaning each "thing" up. It's the owner and only the owner that should call Dispose, no matter how many other classes may have interacted with it.
Ownership needs to be exclusive and (except for wrapper classes) nested1 - the lifetime of the owner needs to be at least as long as the owned object. It's by following these two rules that we can ensure that Dispose is a) called once2 b) when the object is no longer required.
The repositories are the wrong thing to "own" the session. Multiple repositories can be given the same session (so if they're the owners, we've lost the exclusive property), and as your own title alludes to, they have a shorter lifetime than it.
Some general rules of thumb
an object passed as a parameter to an instance method will not normally become owned by the instance.
an object created by an instance and that lives longer than the lifetime of a single method call will be owned by the instance
an object created by an instance method and that doesn't live longer than the lifetime of a single method call will be owned by the method
1For wrappers, the inner object will tend to be created first, possibly configured, then passed to the wrapper object. So the wrapper object's lifetime starts after the inner object.
2Not strictly required. Disposables should tolerate Dispose being called multiple times, but that's more for belt-and-braces defensiveness than a desired pattern.
If I have interface (example from apress book) which implements IDisposable like this
public interface IArchitectRepository : IDisposable
{
IEnumerable<Architect> GetArchitects();
Architect GetAchitectDetails(int id);
void Create(Achitect a);
void Update(Achitect a);
void Delete(int id);
void Save();
}
how would I implement Dispose method in derived class?
In book the it's left as NotImplementedException.
There is no reason why you would implement the Dispose pattern any differently than normal.
See Implementing a Dispose Method
Unlike most interfaces which imply obligations on the part of an implementing class, the only obligation of a class which implements IDisposable is to regard a call to Dispose as adequate notice that an instance is going to be abandoned. The real obligations imparted by IDisposable fall upon instance owners: if a type implements IDisposable, each instance should have one owner who is obligated to ensure that its Dispose method will gets called before it's abandoned; the owner may do this either by calling Dispose itself, or passing ownership to a new owner who would then assume the obligation.
Note that the owner of an IDisposable instance doesn't care what Dispose does provided that the instance may be safely abandoned after it returns. If some particular object can be safely abandoned before Dispose is called, there's no need for the Dispose method to do anything. It should not throw a NotImplementedException or NotSupportedException, since it should be no able to doing everything it needs to do (i.e. nothing).
You should look at MSDN for the complete example: http://msdn.microsoft.com/en-us/library/system.idisposable.aspx
The minimum would be:
public class ArchitectRepository : IArchitectRepository
{
// implement all the IArchitectRepository methods
public void Dispose()
{
// assuming your repository has a connection property
if (this.Connection != null)
this.Connection.Close();
// do the same for all other disposable objects your repository has created.
}
}
Whiting the concrete implementation you can overwrite as follows
public bool IsDisposed { get; set; }
public bool IsLockedForDisposing { get; set; }
/// <summary>
/// Dispose the Loaded Context
/// </summary>
///
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
// Disposing of managed code
context.Dispose();
// GC.Collect(context);
}
this.disposed = true;
}
}
public void Dispose()
{
if (!IsLockedForDisposing)
{
IsDisposed = true;
Dispose(true);
GC.SuppressFinalize(this);
}
}
I have some example code posted here (and included below): How do you properly implement the IDisposable pattern?
Microsoft has slightly more in-depth details here: Implement a Dispose method
#region IDisposable base-class implementation
//TODO remember to make this class inherit from IDisposable -> MyDisposableClass : IDisposable
/// <summary>
/// Gets or sets a value indicating whether this instance is disposed.
/// </summary>
/// <value>
/// <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
/// </value>
/// <remarks>Default initialization for a bool is 'false'</remarks>
private bool IsDisposed { get; set; }
/// <summary>
/// Implementation of Dispose according to .NET Framework Design Guidelines.
/// </summary>
/// <remarks>Do not make this method virtual.
/// A derived class should not be able to override this method.
/// </remarks>
public void Dispose()
{
Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SupressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
// Always use SuppressFinalize() in case a subclass
// of this type implements a finalizer.
GC.SuppressFinalize(this);
}
/// <summary>
/// Overloaded Implementation of Dispose.
/// </summary>
/// <param name="isDisposing"><c>true</c> to release both managed and unmanaged resources;
/// <c>false</c> to release only unmanaged resources.</param>
/// <remarks>
/// <list type="bulleted">Dispose(bool isDisposing) executes in two distinct scenarios.
/// <item>If <paramref name="isDisposing"/> equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.</item>
/// <item>If <paramref name="isDisposing"/> equals <c>false</c>, the method has been called
/// by the runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.</item></list>
/// </remarks>
protected virtual void Dispose(bool isDisposing)
{
// TODO If you need thread safety, use a lock around these
// operations, as well as in your methods that use the resource.
try
{
if (!this.IsDisposed)
{
// Explicitly set root references to null to expressly tell the GarbageCollector
// that the resources have been disposed of and its ok to release the memory
// allocated for them.
if (isDisposing)
{
// Release all managed resources here
// Need to unregister/detach yourself from the events. Always make sure
// the object is not null first before trying to unregister/detach them!
// Failure to unregister can be a BIG source of memory leaks
if (someDisposableObjectWithAnEventHandler != null)
{
someDisposableObjectWithAnEventHandler.SomeEvent -= someDelegate;
someDisposableObjectWithAnEventHandler.Dispose();
someDisposableObjectWithAnEventHandler = null;
}
// If this is a WinForm/UI control, uncomment this code
//if (components != null)
//{
// components.Dispose();
//}
}
// Release all unmanaged resources here
// (example) if (someComObject != null && Marshal.IsComObject(someComObject))
{
Marshal.FinalReleaseComObject(someComObject);
someComObject = null;
}
}
}
finally
{
this.IsDisposed = true;
}
}
//TODO Uncomment this code if this class will contain members which are UNmanaged
///// <summary>Finalizer for MyDisposableClass</summary>
///// <remarks>This finalizer will run only if the Dispose method does not get called.
///// It gives your base class the opportunity to finalize.
///// DO NOT provide finalizers in types derived from this class.
///// All code executed within a Finalizer MUST be thread-safe!</remarks>
// ~MyDisposableClass()
// {
// Dispose( false );
// }
#endregion IDisposable base-class implementation
Here is the code for properly implementing the IDisposable pattern in a derived class:
#region IDisposable derived-class implementation
/// <summary>
/// Gets or sets a value indicating whether this instance is disposed.
/// </summary>
/// <value>
/// <c>true</c> if this instance is disposed; otherwise, <c>false</c>.
/// </value>
/// <remarks>Default initialization for a bool is 'false'</remarks>
private bool IsDisposed { get; set; }
/// <summary>
/// Overloaded Implementation of Dispose.
/// </summary>
/// <param name="isDisposing"><c>true</c> to release both managed and unmanaged resources;
/// <c>false</c> to release only unmanaged resources.</param>
/// <remarks>
/// <list type="bulleted">Dispose(bool isDisposing) executes in two distinct scenarios.
/// <item>If <paramref name="isDisposing"/> equals true, the method has been called directly
/// or indirectly by a user's code. Managed and unmanaged resources
/// can be disposed.</item>
/// <item>If <paramref name="isDisposing"/> equals <c>false</c>, the method has been called
/// by the runtime from inside the finalizer and you should not reference
/// other objects. Only unmanaged resources can be disposed.</item></list>
/// </remarks>
protected override void Dispose(bool isDisposing)
{
// TODO If you need thread safety, use a lock around these
// operations, as well as in your methods that use the resource.
try
{
if (!this.IsDisposed)
{
// Explicitly set root references to null to expressly tell the GarbageCollector
// that the resources have been disposed of and its ok to release the memory
// allocated for them.
if (isDisposing)
{
// Release all managed resources here
// Need to unregister/detach yourself from the events. Always make sure
// the object is not null first before trying to unregister/detach them!
// Failure to unregister can be a BIG source of memory leaks
if (someDisposableObjectWithAnEventHandler != null)
{
someDisposableObjectWithAnEventHandler.SomeEvent -= someDelegate;
someDisposableObjectWithAnEventHandler.Dispose();
someDisposableObjectWithAnEventHandler = null;
}
// If this is a WinForm/UI contrlol, uncomment this code
//if (components != null)
//{
// components.Dispose();
//}
}
// Release all unmanaged resources here
// (example)
if (someComObject != null && Marshal.IsComObject(someComObject))
{
Marshal.FinalReleaseComObject(someComObject);
someComObject = null;
}
}
}
finally
{
this.IsDisposed = true;
// explicitly call the base class Dispose implementation
base.Dispose(isDisposing);
}
}
#endregion IDisposable derived-class implementation
I'm using Ninject and AOP to do some caching. I have a Attribute that I can apply to any method in my repository and on BeforeInvoke it will return my cached Object if there is one and AfterInvoke create a cached object. This all works great but I can't figure out how to stop initial method from being called, ie if there is a cached object the return that instead of calling a the intyercepted method. My interceptor is here:
public class CacheInterceptor : SimpleInterceptor
{
protected override void BeforeInvoke(IInvocation invocation)
{
Type returnType = invocation.Request.Method.ReturnType;
string cacheKey = CacheKeyBuilder.GetCacheKey(invocation, serializer);
object cachedValue = cache.Get(cacheKey);
if (cachedValue == null)
{
invocation.Proceed();
}
else
{
object returnValue = serializer.Deserialize(returnType, cachedValue);
invocation.ReturnValue = returnValue;
returnedCachedResult = true;
}
}
}
Even though in the else statement I am clearly not saying to call the invoked Method 'invocation.Proceed();' it still invokes it. How do I tell ninject to just return with the invocation.ReturnValue ?
You can't use SimpleInterceptor in this case because that is meant as base class for the most common scenario where you want to do an action before or after the actual method call. Also you are not allowed to call Proceed Instead implement the IInterceptor interface and put your code into the Intercept method.
But probably we should extend SimpleInterceptor in a future version so that you can prevent that the actual method is called:
public abstract class SimpleInterceptor : IInterceptor
{
private bool proceedInvocation = true;
/// <summary>
/// Intercepts the specified invocation.
/// </summary>
/// <param name="invocation">The invocation to intercept.</param>
public void Intercept( IInvocation invocation )
{
BeforeInvoke( invocation );
if (proceedInvocation)
{
invocation.Proceed();
AfterInvoke( invocation );
}
}
/// <summary>
/// When called in BeforeInvoke then the invokation in not proceeded anymore.
/// Or in other words the decorated method and AfterInvoke won't be called anymore.
/// Make sure you have assigned the return value in case it is not void.
/// </summary>
protected void DontProceedInvokation()
{
this.proceedInvocation = false;
}
/// <summary>
/// Takes some action before the invocation proceeds.
/// </summary>
/// <param name="invocation">The invocation that is being intercepted.</param>
protected virtual void BeforeInvoke( IInvocation invocation )
{
}
/// <summary>
/// Takes some action after the invocation proceeds.
/// </summary>
/// <param name="invocation">The invocation that is being intercepted.</param>
protected virtual void AfterInvoke( IInvocation invocation )
{
}
}
I have a NativeActivity derived activity that I wrote that is to use bookmarks as a trigger for a pick branch. Using something I found on MSDN I tried writing this to trigger the branch. The branch contains activities that fire service callbacks to remote clients via send activities. If I set a delay for the trigger, callbacks fire to the clients successfully. If I use my code activity, the pick branch activities don't fire.
public sealed class UpdateListener : NativeActivity<ClientUpdate>
{
[RequiredArgument]
public InArgument<string> BookmarkName { get; set; }
protected override void Execute(NativeActivityContext context)
{
context.CreateBookmark(BookmarkName.Get(context),
new BookmarkCallback(this.OnResumeBookmark));
}
protected override bool CanInduceIdle
{
get { return true; }
}
public void OnResumeBookmark(NativeActivityContext context, Bookmark bookmark, object obj )
{
Result.Set(context, (ClientUpdate)obj);
}
}
So it takes an arg to set the bookmark name for future bookmark references to execute the trigger. OnResumeBoookmark() takes in a ClientUpdate object that is passed by my application that is hosting the workflowapp. The activity is to return the object so the ClientUpdate can be passed to the workflow and have it sent to the remote clients via the send activity in the pick branch. In theory anyways.
For some reason it seems to be correct but feels wrong. I'm not sure if I should write the Activity in a different way to take care of what I need for my WF service.
I think your intentions would be a bit clearer if you created an extension (that implements IWorkflowInstanceExtension) to perform your action here.
For example:
public sealed class AsyncWorkExtension
: IWorkflowInstanceExtension
{
// only one extension per workflow
private WorkflowInstanceProxy _proxy;
private Bookmark _lastBookmark;
/// <summary>
/// Request the extension does some work for an activity
/// during which the activity will idle the workflow
/// </summary>
/// <param name="toResumeMe"></param>
public void DoWork(Bookmark toResumeMe)
{
_lastBookmark = toResumeMe;
// imagine I kick off some async op here
// when complete system calls WorkCompleted below
// NOTE: you CANNOT block here or you block the WF!
}
/// <summary>
/// Called by the system when long-running work is complete
/// </summary>
/// <param name="result"></param>
internal void WorkCompleted(object result)
{
//NOT good practice! example only
//this leaks resources search APM for details
_proxy.BeginResumeBookmark(_lastBookmark, result, null, null);
}
/// <summary>
/// When implemented, returns any additional extensions
/// the implementing class requires.
/// </summary>
/// <returns>
/// A collection of additional workflow extensions.
/// </returns>
IEnumerable<object> IWorkflowInstanceExtension
.GetAdditionalExtensions()
{
return new object[0];
}
/// <summary>
/// Sets the specified target
/// <see cref="WorkflowInstanceProxy"/>.
/// </summary>
/// <param name="instance">The target workflow instance to set.</param>
void IWorkflowInstanceExtension
.SetInstance(WorkflowInstanceProxy instance)
{
_proxy = instance;
}
}
Within the Activity, you'd use this thusly:
var ext = context.GetExtension<AsyncWorkExtension>();
var bookmark = context.CreateBookmark(BookmarkCallback);
ext.DoWork(bookmark);
return;
This way is much more explicit (instead of using the bookmark name to convey meaning to the "outside" world) and is much easier to extend if, say, you require to send out more information than a bookmark name.
Is there something actually resuming the bookmark here? If not the workflow will wait very patiently and nothing will happen.
I don't have much experience doing unit testing. From what I learned, code should be decoupled, and I should not strive to test private code, just public methods, setters, etc etc.
Now, I have grasped some basic testing concepts, but I have troubles applying more advanced stuff to this case... Dependency Injection, Inversion of Control, Mock Objects, etc - can't get my head around it just yet :(
Before I move on to code, here are the questions.
In a given class, what exactly should I try to test?
How can I accomplish those test tasks?
Is there something seriously wrong with class design, which prevents testing from being done properly (or is something just plain wrong even outside of testing context)?
What design patterns are useful to testing network code in general?
Also, I've been trying to obey "write tests first, then write code to make tests pass", that's why I wrote first two tests that simply instantiate class and run it, but then, when server was able to start and accept packets, I didn't know what to test next...
Okay, here goes the code snippet. (note: original code is split in several namespaces, that's why it may appear a little out of order)
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace MyProject1
{
/// <summary>
/// Packet buffer that is sent to/received from connection
/// </summary>
public class UDPPacketBuffer
{
/// <summary>
/// Buffer size constant
/// </summary>
public const int BUFFER_SIZE = 4096;
private byte[] _data;
/// <summary>
/// Byte array with buffered data
///
/// DataLength is automatically updated when Data is set
/// </summary>
/// <see cref="DataLength"/>
public byte[] Data { get { return _data; } set { _data = value; DataLength = value.Length; } }
/// <summary>
/// Integer with length of buffered data
/// </summary>
public int DataLength;
/// <summary>
/// Remote end point (IP Address and Port)
/// </summary>
public EndPoint RemoteEndPoint;
/// <summary>
/// Initializes <see cref="UDPPacketBuffer"/> class
/// </summary>
public UDPPacketBuffer()
{
// initialize byte array
this.Data = new byte[BUFFER_SIZE];
// this will be filled in by the caller (eg. udpSocket.BeginReceiveFrom)
RemoteEndPoint = (EndPoint)new IPEndPoint(IPAddress.Any, 0);
}
/// <summary>
/// Returns <see cref="Data"/> as a byte array shortened to <see cref="DataLength"/> number of bytes
/// </summary>
public byte[] ByteContent
{
get
{
if (DataLength > 0)
{
byte[] content = new byte[DataLength];
for (int i = 0; i < DataLength; i++)
content[i] = Data[i];
return content;
}
else
{
return Data;
}
}
}
/// <summary>
/// Returns <see cref="ByteContent"/> converted to string
/// </summary>
public string StringContent { get { return Encoding.ASCII.GetString(ByteContent); } }
}
/// <summary>
/// UDP packet-related event arguments passed when invoking events
/// </summary>
/// <example>
/// This example shows how to use UDPPacketEventArgs class when event is invoked.
/// <code>
/// if (PacketSent != null)
/// PacketSent(this, new UDPPacketEventArgs(buffer, bytesSent));
/// </code>
/// </example>
public class UDPPacketEventArgs : EventArgs
{
/// <summary>
/// Instance of UDPPacketBuffer, holding current event-related buffer
/// </summary>
public UDPPacketBuffer buffer { get; private set; }
/// <summary>
/// Number of bytes sent to remote end point
/// </summary>
public int sent { get; private set; }
/// <summary>
/// Initializes <see cref="buffer"/> only. Used when receiving data.
/// </summary>
/// <param name="buffer">Buffer sent to or received from remote endpoint</param>
public UDPPacketEventArgs(UDPPacketBuffer buffer)
{
this.buffer = buffer;
}
/// <summary>
/// Initializes <see cref="buffer"/> and <see cref="sent"/> variables. Used when sending data.
/// </summary>
/// <param name="buffer">buffer that has been sent</param>
/// <param name="sent">number of bytes sent</param>
public UDPPacketEventArgs(UDPPacketBuffer buffer, int sent)
{
this.buffer = buffer;
this.sent = sent;
}
}
/// <summary>
/// Asynchronous UDP server
/// </summary>
public class AsyncUdp : ServerBase
{
private const int _defaultPort = 45112;
private int _udpPort;
/// <summary>
/// Port number on which server should listen
/// </summary>
public int udpPort { get { return _udpPort; } private set { _udpPort = value; } }
// should server listen for broadcasts?
private bool broadcast = false;
// server socket
private Socket udpSocket;
// the ReaderWriterLock is used solely for the purposes of shutdown (Stop()).
// since there are potentially many "reader" threads in the internal .NET IOCP
// thread pool, this is a cheaper synchronization primitive than using
// a Mutex object. This allows many UDP socket "reads" concurrently - when
// Stop() is called, it attempts to obtain a writer lock which will then
// wait until all outstanding operations are completed before shutting down.
// this avoids the problem of closing the socket with outstanding operations
// and trying to catch the inevitable ObjectDisposedException.
private ReaderWriterLock rwLock = new ReaderWriterLock();
// number of outstanding operations. This is a reference count
// which we use to ensure that the threads exit cleanly. Note that
// we need this because the threads will potentially still need to process
// data even after the socket is closed.
private int rwOperationCount = 0;
// the all important shutdownFlag. This is synchronized through the ReaderWriterLock.
private bool shutdownFlag = true;
/// <summary>
/// Returns server running state
/// </summary>
public bool IsRunning
{
get { return !shutdownFlag; }
}
/// <summary>
/// Initializes UDP server with arbitrary default port
/// </summary>
public AsyncUdp()
{
this.udpPort = _defaultPort;
}
/// <summary>
/// Initializes UDP server with specified port number
/// </summary>
/// <param name="port">Port number for server to listen on</param>
public AsyncUdp(int port)
{
this.udpPort = port;
}
/// <summary>
/// Initializes UDP server with specified port number and broadcast capability
/// </summary>
/// <param name="port">Port number for server to listen on</param>
/// <param name="broadcast">Server will have broadcasting enabled if set to true</param>
public AsyncUdp(int port, bool broadcast)
{
this.udpPort = port;
this.broadcast = broadcast;
}
/// <summary>
/// Raised when packet is received via UDP socket
/// </summary>
public event EventHandler PacketReceived;
/// <summary>
/// Raised when packet is sent via UDP socket
/// </summary>
public event EventHandler PacketSent;
/// <summary>
/// Starts UDP server
/// </summary>
public override void Start()
{
if (! IsRunning)
{
// create and bind the socket
IPEndPoint ipep = new IPEndPoint(IPAddress.Any, udpPort);
udpSocket = new Socket(
AddressFamily.InterNetwork,
SocketType.Dgram,
ProtocolType.Udp);
udpSocket.EnableBroadcast = broadcast;
// we don't want to receive our own broadcasts, if broadcasting is enabled
if (broadcast)
udpSocket.MulticastLoopback = false;
udpSocket.Bind(ipep);
// we're not shutting down, we're starting up
shutdownFlag = false;
// kick off an async receive. The Start() method will return, the
// actual receives will occur asynchronously and will be caught in
// AsyncEndRecieve().
// I experimented with posting multiple AsyncBeginReceives() here in an attempt
// to "queue up" reads, however I found that it negatively impacted performance.
AsyncBeginReceive();
}
}
/// <summary>
/// Stops UDP server, if it is running
/// </summary>
public override void Stop()
{
if (IsRunning)
{
// wait indefinitely for a writer lock. Once this is called, the .NET runtime
// will deny any more reader locks, in effect blocking all other send/receive
// threads. Once we have the lock, we set shutdownFlag to inform the other
// threads that the socket is closed.
rwLock.AcquireWriterLock(-1);
shutdownFlag = true;
udpSocket.Close();
rwLock.ReleaseWriterLock();
// wait for any pending operations to complete on other
// threads before exiting.
while (rwOperationCount > 0)
Thread.Sleep(1);
}
}
/// <summary>
/// Dispose handler for UDP server. Stops the server first if it is still running
/// </summary>
public override void Dispose()
{
if (IsRunning == true)
this.Stop();
}
private void AsyncBeginReceive()
{
// this method actually kicks off the async read on the socket.
// we aquire a reader lock here to ensure that no other thread
// is trying to set shutdownFlag and close the socket.
rwLock.AcquireReaderLock(-1);
if (!shutdownFlag)
{
// increment the count of pending operations
Interlocked.Increment(ref rwOperationCount);
// allocate a packet buffer
UDPPacketBuffer buf = new UDPPacketBuffer();
try
{
// kick off an async read
udpSocket.BeginReceiveFrom(
buf.Data,
0,
UDPPacketBuffer.BUFFER_SIZE,
SocketFlags.None,
ref buf.RemoteEndPoint,
new AsyncCallback(AsyncEndReceive),
buf);
}
catch (SocketException)
{
// an error occurred, therefore the operation is void. Decrement the reference count.
Interlocked.Decrement(ref rwOperationCount);
}
}
// we're done with the socket for now, release the reader lock.
rwLock.ReleaseReaderLock();
}
private void AsyncEndReceive(IAsyncResult iar)
{
// Asynchronous receive operations will complete here through the call
// to AsyncBeginReceive
// aquire a reader lock
rwLock.AcquireReaderLock(-1);
if (!shutdownFlag)
{
// start another receive - this keeps the server going!
AsyncBeginReceive();
// get the buffer that was created in AsyncBeginReceive
// this is the received data
UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
try
{
// get the length of data actually read from the socket, store it with the
// buffer
buffer.DataLength = udpSocket.EndReceiveFrom(iar, ref buffer.RemoteEndPoint);
// this operation is now complete, decrement the reference count
Interlocked.Decrement(ref rwOperationCount);
// we're done with the socket, release the reader lock
rwLock.ReleaseReaderLock();
// run event PacketReceived(), passing the buffer that
// has just been filled from the socket read.
if (PacketReceived != null)
PacketReceived(this, new UDPPacketEventArgs(buffer));
}
catch (SocketException)
{
// an error occurred, therefore the operation is void. Decrement the reference count.
Interlocked.Decrement(ref rwOperationCount);
// we're done with the socket for now, release the reader lock.
rwLock.ReleaseReaderLock();
}
}
else
{
// nothing bad happened, but we are done with the operation
// decrement the reference count and release the reader lock
Interlocked.Decrement(ref rwOperationCount);
rwLock.ReleaseReaderLock();
}
}
/// <summary>
/// Send packet to remote end point speified in <see cref="UDPPacketBuffer"/>
/// </summary>
/// <param name="buf">Packet to send</param>
public void AsyncBeginSend(UDPPacketBuffer buf)
{
// by now you should you get the idea - no further explanation necessary
rwLock.AcquireReaderLock(-1);
if (!shutdownFlag)
{
try
{
Interlocked.Increment(ref rwOperationCount);
udpSocket.BeginSendTo(
buf.Data,
0,
buf.DataLength,
SocketFlags.None,
buf.RemoteEndPoint,
new AsyncCallback(AsyncEndSend),
buf);
}
catch (SocketException)
{
throw new NotImplementedException();
}
}
rwLock.ReleaseReaderLock();
}
private void AsyncEndSend(IAsyncResult iar)
{
// by now you should you get the idea - no further explanation necessary
rwLock.AcquireReaderLock(-1);
if (!shutdownFlag)
{
UDPPacketBuffer buffer = (UDPPacketBuffer)iar.AsyncState;
try
{
int bytesSent = udpSocket.EndSendTo(iar);
// note that in invocation of PacketSent event - we are passing the number
// of bytes sent in a separate parameter, since we can't use buffer.DataLength which
// is the number of bytes to send (or bytes received depending upon whether this
// buffer was part of a send or a receive).
if (PacketSent != null)
PacketSent(this, new UDPPacketEventArgs(buffer, bytesSent));
}
catch (SocketException)
{
throw new NotImplementedException();
}
}
Interlocked.Decrement(ref rwOperationCount);
rwLock.ReleaseReaderLock();
}
}
/// <summary>
/// Base class used for all network-oriented servers.
/// <para>Disposable. All methods are abstract, including Dispose().</para>
/// </summary>
/// <example>
/// This example shows how to inherit from ServerBase class.
/// <code>
/// public class SyncTcp : ServerBase {...}
/// </code>
/// </example>
abstract public class ServerBase : IDisposable
{
/// <summary>
/// Starts the server.
/// </summary>
abstract public void Start();
/// <summary>
/// Stops the server.
/// </summary>
abstract public void Stop();
#region IDisposable Members
/// <summary>
/// Cleans up after server.
/// <para>It usually calls Stop() if server is running.</para>
/// </summary>
public abstract void Dispose();
#endregion
}
}
"Test code" follows.
namespace MyProject1
{
class AsyncUdpTest
{
[Fact]
public void UdpServerInstance()
{
AsyncUdp udp = new AsyncUdp();
Assert.True(udp is AsyncUdp);
udp.Dispose();
}
[Fact]
public void StartStopUdpServer()
{
using (AsyncUdp udp = new AsyncUdp(5000))
{
udp.Start();
Thread.Sleep(5000);
}
}
string udpReceiveMessageSend = "This is a test message";
byte[] udpReceiveData = new byte[4096];
bool udpReceivePacketMatches = false;
[Fact]
public void UdpServerReceive()
{
using (AsyncUdp udp = new AsyncUdp(5000))
{
udp.Start();
udp.PacketReceived += new EventHandler(delegate(object sender, EventArgs e)
{
UDPPacketEventArgs ea = e as UDPPacketEventArgs;
if (this.udpReceiveMessageSend.Equals(ea.buffer.StringContent))
{
udpReceivePacketMatches = true;
}
});
// wait 20 ms for a socket to be bound etc
Thread.Sleep(20);
UdpClient sock = new UdpClient();
IPEndPoint iep = new IPEndPoint(IPAddress.Loopback, 5000);
this.udpReceiveData = Encoding.ASCII.GetBytes(this.udpReceiveMessageSend);
sock.Send(this.udpReceiveData, this.udpReceiveData.Length, iep);
sock.Close();
// wait 20 ms for an event to fire, it should be enough
Thread.Sleep(20);
Assert.True(udpReceivePacketMatches);
}
}
}
}
note: code is c#, testing framework xUnit
A big thanks to everyone who takes time to go through my question and answer it!
Should you test ? Absolutely. You need to engineer your code for testability to make this simple. Your first statement is largely correct. So, some further comments:
Unit testing is largely testing code alone against test data and not reliant on external systems/servers etc. Functional/integration testing then brings in your external servers/databases etc. You can use dependency injection to inject either that real external system reference, or a test (mocked) system implementing the same interface, and thus your code becomes easily testable.
So in the above you would probably want to inject the UDP data source into your receiver. Your data source would implement a particular interface, and a mocked (or simple test) source would provide different packets for testing (e.g. empty, containing valid data, containing invalid data). That would form the basis of your unit test.
Your integration (or functional? I never know what to call it) test would perhaps start up a test UDP data source in the same VM, for each test, and pump data via UDP to your receiver. So now you've tested the basic functionality in the face of different packets via your unit test, and you're testing the actual UDP client/server function via your integration test.
So now you've tested your packet transmission/reception, you can test further parts of your code. Your UDP receiver will plug into another component, and here you can use dependency injection to inject the UDP receiver into your upstream component, or a mocked/test receiver implementing the same interface (and so on).
(Note: given that UDP transmission is unreliable even intra-host you should be prepared to cater for that somehow, or accept that infrequently you'll have problems. But that's a UDP-specific issue).
I notices some design problems in your code, and I think that this problems also interfere with ability to test this code.
I don't really unserstand UDPPacketBuffer class purpose. This class isn't encapsulate anything. It contains read/write Data property and I noticed only one probably useful is StringContent.
If you assume pass through UDP some application level packets, maybe you should create appropriate abstractions for this packets. Also, using UDP you should create something that helps you gather all parts in one (because you can receive parts of your packets in different order).
Also, I don't understand why your UDPPacketBuffer contains IPEndPoint.
That's why you can't test this class, because there no obvious purpose for this class.
It's really hard to test class that sends and receives data over network. But I notices some problems with your AsyncUdp implementation.
2.1 There is no packets delivery guarantee. I mean, who responsible for reliable packet delivery?
2.2 Ther is no thread safe (due to lack of exception safety).
What happens if Start method would be called simultaneously from separate threads?
And, consider following code (From Stop method):
rwLock.AcquireWriterLock(-1);
shutdownFlag = true;
udpSocket.Close();
rwLock.ReleaseWriterLock();
What if updSocket.Close method raise an exception? In this case rwLock whould stay in acquired state.
And in AsyncBeginReceive: what if UDPPacketBuffer ctor throws an exception, or udpSocket.BeginReceiveFrom throws SecurityException or ArgumentOutOfRangeException.
Other functions also not thread safe due to unhandled exception.
In this case you may create some helper class, that can be used in using statemant.
Something like this:
class ReadLockHelper : IDisposable
{
public ReadLockHelper(ReaderWriterLockSlim rwLock)
{
rwLock.AcquireReadLock(-1);
this.rwLock = rwLock;
}
public void Dispose()
{
rwLock.ReleaseReadLock();
}
private ReaderWriterLockSlim rwLock;
}
And than use it in your methods:
using (var l = new ReadLockHelper(rwLock))
{
//all other stuff
}
And finally. You should use ReaderWriterLockSlim instead ReaderWriterLock.
Important note from MSDN:
The .NET Framework has two reader-writer locks, ReaderWriterLockSlim and ReaderWriterLock. ReaderWriterLockSlim is recommended for all new development. ReaderWriterLockSlim is similar to ReaderWriterLock, but it has simplified rules for recursion and for upgrading and downgrading lock state. ReaderWriterLockSlim avoids many cases of potential deadlock. In addition, the performance of ReaderWriterLockSlim is significantly better than ReaderWriterLock.