Ok, first I’ll describe my goal, then what I’ve coded, finally questions.
Goal
To have a generic class that manage multiple contracts that , and is able to find out wheter it’s an online or offline situation, on the very moment when an operation is being made. There’s a really easy way of doing it: a class for each Online-Offline pair that implement the contract and check on every each method wheter if it’s online or not, and makes the right call. And that’s exactly what I want to avoid.
Just FYI, behind the scenes it would be an Online scenario connected to WCF services and an Offline scenario connected to a client local database.
FYI 2: I’ve tried to accomplish this avoiding Interception and AOP stuff, but I found a dead end. You can see this post where I implement what seems to be a good solution, but stablishes if it’s connected or not on the contructor, but real-world scenario needs this check at Operation level, not constructor level.
Code
It’s ready to run & test: just copy/paste on a new console application.
using System;
using System.Reflection;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.InterceptionExtension;
namespace ConsoleApplication1
{
public class Unity
{
public static IUnityContainer Container;
public static void Initialize()
{
Container = new UnityContainer();
Container.AddNewExtension<Interception>();
Container.RegisterType<ILogger, OnlineLogger>();
Container.Configure<Interception>().SetInterceptorFor<ILogger>(new InterfaceInterceptor());
}
}
class Program
{
static void Main(string[] args)
{
Unity.Initialize();
var r = new Router<ILogger, OnlineLogger, OfflineLogger>();
try
{
r.Logger.Write("Method executed.");
}
catch (CantLogException ex)
{
r.ManageCantLogException(ex);
}
Console.ReadKey();
}
}
public class Router<TContract, TOnline, TOffline>
where TOnline : TContract, new()
where TOffline : TContract, new()
{
public TContract Logger;
public Router()
{
Logger = Unity.Container.Resolve<TContract>();
}
public void ManageCantLogException(CantLogException ex)
{
// Is this an ugly trick? I mean, the type was already registered with online.
Unity.Container.RegisterType<TContract, TOffline>();
Logger = Unity.Container.Resolve<TContract>();
var method = ((MethodBase)ex.MethodBase);
method.Invoke(Logger, ex.ParameterCollection);
}
}
public interface ILogger
{
[Test]
void Write(string message);
}
public class OnlineLogger : ILogger
{
public static bool IsOnline()
{
// A routine that check connectivity
return false;
// Should I perform a "lock" here to make this tread safe?
}
public void Write(string message)
{
Console.WriteLine("Logger: " + message);
}
}
public class OfflineLogger : ILogger
{
public void Write(string message)
{
Console.WriteLine("Logger: " + message);
}
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
public class TestAttribute : HandlerAttribute
{
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new TestHandler();
}
}
public class TestHandler : ICallHandler
{
public int Order { get; set; }
public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
{
Console.WriteLine("It's been intercepted.");
if (!OnlineLogger.IsOnline() && input.Target is OnlineLogger)
{
Console.WriteLine("It's been canceled.");
throw new CantLogException(input.MethodBase, input.Inputs);
}
return getNext()(input, getNext);
}
}
public class CantLogException : Exception
{
public MethodBase MethodBase { get; set; }
public object[] ParameterCollection { get; set; }
public CantLogException(string message)
: base(message)
{
}
public CantLogException(MethodBase methodBase, IParameterCollection parameterCollection)
{
this.MethodBase = methodBase;
var parameters = new object[parameterCollection.Count];
int i = 0;
foreach (var parameter in parameterCollection)
{
parameters[i] = parameter;
i++;
}
this.ParameterCollection = parameters;
}
}
}
Questions
-
Is this design that I present thread-safe?
-
Is it a performance disgrace? The exception handling the Online-Offline situation and reflection there makes me fell I’m doing all wrong.
-
I think this is a common requeriment, isn’t there any api/fwk/whatever that does this Online-Offline management? Kind of feel like I’m reinventing the weel here.
-
This is a long shot question: I really don’t want client (Program class on this example) to know about the exception, isn’t there any other way to cancel method execution but through an exception on the interceptor? Any other approach is welcomed too.
I’m not interested on paid third-party stuff, so sadly things like PostSharp aren’t options for me.
I would like to suggest another possible approach. It’s rather different than what you’re planning, but might work out better.
The basic idea is to split your app into two parts. The first part is what you’re describing – the UI. However, it’s written assuming you’re offline. It stores everything into a local database/file/memory store.
You then have another part of the program, probably on another thread (or possibly in another process) which is responsible for the synchronization. It looks at the data store, waiting for changes, and if online it writes them to the server. When updates come down from the server the data store will need to raise events to tell the main program something has changed, but it would have had to do that anyway. If you’re offline, the synchronizer doesn’t do anything, but all the data changes are being safely squirreled away automatically until you are back online later.
The nice thing about this approach is you never need to worry about the online/offline switch anywhere except the part of the code specifically dealing with synchronization. By just assuming you’re offline you’ve already set up the default case. You can get rid of all the interception / AOP stuff completely.