For a given class I would like to have tracing functionality i.e. I would like to log every method call (method signature and actual parameter values) and every method exit (just the method signature).
How do I accomplish this assuming that:
I don't want to use any 3rd party
AOP libraries for C#,
I don't want to add duplicate code to all the methods that I want to trace,
I don't want to change the public API of the class - users of the class should be able to call all the methods in exactly the same way.
To make the question more concrete let's assume there are 3 classes:
public class Caller
{
public static void Call()
{
Traced traced = new Traced();
traced.Method1();
traced.Method2();
}
}
public class Traced
{
public void Method1(String name, Int32 value) { }
public void Method2(Object object) { }
}
public class Logger
{
public static void LogStart(MethodInfo method, Object[] parameterValues);
public static void LogEnd(MethodInfo method);
}
How do I invoke Logger.LogStart and Logger.LogEnd for every call to Method1 and Method2 without modifying the Caller.Call method and without adding the calls explicitly to Traced.Method1 and Traced.Method2?
Edit: What would be the solution if I'm allowed to slightly change the Call method?
C# is not an AOP oriented language. It has some AOP features and you can emulate some others but making AOP with C# is painful.
I looked up for ways to do exactly what you wanted to do and I found no easy way to do it.
As I understand it, this is what you want to do:
[Log()]
public void Method1(String name, Int32 value);
and in order to do that you have two main options
Inherit your class from MarshalByRefObject or ContextBoundObject and define an attribute which inherits from IMessageSink. This article has a good example. You have to consider nontheless that using a MarshalByRefObject the performance will go down like hell, and I mean it, I'm talking about a 10x performance lost so think carefully before trying that.
The other option is to inject code directly. In runtime, meaning you'll have to use reflection to "read" every class, get its attributes and inject the appropiate call (and for that matter I think you couldn't use the Reflection.Emit method as I think Reflection.Emit wouldn't allow you to insert new code inside an already existing method). At design time this will mean creating an extension to the CLR compiler which I have honestly no idea on how it's done.
The final option is using an IoC framework. Maybe it's not the perfect solution as most IoC frameworks works by defining entry points which allow methods to be hooked but, depending on what you want to achive, that might be a fair aproximation.
The simplest way to achieve that is probably to use PostSharp. It injects code inside your methods based on the attributes that you apply to it. It allows you to do exactly what you want.
Another option is to use the profiling API to inject code inside the method, but that is really hardcore.
You could achieve it with Interception feature of a DI container such as Castle Windsor. Indeed, it is possible to configure the container in such way that every classes that have a method decorated by a specific attribute would be intercepted.
Regarding point #3, OP asked for a solution without AOP framework. I assumed in the following answer that what should be avoided were Aspect, JointPoint, PointCut, etc. According to Interception documentation from CastleWindsor, none of those are required to accomplish what is asked.
Configure generic registration of an Interceptor, based on the presence of an attribute:
public class RequireInterception : IContributeComponentModelConstruction
{
public void ProcessModel(IKernel kernel, ComponentModel model)
{
if (HasAMethodDecoratedByLoggingAttribute(model.Implementation))
{
model.Interceptors.Add(new InterceptorReference(typeof(ConsoleLoggingInterceptor)));
model.Interceptors.Add(new InterceptorReference(typeof(NLogInterceptor)));
}
}
private bool HasAMethodDecoratedByLoggingAttribute(Type implementation)
{
foreach (var memberInfo in implementation.GetMembers())
{
var attribute = memberInfo.GetCustomAttributes(typeof(LogAttribute)).FirstOrDefault() as LogAttribute;
if (attribute != null)
{
return true;
}
}
return false;
}
}
Add the created IContributeComponentModelConstruction to container
container.Kernel.ComponentModelBuilder.AddContributor(new RequireInterception());
And you can do whatever you want in the interceptor itself
public class ConsoleLoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.Writeline("Log before executing");
invocation.Proceed();
Console.Writeline("Log after executing");
}
}
Add the logging attribute to your method to log
public class Traced
{
[Log]
public void Method1(String name, Int32 value) { }
[Log]
public void Method2(Object object) { }
}
Note that some handling of the attribute will be required if only some method of a class needs to be intercepted. By default, all public methods will be intercepted.
If you write a class - call it Tracing - that implements the IDisposable interface, you could wrap all method bodies in a
Using( Tracing tracing = new Tracing() ){ ... method body ...}
In the Tracing class you could the handle the logic of the traces in the constructor/Dispose method, respectively, in the Tracing class to keep track of the entering and exiting of the methods. Such that:
public class Traced
{
public void Method1(String name, Int32 value) {
using(Tracing tracer = new Tracing())
{
[... method body ...]
}
}
public void Method2(Object object) {
using(Tracing tracer = new Tracing())
{
[... method body ...]
}
}
}
If you want to trace after your methods without limitation (no code adaptation, no AOP Framework, no duplicate code), let me tell you, you need some magic...
Seriously, I resolved it to implement an AOP Framework working at runtime.
You can find here : NConcern .NET AOP Framework
I decided to create this AOP Framework to give a respond to this kind of needs. it is a simple library very lightweight. You can see an example of logger in home page.
If you don't want to use a 3rd party assembly, you can browse the code source (open source) and copy both files Aspect.Directory.cs and Aspect.Directory.Entry.cs to adapted as your wishes. Theses classes allow to replace your methods at runtime. I would just ask you to respect the license.
I hope you will find what you need or to convince you to finally use an AOP Framework.
Take a look at this - Pretty heavy stuff..
http://msdn.microsoft.com/en-us/magazine/cc164165.aspx
Essential .net - don box had a chapter on what you need called Interception.
I scraped some of it here (Sorry about the font colors - I had a dark theme back then...)
http://madcoderspeak.blogspot.com/2005/09/essential-interception-using-contexts.html
I have found a different way which may be easier...
Declare a Method InvokeMethod
[WebMethod]
public object InvokeMethod(string methodName, Dictionary<string, object> methodArguments)
{
try
{
string lowerMethodName = '_' + methodName.ToLowerInvariant();
List<object> tempParams = new List<object>();
foreach (MethodInfo methodInfo in serviceMethods.Where(methodInfo => methodInfo.Name.ToLowerInvariant() == lowerMethodName))
{
ParameterInfo[] parameters = methodInfo.GetParameters();
if (parameters.Length != methodArguments.Count()) continue;
else foreach (ParameterInfo parameter in parameters)
{
object argument = null;
if (methodArguments.TryGetValue(parameter.Name, out argument))
{
if (parameter.ParameterType.IsValueType)
{
System.ComponentModel.TypeConverter tc = System.ComponentModel.TypeDescriptor.GetConverter(parameter.ParameterType);
argument = tc.ConvertFrom(argument);
}
tempParams.Insert(parameter.Position, argument);
}
else goto ContinueLoop;
}
foreach (object attribute in methodInfo.GetCustomAttributes(true))
{
if (attribute is YourAttributeClass)
{
RequiresPermissionAttribute attrib = attribute as YourAttributeClass;
YourAttributeClass.YourMethod();//Mine throws an ex
}
}
return methodInfo.Invoke(this, tempParams.ToArray());
ContinueLoop:
continue;
}
return null;
}
catch
{
throw;
}
}
I then define my methods like so
[WebMethod]
public void BroadcastMessage(string Message)
{
//MessageBus.GetInstance().SendAll("<span class='system'>Web Service Broadcast: <b>" + Message + "</b></span>");
//return;
InvokeMethod("BroadcastMessage", new Dictionary<string, object>() { {"Message", Message} });
}
[RequiresPermission("editUser")]
void _BroadcastMessage(string Message)
{
MessageBus.GetInstance().SendAll("<span class='system'>Web Service Broadcast: <b>" + Message + "</b></span>");
return;
}
Now I can have the check at run time without the dependency injection...
No gotchas in site :)
Hopefully you will agree that this is less weight then a AOP Framework or deriving from MarshalByRefObject or using remoting or proxy classes.
First you have to modify your class to implement an interface (rather than implementing the MarshalByRefObject).
interface ITraced {
void Method1();
void Method2()
}
class Traced: ITraced { .... }
Next you need a generic wrapper object based on RealProxy to decorate any interface to allow intercepting any call to the decorated object.
class MethodLogInterceptor: RealProxy
{
public MethodLogInterceptor(Type interfaceType, object decorated)
: base(interfaceType)
{
_decorated = decorated;
}
public override IMessage Invoke(IMessage msg)
{
var methodCall = msg as IMethodCallMessage;
var methodInfo = methodCall.MethodBase;
Console.WriteLine("Precall " + methodInfo.Name);
var result = methodInfo.Invoke(_decorated, methodCall.InArgs);
Console.WriteLine("Postcall " + methodInfo.Name);
return new ReturnMessage(result, null, 0,
methodCall.LogicalCallContext, methodCall);
}
}
Now we are ready to intercept calls to Method1 and Method2 of ITraced
public class Caller
{
public static void Call()
{
ITraced traced = (ITraced)new MethodLogInterceptor(typeof(ITraced), new Traced()).GetTransparentProxy();
traced.Method1();
traced.Method2();
}
}
You can use open source framework CInject on CodePlex. You can write minimal code to create an Injector and get it to intercept any code quickly with CInject. Plus, since this is Open Source you can extend this as well.
Or you can follow the steps mentioned on this article on Intercepting Method Calls using IL and create your own interceptor using Reflection.Emit classes in C#.
I don't know a solution but my approach would be as follows.
Decorate the class (or its methods) with a custom attribute. Somewhere else in the program, let an initialization function reflect all types, read the methods decorated with the attributes and inject some IL code into the method. It might actually be more practical to replace the method by a stub that calls LogStart, the actual method and then LogEnd. Additionally, I don't know if you can change methods using reflection so it might be more practical to replace the whole type.
You could potentially use the GOF Decorator Pattern, and 'decorate' all classes that need tracing.
It's probably only really practical with an IOC container (but as pointer out earlier you may want to consider method interception if you're going to go down the IOC path).
you need to bug Ayende for an answer on how he did it:
http://ayende.com/Blog/archive/2009/11/19/can-you-hack-this-out.aspx
AOP is a must for clean code implementing, however if you want to surround a block in C#, generic methods have relatively easier usage. (with intelli sense and strongly typed code) Certainly, it can NOT be an alternative for AOP.
Although PostSHarp have little buggy issues (i do not feel confident for using at production), it is a good stuff.
Generic wrapper class,
public class Wrapper
{
public static Exception TryCatch(Action actionToWrap, Action<Exception> exceptionHandler = null)
{
Exception retval = null;
try
{
actionToWrap();
}
catch (Exception exception)
{
retval = exception;
if (exceptionHandler != null)
{
exceptionHandler(retval);
}
}
return retval;
}
public static Exception LogOnError(Action actionToWrap, string errorMessage = "", Action<Exception> afterExceptionHandled = null)
{
return Wrapper.TryCatch(actionToWrap, (e) =>
{
if (afterExceptionHandled != null)
{
afterExceptionHandled(e);
}
});
}
}
usage could be like this (with intelli sense of course)
var exception = Wrapper.LogOnError(() =>
{
MessageBox.Show("test");
throw new Exception("test");
}, "Hata");
Maybe it's to late for this answer but here it goes.
What you are looking to achieve is built in MediatR library.
This is my RequestLoggerBehaviour which intercepts all calls to my business layer.
namespace SmartWay.Application.Behaviours
{
public class RequestLoggerBehaviour<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse>
{
private readonly ILogger _logger;
private readonly IAppSession _appSession;
private readonly ICreateLogGrain _createLogGrain;
public RequestLoggerBehaviour(ILogger<TRequest> logger, IAppSession appSession, IClusterClient clusterClient)
{
_logger = logger;
_appSession = appSession;
_createLogGrain = clusterClient.GetGrain<ICreateLogGrain>(Guid.NewGuid());
}
public async Task<TResponse> Handle(TRequest request, CancellationToken cancellationToken, RequestHandlerDelegate<TResponse> next)
{
var name = typeof(TRequest).Name;
_logger.LogInformation($"SmartWay request started: ClientId: {_appSession.ClientId} UserId: {_appSession.UserId} Operation: {name} Request: {request}");
var response = await next();
_logger.LogInformation($"SmartWay request ended: ClientId: {_appSession.ClientId} UserId: {_appSession.UserId} Operation: {name} Request: {request}");
return response;
}
}
}
You can also create performance behaviours to trace methods that take too long to execute for example.
Having clean architecture (MediatR) on your business layer will allow you to keep your code clean while you enforce SOLID principles.
You can see how it works here:
https://youtu.be/5OtUm1BLmG0?t=1
Write your own AOP library.
Use reflection to generate a logging proxy over your instances (not sure if you can do it without changing some part of your existing code).
Rewrite the assembly and inject your logging code (basically the same as 1).
Host the CLR and add logging at this level (i think this is the hardest solution to implement, not sure if you have the required hooks in the CLR though).
The best you can do before C# 6 with 'nameof' released is to use slow StackTrace and linq Expressions.
E.g. for such method
public void MyMethod(int age, string name)
{
log.DebugTrace(() => age, () => name);
//do your stuff
}
Such line may be produces in your log file
Method 'MyMethod' parameters age: 20 name: Mike
Here is the implementation:
//TODO: replace with 'nameof' in C# 6
public static void DebugTrace(this ILog log, params Expression<Func<object>>[] args)
{
#if DEBUG
var method = (new StackTrace()).GetFrame(1).GetMethod();
var parameters = new List<string>();
foreach(var arg in args)
{
MemberExpression memberExpression = null;
if (arg.Body is MemberExpression)
memberExpression = (MemberExpression)arg.Body;
if (arg.Body is UnaryExpression && ((UnaryExpression)arg.Body).Operand is MemberExpression)
memberExpression = (MemberExpression)((UnaryExpression)arg.Body).Operand;
parameters.Add(memberExpression == null ? "NA" : memberExpression.Member.Name + ": " + arg.Compile().DynamicInvoke().ToString());
}
log.Debug(string.Format("Method '{0}' parameters {1}", method.Name, string.Join(" ", parameters)));
#endif
}
I'm not sure if this is possible, but I'm essentially looking for a class constructor redirect.
An example of what I'm attempting:
public class Test
{
public Test() : TestFromOther();
//public Test() => TestFromOther();
public TestFromOther() { return 'this' with some stuff done here }
//another case might be => TestFromOther(defaultparam)
}
I'm trying to do this so that even if the base constructor is called, it redirects to my method.
(I don't want to just put a call to TestFromOther() inside the body of the constructor.. I'm specifically looking for the :TestFromOther() or => operator.. I've seen it before but for the life of me cannot remember how it's done)
EDIT: It's mostly for cleanliness and readability, thus having the Logger.GetCurrentClassLogger();
public class Logger {
private string _callerClass;
// obviously this doesn't function, but is the ideal end product
//public Logger() => GetCurrentClassLogger();
// Ideally I want the constructor to be this function and if a user, for
// whatever reason does call the empty constructor, it goes to this func
public Logger GetCurrentClassLogger() {
StackFrame[] sf = new StackTrace().GetFrames();
string callerName = "";
foreach (StackFrame f in sf) {
if (f == sf[0])
continue;
if (f.GetMethod().Name == ".ctor") {
callerName = f.GetMethod().ReflectedType.Name;
break;
}
callerName = f.GetMethod().Name;
break;
}
this._callerClass = callerName;
return this;
}
}
I trimmed this down about as far as I could for use as an example
You can "chain" constructors. it's not a redirection.
public class Test
{
public Test() : this("defaultParam") {}
public Test(string stringParam) { }
}
It will execute Test(string stringParam) first and then Test()
Edit per the comments and the edited question
static method is the way to achieve what you like:
public static Logger GetCurrentClassLogger() {...}
and the instantiation:
var logger = Logger.GetCurrentClassLogger(); // no new key word here
No, this is not possible. C# only allows you to call a base constructor or another constructor of the current class.
BTW the thing TestFromOther is also not a valid syntax, as it it is neither a method nor a constructor. Further, a constructor is not allowed to return anything.
The typical solution here would rather be to use a single constructor (possibly private such that it cannot be accessed from the outside) that does what you want. Or you may use helper methods for the initialization.
In c#, the main class created a Logger object that will be accessed by many threads. The logger object looks like (simplified)
public sealed class Logger
{
private ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public Logger()
{
// create other objects here AND a thread that extracts
// from the queue and writes to a file
// because queue is thread safe this is perfectly ok
}
public void Log(string whatToLog)
{
// Now, is this safe? This method will be called by several threads
// perhaps at the same time
string s = whatToLog + " " + DateTime.Now.ToString();
queue.Enqueue(s);
// The thread created in the constructor will extract and log
}
}
Is this OK from a design point of view? My two questions are:
Is "string s = whatToLog + " " + DateTime.Now.ToString();" ok if this method is accessed by several threads at the same time? I guess yes because any thread will have its own copy of s, right?
If the Logger object is accessed by several threads at the same time using only the Log() method, is everything safe then?
Thanks
The class is pretty thread safe.
Some suggested improvements.
The class doesn't prevent multiple instances from being instantiated, which is important if you want to have all threads log to the same object. Perhaps the singleton pattern could be applied. Quick example of a pseudo singleton using a static constructor. Please note the default constructor is private preventing any other class from creating a logger.
A performance related change is to avoid concatenating strings when logging. Creating new string is not a cheap operation. Also, once DateTime.Now is converted to a string, it is much harder to evaluate. E.g. sorting messages by creation date and time, etc. In the following, whatToLog is paired up with DateTime.Now in a Tuple.
public sealed class Logger
{
public static Logger instance {get; private set;}
static Logger()
{
instance = new Logger();
}
private ConcurrentQueue<Tuple<string, DateTime>> queue = new ConcurrentQueue<Tuple<string, DateTime>>();
private Logger() {}
public void Log(string whatToLog)
{
queue.Enqueue(new Tuple(whatToLog, DateTime.Now));
}
}
The ConcurrentQueue will make sure that the queue-part will be thread safe.
The string s you construct will not make it more or less thread-safe
In the current form, you should instantiate the logger, and pass the reference to each thread that will use this class
Although thread-safe, it does not guarantee sequentiality of the items
Queues cannot grow infinitely, make sure that your mechanism to dequeue can keep up
Improvements:
Make the class static, easier access for several threads
Separate concerns on reading and writing; this can be done by making several essential function internal and placing classes in the same namespace
use C#6 string interpolation
Code with improvements
public static class Logger
{
private static ConcurrentQueue<string> queue = new ConcurrentQueue<string>();
public static void Log(string LogMessage)
{
// thread safe logging
queue.Enqueue($"{LogMessage} {DateTime.Now}");
}
//dequeue only within namespace
internal static string Dequeue() {
string dequeuedItem;
queue.TryDequeue(out dequeuedItem);
return dequeuedItem;
}
}
public class LoggerReader
{
public LoggerReader()
{
// create other objects here AND a thread that extracts
// from the queue and writes to a file
// because queue is thread safe this is perfectly ok
string logItem = Logger.Dequeue();
}
}
I would simply use a lock in the Log method (replace ConcurrentQueue by Queue), and would not worry about each instruction anymore, especially if the original logger is more complicated than the example here!
public void Log(string whatToLog)
{
lock(queue) {
string s = whatToLog + " " + DateTime.Now.ToString();
queue.Enqueue(s);
}
}
I wrote a class library for logging and diagnostics. The interface is pretty basic. You call these static methods to log something:
interface ILogger {
void Critical (string message);
void Error (string message);
void Warning (string message);
void Info (string message);
void Verbose (string message);
}
However, I want to append a call context (let's say trace identifier) implicitly to the each message and I want that context to be set/reset by callers of the library (specifically top level caller) rather than pushing trace context down to each method call. Assuming that context can be updated at runtime, the updated information needs to retraverse all the layers. In fact, the trace context can be extended in the future too. So having context passed around each and every method/constructor initialization is definitely not a good design choice.
Given the fact that library is used in different layers of the code and called by various classes and these callers may fork other multiple threads, I want to be able to implement caller-specific singletons - global data that's only global to that caller.
Let's say the top level class can only set/reset the identifier via some Register (Guid traceId) method and down-the-path the callers just call log methods and do not care about the context. Be aware that the number of layers could be high. Think about the following and consider when the number of layers is tens and maybe hundreds making it really really hard to pass the context and make sure log method calls are aware of any update:
class A {
private B bObj;
void Do() {
bObj.DoSomethingElse();
Logger.Critical("some message from A");
}
}
class B {
private C cObj;
void DoSomethingElse() {
cObj.DoAnotherThing();
Logger.Critical("some message from B");
}
}
class C {
private D dObj;
void DoAnotherThing() {
dObj.DoSomethingElse();
Logger.Critical("some message from C");
}
}
I did a quick research find out ThreadStatic, CallContext and HttpContext in ASP.Net, but I couldn't wrap my head around this without having System.Web in multithread environment. ThreadStatic could be the solution, but my main source of confusion is that a caller may fork new threads and what happens to that existing context from that point on in child threads.
In summary, I am looking for a solution that does not require traversing tramp data to callers of the library (method calls or constructors doesn't matter), and I want to keep log method calls to be aware of any updates to the context data.
NOTE: I am not really sure if caller-specific singletons is right way to put this.
UPDATE: Jon Skeet has an article on this issue.
In such cases, I always prefer to think in terms of decoration. Specifically, you have your interface
interface ILogger {
void Critical (string message);
}
then you have a concrete logger
public class ConcreteLogger : ILogger {
public void Cricital( string message ) {
// log somewhere
}
}
and then you have your decorators that can be composed
public class ContextAwareLogger : ILogger {
private string context;
private ILogger decorated;
public ContextAwareLogger( string context, ILogger decorated ) {
this.context = context;
this.decorated = decorated;
}
public void Critical( string message ) {
this.decorated.Critical( this.context + this.message );
}
}
and last but not least, you have a factory:
public class LoggerFactory {
public ILogger Create( string context ) {
if ( !string.IsNullOrEmpty( context ) )
return new ContextAwareLogger( context, new ConcreteLogger() );
else
return new ConcreteLogger();
}
}
This gives your client a detailed control over what happens, without really changing their interface:
// client code
// no context
var logger = new LoggerFactory().Create( null );
logger.Critical( "a critical issue" );
// with context
var logger2 = new LoggerFactory().Create( "context" );
logger2.Critical( "a critical issue" );
Hope you get the idea. Having a bunch of different decorators and a smart factory with several different ways to parametrize your logger creation, you can still rely on the very same logger interface and you let the additional work be done by specific decorators.
Instead of passing pure data results for example List<Customer> between layers you can create a MessageEnvelope<List<Customer>> class. In this MessageEnvelope class you can then have a property of IContext and also a GUID identifier and additional data that you need for your application.
So you have to refactor your code then of course.
This would also work in N-Tier scenarios.
I would not use singetons!
After some research, I found out Stephen Cleary's article Implicit Async Context ("AsyncLocal"). He provides example of how to maintain an implicit context that can flow into the threads.
In my case, the following solves the tramp data traversal:
interface ILogger {
void Critical (string message);
void Error (string message);
void Warning (string message);
void Info (string message);
void Verbose (string message);
void SetContext(string context);
string GetContext();
}
class Logger : ILogger {
void Critical(string message) {
Debug.WriteLine(string.Format("{0}: {1}", GetContext(), message));
}
void SetContext(string context) {
CallContext.LogicalSetData("myContext", context);
}
string GetContext() {
return (string)CallContext.LogicalGetData("myContext") ?? string.Empty;
}
}
Each log method call retrieves the implicit context using CallContext.
I have an object that takes a long time to be initialized. Therefore I the capability to Start Initializing on application startup. Any subsequent calls to methods on the class we need to have a delay mechanism that waits for the class to finish initialization.
I have a couple of potential solutions however I am not entirely satisfied with either of them. The first uses Task.Delay in a while loop and the second uses SemaphoreSlim but involves some unnecessary blocking. I feel this must be a fairly common requirement, can anybody provide some advice on how to best manage this?
Oh btw, this is a Metro application so we have limited API's
Here is the pseudocode:
public class ExposeSomeInterestingItems
{
private InitialisationState _initialised;
private readonly SemaphoreSlim _waiter =
new SemaphoreSlim(0);
public async Task StartInitialize()
{
if (_initialised == InitialisationState.Initialised)
{
throw new InvalidOperationException(
"Attempted to initialise ActiveTrackDown" +
"loads when it is already initialized");
}
_initialised =
InitialisationState.StartedInitialisation;
new TaskFactory().StartNew(async () =>
{
// This takes some time to load
this._interestingItems =
InterestingItemsLoader.LoadItems();
_waiter.Release();
_initialised = InitialisationState.Initialised;
});
}
public InterestingItem GetItem(string id)
{
DelayUntilLoaded();
DelayUntilLoadedAlternative();
}
private async Task DelayUntilLoaded()
{
if (_initialised == InitialisationState.NotInitialised)
{
throw new InvalidOperationException("Error " +
"occurred attempting to access details on " +
"ActiveTrackDownloads before calling initialise");
}
while (true)
{
if (_initialised == InitialisationState.Initialised)
{
return;
}
await Task.Delay(300);
}
}
private async Task DelayUntilLoadedAlternative()
{
if (_initialised == InitialisationState.NotInitialised)
{
throw new InvalidOperationException(
"Error occurred attempting to access details " +
"on ActiveTrackDownloads before calling initialise");
}
try
{
await _waiter.WaitAsync();
}
finally
{
_waiter.Release();
}
}
}
I think that a better design would be an asynchronous factory, where the calling code awaits the object creation and then receives a regular object instance.
Stealing liberally from Stephen Toub:
public class AsyncLazy<T> : Lazy<Task<T>>
{
public AsyncLazy(Func<T> valueFactory) :
base(() => Task.Run(valueFactory)) { }
public AsyncLazy(Func<Task<T>> taskFactory) :
base(() => Task.Run(taskFactory)) { }
public TaskAwaiter<T> GetAwaiter() { return Value.GetAwaiter(); }
}
public static class ExposeSomeInterestingItemsFactory
{
public static AsyncLazy<ExposeSomeInterestingItems> Instance
{
get { return _instance; }
}
private static readonly AsyncLazy<ExposeSomeInterestingItems> _instance =
new AsyncLazy<ExposeSomeInterestingItems>(() => new ExposeSomeInterestingItems());
public static void StartInitialization()
{
var unused = Instance.Value;
}
}
public class ExposeSomeInterestingItems
{
public ExposeSomeInterestingItems()
{
// This takes some time to load
this._interestingItems = InterestingItemsLoader.LoadItems();
}
public InterestingItem GetItem(string id)
{
// Regular logic. No "delays".
}
}
...
var exposeSomeInterestingItems = await ExposeSomeInterestingItemsFactory.Instance;
var item = exposeSomeInterestingItems.GetItem("id");
That way, you keep the Single Responsibility Principle nicely:
AsyncLazy<T> combines Task<T> with Lazy<T> (so the instance is created asynchronously only when needed).
ExposeSomeInterestingItemsFactory contains construction logic.
ExposeSomeInterestingItems is only concerned with exposing interesting items, rather than having to pollute all its members with asynchronous delays.
Also, this solution is asynchronous throughout (no blocking), which is good (particularly for Metro apps).
Update, 2012-09-14: I've taken this code and cleaned it up and commented it on my blog.
You can use the Task<T> for this. This will take care of all the synchronisation for you and allows you to block untill the value is available:
private static Task<HeavyObject> heavyObjectInitializer;
// Call this method during application initialization
public static void Bootstrap()
{
heavyObjectInitializer = new Task<HeavyObject>(() =>
{
// creation of heavy object here
return new HeavyObject();
});
// Start running the initialization right now on a
// background thread. We don't have to wait on this.
heavyObjectInitializer.Start();
}
// Call this method whenever you need to use the object.
public static HeavyObject GetHeavyObject()
{
// Get the initialized object, or block untill this
// instance gets available.
return heavyObjectInitializer.Result;
}
Optionally, you can also query to see if the object is available or not:
public static bool IsHeavyObjectAvailable
{
get { return heavyObjectInitializer.IsCompleted; }
}
Put the method calls into a queue which you process when you finish initialising. Only put methods into the queue when you have not yet initialised.
You could move to a an event driven architecture where you application is in different states.
Initially the application moves into the Starting state. In this state HeavyObject is created using a background task. When the initialization is complete an event is fired. (You don't have to use an actual .NET event. You can use callbacks or something similar and frameworks like Reactive Extensions allows you to compose sequences of events.)
When all initialization events have fired you move into the Started state of your application. For an UI application this could modify the UI to enable some previously disabled operations.
Check this Prototype Pattern. Maybe it can help you
You only need to create your object once and clone it when you need another one.