Skip to content

Instantly share code, notes, and snippets.

@hanishi
Created July 10, 2013 15:14
Show Gist options
  • Save hanishi/5967154 to your computer and use it in GitHub Desktop.
Save hanishi/5967154 to your computer and use it in GitHub Desktop.
SignalR HubConfigurator
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition.Hosting;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.SignalR.Client.Hubs;
using System.ComponentModel.Composition;
namespace SignalR
{
public class HubConfigurator : MarshalByRefObject, IDisposable
{
private Sponsor<TextWriter> _log;
public TextWriter Log
{
get { return (_log != null) ? _log.Instance : null; }
set { _log = (value != null) ? new Sponsor<TextWriter>(value) : null; }
}
[ImportMany(typeof (IHubClient))]
private IEnumerable<IHubClient> _clients;
private IEnumerable<Synchronizer> Synchronizer { get; set; }
internal HubConnectionSingleton HubConnection { get; set; }
public HubConfigurator()
{
Log = TextWriter.Null;
HubConnection = HubConnectionSingleton.GetInstance();
}
~HubConfigurator()
{
Dispose(false);
}
private IEnumerable<Tuple<string, Synchronizer>> Configurations(IHubClient client)
{
return from methodInfo in client.GetType().GetMethods()
let paramInfo = methodInfo.GetParameters()
where paramInfo.Length == 1 && paramInfo[0].ParameterType == typeof (IHubProxy) && methodInfo.ReturnType == typeof(void)
select Tuple.Create(methodInfo.Name, new Synchronizer(HubConnection.CreateHubProxy(methodInfo.Name)));
}
private IEnumerable<Synchronizer> Start()
{
var sync = new List<Synchronizer>();
foreach (var client in _clients)
{
foreach (var configuration in Configurations(client))
{
var conf = configuration;
var c = client;
var method = c.GetType().GetMethod(conf.Item1);
var task = Task.Factory.StartNew(() =>
{
method.Invoke(c, new object[] {conf.Item2});
});
task.ContinueWith(_ =>
{
if (_.Exception != null)
{
Console.WriteLine(_.Exception.InnerException.GetType().Name);
}
}, TaskContinuationOptions.OnlyOnFaulted);
sync.Add(conf.Item2);
}
}
return sync.ToArray();
}
private async void SetUp()
{
Synchronizer = Start();
await HubConnection.Start();
foreach (var sync in Synchronizer)
{
sync.Resume();
}
}
internal void SetUp(string directory)
{
foreach (var dllFile in Directory.GetFiles(directory, "*.dll"))
{
try
{
var asm = Assembly.LoadFile(dllFile);
Console.WriteLine(dllFile);
Log.WriteLine("Loaded assembly {0} in {1}", asm.GetName().FullName, directory);
}
catch (ReflectionTypeLoadException rex)
{
Console.WriteLine("{0} failed to load.", Path.GetFileName(dllFile));
foreach (var ex in rex.LoaderExceptions)
{
Log.WriteLine("\t{0}: {1}", ex.GetType().Name, ex.Message);
}
}
catch (BadImageFormatException e)
{
Console.WriteLine("{0} is not a valid assembly.", Path.GetFileName(dllFile));
}
catch (Exception ex)
{
Console.WriteLine("{0} failed to load.", Path.GetFileName(dllFile));
Console.WriteLine("\t{0}: {1}", ex.GetType().Name, ex.Message);
}
}
var catalog = new DirectoryCatalog(directory);
var container = new CompositionContainer(catalog);
container.SatisfyImportsOnce(this);
SetUp();
}
private void TearDown()
{
foreach (var sync in Synchronizer)
{
Console.WriteLine("Stopped!");
sync.Pause();
sync.Stop();
}
HubConnection.Stop();
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool disposing)
{
if (!disposing) return;
TearDown();
foreach (var hubClient in _clients)
{
try
{
hubClient.Dispose();
}
catch (Exception ex)
{
Log.WriteLine("{0} thrown while disposing {1}", ex.GetType(), hubClient);
Log.WriteLine("\t{0}: {1}", ex.GetType().Name, ex.Message);
}
}
if (_log != null) _log.Dispose();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment