如何将AutoFac与SignalR 2.0.0一起使用,其中集线器位于外部DLL中?

时间:2014-01-09 16:20:38

标签: signalr autofac signalr-hub

我们需要能够将新项目/ dll放入我们的主项目中,并让主项目接收它们并能够使用它们。决定使用AutoFac来满足这种需求。这样主要项目就不需要直接引用我们想要使用的任何其他项目/ dll。这是global.asax:

var builder = new ContainerBuilder();

var directoryName = HttpContext.Current.Server.MapPath("~/bin/");
var cfg = new ModularityLoader(new ModularityConfig(Path.Combine(directoryName, @"Modules")), new Log4NetLogger(typeof(ModularityConfig)));
cfg.RegisterModulesFromCatalog(builder);

builder.RegisterType<AssembliesResolver>().AsImplementedInterfaces();
builder.RegisterType<AppsSecurityFeatureResolver>().AsImplementedInterfaces();
builder.RegisterType<FeaturesAutofacAuthoriztationFilter>()
    .AsWebApiAuthorizationFilterFor<ApiController>().InstancePerApiRequest();

builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);

builder.RegisterControllers(typeof(MvcApplication).Assembly);

Container = builder.Build();

我们在将其dll复制到主项目的bin目录中的所有项目上都有后期构建事件。所有的dll都加载到 var cfg = new ModularityLoader

见图片: dll list screenshot

builder.Build()在我们项目中实现Autofac.Module的任何dll中调用以下类,如下所示:

public class AutofacModuleConfig : Autofac.Module
{
    protected override void Load(ContainerBuilder builder)
    {
        base.Load(builder);
        builder.RegisterApiControllers(typeof(AutofacModuleConfig).Assembly);
    }
}

这是SignalR的问题所在。我想将RouteTable.Routes.MapHubs()放入AutofacModuleConfig,但SignalR 2.0.0+不再支持此功能。相反,它希望您创建一个这样的Startup类:

[assembly: OwinStartup("SignalRConfig", typeof(KL.Apps.TestHarness.SignalR.Startup))]

namespace KL.Apps.TestHarness.SignalR
{
    public static class Startup
    {
        public static void Configuration(IAppBuilder app)
        {
            app.MapSignalR("/signalr", new HubConfiguration());
        }
    }
}

注意:为了实现这一点,我将以下内容添加到web.config中:

<add key="owin:appStartup" value="SignalRConfig" />

SignalR还需要这样的Hub类:

[HubName("BatchHub")]
public class BatchHub : Hub
{
    public void RemoveBatchRow(Guid batchId)
    {
        Clients.All.RemoveBatchRow(batchId);
    }
}

在我的主项目中使用Startup类和Hub类可以很好地工作。但是,由于AutoFac的独特性,我的外部dll中的所有Hub都没有被加载。我正在考虑尝试找到一种方法来强制AutofacModuleConfig.Load接受RouteTable.Routes.MapHubs(),但添加此行会破坏代码。

我想回到SignalR的早期版本,所以我可以使用RouteTable.Routes.MapHubs(),但我真的想使用最新版本。

有什么想法吗?

提前致谢。


编辑1:

我发现了这个:https://code.google.com/p/autofac/wiki/SignalRIntegration 这似乎是问题的答案。但是,即使在安装Autofac.SignalR NuGet包之后,RegisterHubs也不存在于构建器对象之外......

var builder = new ContainerBuilder();
builder.RegisterHubs(Assembly.GetExecutingAssembly());

编辑2:

所以这就是我的AutofacModuleConfig现在的样子,但我的集线器仍然没有出现在javascript中。

namespace OurName.IOC
{
    public class AutofacModuleConfig : Autofac.Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            base.Load(builder);
            AutofacSignalRConfig.Load(builder);
            builder.RegisterApiControllers(typeof(AutofacModuleConfig).Assembly);
        }
    }
}

namespace Autofac.Integration.SignalR
{
    public static class AutofacSignalRConfig
    {
        public static void Load(ContainerBuilder builder)
        {
            builder.RegisterHubs(Assembly.GetExecutingAssembly());
        }
    }
}

仍然没有工作。在javascript中,我无法看到我的中心。

$(document).ready(function(){
    var myHub = $.connection.BatchHub;
});

myHub为空。


编辑3:

昨晚试了一下。我删除了AutofacSignalRConfig,这就是主要的Global.asax现在的样子:

var builder = new ContainerBuilder();

var directoryName = HttpContext.Current.Server.MapPath("~/bin/");
var cfg = new ModularityLoader(new ModularityConfig(Path.Combine(directoryName, @"Modules")), new Log4NetLogger(typeof(ModularityConfig)));
cfg.RegisterModulesFromCatalog(builder);

builder.RegisterType<AssembliesResolver>().AsImplementedInterfaces();
builder.RegisterType<AppsSecurityFeatureResolver>().AsImplementedInterfaces();
builder.RegisterType<FeaturesAutofacAuthoriztationFilter>()
    .AsWebApiAuthorizationFilterFor<ApiController>().InstancePerApiRequest();

builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

builder.RegisterWebApiFilterProvider(GlobalConfiguration.Configuration);

builder.RegisterControllers(typeof(MvcApplication).Assembly);

foreach (var assembly in cfg.LoadedAssemblies)
{
    var hubs = builder.RegisterHubs(assembly);
}

Container = builder.Build();

GlobalHost.DependencyResolver = new Autofac.Integration.SignalR.AutofacDependencyResolver(Container);

注意我是如何尝试获取cfg的输出(它是bin文件夹中找到的所有程序集的集合),然后通过它们进行操作以便在每个文件夹上执行builder.RegisterHubs。尽管如此,仍然没有从任何一个组件中拿起我的集线器。

我的每个导入的dll中是否还需要一个Startup类?如果是这样,我该如何调用呢?


编辑4:

尝试过这一点也没有成功:

foreach (var assembly in cfg.LoadedAssemblies)
{
    //var hubs = builder.RegisterHubs(assembly);
    var a = assembly.GetExportedTypes().Where(x => x.BaseType == typeof (Hub));

    foreach (var x in a)
    {
        builder.RegisterType(x);
    }
}

有关调试信息,请参阅图像: Another attempt at loading hubs


编辑5:

Jim Bolla感谢您的投入。这是我第一次尝试你的建议。

public class AssemblyLocator : IAssemblyLocator
{
    public IList<Assembly> GetAssemblies()
    {
        var directoryName = HttpContext.Current.Server.MapPath("~/bin/");
        var cfg = new ModularityLoader(new ModularityConfig(Path.Combine(directoryName, @"Modules")), new Log4NetLogger(typeof(ModularityConfig)));
        return cfg.LoadedAssemblies;
    }
}

还在Container = builder.Build上面添加了这个:

builder.RegisterType<AssemblyLocator>().As<IAssemblyLocator>().SingleInstance();

现在调用AssemblyLocator.GetAssemblies()。

......测试......


编辑6:

好。所以现在当我在javascript中抛出一个断点时,我可以看到$ .connection.BatchHub这很棒!但是,当尝试在服务器端调用hub方法RemoveBatchRow时,我收到以下错误:

“不支持使用HubPipeline未创建的Hub实例。”

这是堆栈跟踪:

  

在   Microsoft.AspNet.SignalR.Hubs.NullClientProxy.TryInvokeMember(InvokeMemberBinder   binder,Object [] args,Object&amp;结果)在CallSite.Target(Closure,   CallSite,Object,Guid)at   System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid2 [T0,T1](调用点   site,T0 arg0,T1 arg1)at   KL.Apps.WebIndex.Hubs.BatchHub.RemoveBatchRow(Guid batchId)in   d:\ Source \ Apps Framework   Modules \ WebIndex \ Main \ Source \ KL.Apps.WebIndex \ Hubs \ BatchHub.cs:第20行   在   KL.Apps.WebIndex.API.Batch.BatchLockController.TryLockBatchAsync(字符串   batchId)在d:\ Source \ Apps Framework中   模块\ WebIndex \ MAIN \来源\ KL.Apps.WebIndex \ API \批次\ BatchLockController.cs:行   30在lambda_method(Closure,Object,Object [])at   System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor&LT;&GT; c__DisplayClass13.b__c(对象   instance,Object [] methodParameters)at   System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(对象   instance,Object [] arguments)at   System.Web.Http.Controllers.ReflectedHttpActionDescriptor&LT;&GT; c__DisplayClass5.b__4()   在System.Threading.Tasks.TaskHelpers.RunSynchronously [TResult](Func`1   func,CancellationToken cancellationToken)

我从我的一个远程dll调用hub方法:

new BatchHub().RemoveBatchRow(gId);

您可以在上面看到BatchHub的定义。

还有其他想法吗?

0 个答案:

没有答案