Skip to content

Instantly share code, notes, and snippets.

@Fristi
Created October 25, 2012 19:16
Show Gist options
  • Save Fristi/3954797 to your computer and use it in GitHub Desktop.
Save Fristi/3954797 to your computer and use it in GitHub Desktop.
Hub activation with metadata and decoupling of the hub deactivation
public class AutofacScopedHubActivator : IHubActivator
{
private readonly ILifetimeScope rootScope;
public AutofacScopedHubActivator(ILifetimeScope rootScope)
{
this.rootScope = rootScope;
}
public HubActivationResult Create(HubDescriptor descriptor)
{
//create a new scope
var scope = rootScope.BeginLifetimeScope();
//resolve the hub using the scope
var hub = scope.Resolve(descriptor.Type) as IHub;
//create a new result
var hubActivationResult = new HubActivationResult(hub);
//put the scope in the result
hubActivationResult.Items.Add("scope", scope);
//return it
return hubActivationResult;
}
}
public class AutofacScopedHubDeactivator : IHubDeactivator
{
public void Destruct(HubActivationResult hubActivationResult)
{
//check if the items contains a item called scope and if its actually a scope
if(hubActivationResult.Items.ContainsKey("scope") && hubActivationResult.Items["scope"] is ILifetimeScope)
{
//cast it
var scope = hubActivationResult.Items["scope"] as ILifetimeScope;
//dispose it
scope.Dispose();
}
}
}
public class PersistenceModule : Module
{
private static ISessionFactory GetSessionFactory()
{
return Fluently.Configure()
.Database(MySQLConfiguration.Standard.ConnectionString("Server=localhost; Port=3306; Database=AuctionExample; Uid=root; Pwd=;"))
.Mappings(m => m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly()))
.ExposeConfiguration(ConfigureExposeConfiguration)
.BuildSessionFactory();
}
private static void ConfigureExposeConfiguration(Configuration configuration)
{
var schemaExport = new SchemaExport(configuration);
schemaExport.Create(true, true);
}
protected override void Load(ContainerBuilder builder)
{
builder.Register(ctx => GetSessionFactory()).SingleInstance();
builder
.Register(ctx => ctx.Resolve<ISessionFactory>().OpenSession())
.InstancePerLifetimeScope();
builder.Register(ctx => new AuctionRepository(ctx.Resolve<ISession>()));
}
}
public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
var container = BuildContainer();
ConfigureSignalR(container);
}
private static void ConfigureSignalR(IContainer container)
{
GlobalHost.DependencyResolver = new AutofacDependencyResolver(container);
RouteTable.Routes.MapHubs();
GlobalHost.HubPipeline.AddModule(new NhibernateTransactionalModule());
}
private static IContainer BuildContainer()
{
var builder = new ContainerBuilder();
builder.RegisterModule(new PersistenceModule());
builder.Register(ctx => new PersonHub(ctx.Resolve<PersonRepository>()));
builder.Register(ctx => new AutofacScopedHubActivator(ctx.Resolve<ILifetimeScope>())).As<IHubActivator>();
builder.Register(ctx => new AutofacScopedHubDeactivator()).As<IHubDeactivator>();
return builder.Build();
}
}
public sealed class HubActivationResult
{
public IHub Hub { get; private set; }
public IDictionary<string, object> Items { get; private set; }
public HubActivationResult(IHub hub)
{
Hub = hub;
Items = new Dictionary<string, object>();
}
}
public interface IHubActivator
{
HubActivationResult Create(HubDescriptor descriptor);
}
public interface IHubDeactivator
{
void Destruct(HubActivationResult hubActivationResult);
}
/// <summary>
///
/// </summary>
public interface IHubIncomingInvokerContext
{
/// <summary>
///
/// </summary>
IDictionary<string, object> ActivationItems { get; }
/// <summary>
///
/// </summary>
IHub Hub { get; }
/// <summary>
///
/// </summary>
MethodDescriptor MethodDescriptor { get; }
/// <summary>
///
/// </summary>
object[] Args { get; }
/// <summary>
///
/// </summary>
TrackingDictionary State { get; }
}
public class NhibernateTransactionalModule : HubPipelineModule
{
public override Func<IHubIncomingInvokerContext, Task<object>> BuildIncoming(Func<IHubIncomingInvokerContext, Task<object>> invoke)
{
return base.BuildIncoming(context => {
//check if we got a transaciton attribute
if(HasTransactionAttribute(context))
{
//get the created scope from the activation items
var scope = context.ActivationItems["scope"] as ILifetimeScope;
//get the session
var session = scope.Resolve<ISession>();
//wrapped using statement since it's async
return TaskExtensions.Using(session.BeginTransaction, trans => {
//invoke the method
var task = invoke(context);
//extension method which will do an action in between and pass the result on
return task.CarryOn(result => {
try
{
//after task completes commit
trans.Commit();
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
//if it fails, rollback
trans.Rollback();
}
});
});
}
return invoke(context);
});
}
private static bool HasTransactionAttribute(IHubIncomingInvokerContext context)
{
return context.MethodDescriptor.Attributes.Any(x => x.GetType().IsInstanceOfType(typeof(TransactionalAttribute))) ||
context.MethodDescriptor.Hub.Type.GetCustomAttributes(typeof(TransactionalAttribute), true).Any();
}
}
class PersonHub
{
private PersonRepository repos;
public PersonHub(PersonRepository repos)
{
this.repos = repos;
}
[Transactional]
public void Add(Person person)
{
repos.Add(person);
}
}
class PersonRepository
{
private ISession session;
public PersonRepository(ISession session)
{
this.session = session;
}
public void Add(Person persson)
{
this.session.Save(person);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment