Asp.net web api 无法完成该操作,因为DbContext已使用EF5信号器和Windsor Castle作为IoC处理

Asp.net web api 无法完成该操作,因为DbContext已使用EF5信号器和Windsor Castle作为IoC处理,asp.net-web-api,entity-framework-5,castle-windsor,signalr,signalr-hub,Asp.net Web Api,Entity Framework 5,Castle Windsor,Signalr,Signalr Hub,我正在使用以下技术进行一个项目: 实体框架版本:5 实体框架迁移 信号机版本1.1.2 国际奥委会:温莎城堡 dotnetframework4.5 WebAPI Visual Studio 2012 SQL Server Express 2012 我发现了错误 The operation cannot be completed because the DbContext has been disposed 在ServerHub类中,我放置了以下内容: // TODO: This is th

我正在使用以下技术进行一个项目:

  • 实体框架版本:5
  • 实体框架迁移
  • 信号机版本1.1.2
  • 国际奥委会:温莎城堡
  • dotnetframework4.5
  • WebAPI
  • Visual Studio 2012
  • SQL Server Express 2012
我发现了错误

The operation cannot be completed because the DbContext has been disposed
在ServerHub类中,我放置了以下内容:

// TODO: This is throwing the error: The operation cannot be completed because the DbContext has been disposed
有人知道我为什么会这样吗?我已经读了很多答案,但到目前为止,我还没有尝试解决它

EF通用存储库(EF5)

UoW(工作单位)

更新 我添加了Drew建议的这个…仍然没有运气

    using System;
    using System.Linq;
    using System.Timers;
    using Data.Contracts;
    using Data.Model;
    using Microsoft.AspNet.SignalR;

    public class ServerHub : Hub
    {
        private static System.Timers.Timer aTimer;

        DateTime lastDate = DateTime.UtcNow;

        public IHubHandler hubHandler { get; set; }

        public ServerHub()
        {
            // Create a timer with a ten second interval.
            aTimer = new System.Timers.Timer(10000);

            // Hook up the Elapsed event for the timer.
            aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

            aTimer.Enabled = true;

            // If the timer is declared in a long-running method, use
            // KeepAlive to prevent garbage collection from occurring
            // before the method ends.
            GC.KeepAlive(aTimer);
        }

        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            HubHandler.SendNewMessage(e.SignalTime);
        }


        // Called from the client
        public void GetAllMessages()
        {
            var MessagesList = Uow.Messages.GetAll().Select(
                newMessage => new MessageDto
                {
                    Country = newMessage.Country,
                    CountryId = newMessage.CountryId ?? 0,
                    MessageId = newMessage.MessageId
                });
            Clients.All.handleGetAll(MessagesList);
        }

        private void OnTimedEvent(object source, ElapsedEventArgs e)
        {
            hubHandler.SendNewMessage(e.SignalTime);
        }
    }
新班级呢

轮毂处理器

    using System;
    using System.Linq;
    using Data.Contracts;
    using Data.Model;
    using Microsoft.AspNet.SignalR;

    public class HubHandler : IHubHandler
    {
        public IGdpUow Uow { get; set; }
        DateTime lastDate = DateTime.UtcNow;

        public void SendNewMessage(DateTime signalTime)
        {
            // Get a hub context for ServerHub
            var serverHub = GlobalHost.ConnectionManager.GetHubContext<ServerHub>();

            // TODO: This is throwing the error: The operation cannot be completed because the DbContext has been disposed
            var gdpConfigurationRecord = Uow.GdpConfigurations.GetByPredicate(a => a.Description.Equals("LastDateTimeMessagesCheck")).SingleOrDefault();
            if (gdpConfigurationRecord == null)
            {
                throw new ApplicationException("Please set the LastDateTimeMessagesCheck value in GdpConfigurations");
            }

            var lastMessagesDateTimeCheck = gdpConfigurationRecord.DateTimeValue;

            // Send a message to all the clients
            serverHub.Clients.All.handleNewMessages("message");
            gdpConfigurationRecord.DateTimeValue = signalTime.ToUniversalTime();
            Uow.GdpConfigurations.Update(gdpConfigurationRecord);
        }
    }
}
namespace GdpSoftware.App.Ui.Web.Hubs
{
    using System;
    using System.Linq;
    using Data.Contracts;
    using Data.Model;
    using Microsoft.AspNet.SignalR;

    public class ServerHub : Hub
    {
        public IGdpUow Uow { get; set; }

        public IHubHandler hubHandler { get; set; }

        public void GetAllMessages()
        {
            var messagesList = Uow.Messages.GetAll().Select(
                newMessage => new MessageDto
                {
                    MessageId = newMessage.MessageId,
                    Messagestatus = newMessage.MessageStatus.Description
                });
            hubHandler.SetClients(Clients);
            hubHandler.StartTimer();
            Clients.All.handleMessages(messagesList);
        }
    }
}
HUB安装程序

using Microsoft.AspNet.SignalR;

public class HubsInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component
            .For<RepositoryFactories>()
            .ImplementedBy<RepositoryFactories>()
            .LifestyleSingleton());

        container.Register(Component
            .For<IRepositoryProvider>()
            .ImplementedBy<RepositoryProvider>()
            .LifestylePerWebRequest());

        container.Register(Component
            .For<IGdpUow>()
            .ImplementedBy<GdpUow>()
            .LifestylePerWebRequest());

        container.Register(Classes.FromThisAssembly()
            .BasedOn<Hub>()
            .LifestyleTransient());            
    }
}
public class HubsInstaller : IWindsorInstaller
{
    public void Install(IWindsorContainer container, IConfigurationStore store)
    {
        container.Register(Component
            .For<RepositoryFactories>()
            .ImplementedBy<RepositoryFactories>()
            .LifestyleSingleton());

        container.Register(Component
            .For<IRepositoryProvider>()
            .ImplementedBy<RepositoryProvider>()
        .LifeStyle.HybridPerWebRequestTransient());

        container.Register(Component
            .For<IGdpUow>()
            .ImplementedBy<GdpUow>()
            .LifeStyle.HybridPerWebRequestTransient());

        container.Register(Component
            .For<IHubHandler>()
            .ImplementedBy<HubHandler>()
            .LifestyleSingleton());

        container.Register(Classes.FromThisAssembly()
            .BasedOn<Hub>()
            .LifestyleTransient());
    }
}
public class HubHandler : IHubHandler
{
    private static System.Timers.Timer aTimer;
    private IHubConnectionContext Clients { get; set; }
    public IGdpUow Uow { get; set; }
    DateTime lastDate = DateTime.UtcNow;

    public void SetClients(IHubConnectionContext clients)
    {
        Clients = clients;
    }

    public void StartTimer()
    {
        aTimer = new System.Timers.Timer(10000);
        aTimer.Elapsed += new ElapsedEventHandler(SendNewMessage);
        aTimer.Enabled = true;

        //If the timer is declared in a long-running method, use KeepAlive to prevent garbage collection from occurring before the method ends.
        GC.KeepAlive(aTimer);     
    }

    public void SendNewMessage(object state, ElapsedEventArgs elapsedEventArgs)
    {
        // Get a hub context for ServerHub
        var serverHub = GlobalHost.ConnectionManager.GetHubContext<ServerHub>();

        // TODO: This is throwing the error: The operation cannot be completed because the DbContext has been disposed
        var gdpConfigurationsRecord = Uow.GdpConfigurations.GetByPredicate(a => a.Description.Equals("LastDateTimeMessagesCheck")).SingleOrDefault();
        if (gdpConfigurationsRecord == null)
        {
            throw new ApplicationException("Please set the LastDateTimeMessagesCheck value in GdpConfigurations");
        }

        // Send a message to all the clients
        serverHub.Clients.All.handleSendNewMessages("");
    }
}
更新3

我从温莎那里得到一个错误

如果我把它作为IoC.config中的最新一行(在应用程序_Start中调用)

如果我将它从IoC.config中删除,并尝试在中使用它作为应用程序\u Start中的最新一行,也会发生同样的事情

webApicontainer.Resolve<IHubHandler>().StartTimer();
Container.Resolve<IHubHandler>().StartTimer();
    protected void Application_Start()
    {
        RegisterHubs.Start();
        IocConfig.RegisterIoc(GlobalConfiguration.Configuration);
        GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule());
        AreaRegistration.RegisterAllAreas();
        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
        GlobalConfig.CustomizeConfig(GlobalConfiguration.Configuration);
    }
在哪里/如何使用

Container.Resolve<IHubHandler>().StartTimer();

我甚至不明白为什么它应该在ControllerInstaller中,而不是在HubInstaller中…

在我看来,您正在将UoW注入Hub,但希望在计时器回调中使用该实例。问题在于,集线器实例及其依赖项在处理其收到的最后一条消息后将在逻辑上被清除(例如,已释放),因此当计时器回调触发时,它正在查找已释放的实例

最好将这种基于计时器的逻辑从集线器转移到一个单独的类中,该类在需要时解析集线器上下文以触发消息。下面是一个示例,说明在该类中获取消息并将其发送到集线器的逻辑可能是什么:

   // Get a hub context for ServerHub
   IHubContext serverHub = GlobalHost.ConnectionManager.GetHubContext<ServerHub>();

   // Send a message to all the clients
   serverHub.Clients.All.SendNewMessage(e.SignalTime);
然后,在安装容器后的应用程序启动范围内的某个地方(例如,如果是ASP.NET,则为应用程序启动),您希望在注册的
IHubHandler
上启动计时器:

container.Resolve<IHubHandler>().StartTimer();
public class ServerHub : Hub
{
    public IGdpUow Uow { get; set; }

    public void GetAllMessages()
    {
        var messagesList = Uow.Messages.GetAll().Select(
            newMessage => new MessageDto
            {
                MessageId = newMessage.MessageId,
                Messagestatus = newMessage.MessageStatus.Description
            });

        Clients.All.handleMessages(messagesList);
    }
}
首先,作为免责声明,这是一个快速而肮脏的示例,只是想让您了解如何将这些东西连接在一起。一般来说,让一个类实际上依赖于IoC框架(在本例中是IKernel)不是一个好的设计。然而,由于该类确实需要管理回调中的生存期范围,因此它确实需要与它所使用的容器保持密切关系。你可能想把这个清理一下


其次,您可能不想直接在回调中使用GlobalHost.ConnectionManager,而是想通过容器实际解析
IConnectionManager
。显然,您必须将默认的
ConnectionManager
实例注册为容器中的
IConnectionManager
,然后signar将看到/使用该实例,而不是后退并创建自己的实例。这种解耦将允许您使用一个mock/fake
IConnectionManager
实现测试
HubHandler
类,这可能是您所需要的。

在我看来,您似乎正在将UoW注入到Hub中,但希望在计时器回调中使用该实例。问题在于,集线器实例及其依赖项在处理其收到的最后一条消息后将在逻辑上被清除(例如,已释放),因此当计时器回调触发时,它正在查找已释放的实例

最好将这种基于计时器的逻辑从集线器转移到一个单独的类中,该类在需要时解析集线器上下文以触发消息。下面是一个示例,说明在该类中获取消息并将其发送到集线器的逻辑可能是什么:

   // Get a hub context for ServerHub
   IHubContext serverHub = GlobalHost.ConnectionManager.GetHubContext<ServerHub>();

   // Send a message to all the clients
   serverHub.Clients.All.SendNewMessage(e.SignalTime);
然后,在安装容器后的应用程序启动范围内的某个地方(例如,如果是ASP.NET,则为应用程序启动),您希望在注册的
IHubHandler
上启动计时器:

container.Resolve<IHubHandler>().StartTimer();
public class ServerHub : Hub
{
    public IGdpUow Uow { get; set; }

    public void GetAllMessages()
    {
        var messagesList = Uow.Messages.GetAll().Select(
            newMessage => new MessageDto
            {
                MessageId = newMessage.MessageId,
                Messagestatus = newMessage.MessageStatus.Description
            });

        Clients.All.handleMessages(messagesList);
    }
}
首先,作为免责声明,这是一个快速而肮脏的示例,只是想让您了解如何将这些东西连接在一起。一般来说,让一个类实际上依赖于IoC框架(在本例中是IKernel)不是一个好的设计。然而,由于该类确实需要管理回调中的生存期范围,因此它确实需要与它所使用的容器保持密切关系。你可能想把这个清理一下


其次,您可能不想直接在回调中使用GlobalHost.ConnectionManager,而是想通过容器实际解析
IConnectionManager
。显然,您必须将默认的
ConnectionManager
实例注册为容器中的
IConnectionManager
,然后signar将看到/使用该实例,而不是后退并创建自己的实例。这种解耦将允许您使用一个mock/fake
IConnectionManager
实现来测试
HubHandler
类,这可能是需要的。

正如我看到的,您正在做大量的抽象。。。这使得整个事情比它应该的复杂得多

从问题描述来看,它似乎真的与温莎配置的生活方式有关

我能给你的建议是:试试这本书提供的
HybridPerWebRequestTransient
生活方式。它解决了我在实现
signal.Hub
类的派生类中实例化
DbContext
时遇到的错误

请务必仔细阅读以下帖子:


正如我看到的,你在做很多抽象。。。这使得整个事情比它应该的复杂得多

从问题描述来看,它似乎真的与温莎配置的生活方式有关

我能建议什么
Container.Resolve<IHubHandler>().StartTimer();
public static class IocConfig
{
    public static IWindsorContainer Container { get; private set; }

    public static void RegisterIoc(HttpConfiguration config)
    {
        var webApicontainer = new WindsorContainer().Install(new WebWindsorInstaller());
        GlobalConfiguration.Configuration.DependencyResolver = new WebApiWindsorDependencyResolver(webApicontainer);
        Container = new WindsorContainer().Install(new ControllersInstaller());
        DependencyResolver.SetResolver(new MvcWindsorDependencyResolver(Container)); 
        ServiceLocator.SetLocatorProvider(() => new WindsorServiceLocator(Container));
        var controllerFactory = new WindsorControllerFactory(Container.Kernel);
        ControllerBuilder.Current.SetControllerFactory(controllerFactory); 
        webApicontainer.Resolve<IHubHandler>().StartTimer();
    }
}
    protected void Application_Start()
    {
        RegisterHubs.Start();
        IocConfig.RegisterIoc(GlobalConfiguration.Configuration);
        GlobalHost.HubPipeline.AddModule(new LoggingPipelineModule());
        AreaRegistration.RegisterAllAreas();
        WebApiConfig.Register(GlobalConfiguration.Configuration);
        FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
        RouteConfig.RegisterRoutes(RouteTable.Routes);
        BundleConfig.RegisterBundles(BundleTable.Bundles);
        AuthConfig.RegisterAuth();
        GlobalConfig.CustomizeConfig(GlobalConfiguration.Configuration);
    }
   // Get a hub context for ServerHub
   IHubContext serverHub = GlobalHost.ConnectionManager.GetHubContext<ServerHub>();

   // Send a message to all the clients
   serverHub.Clients.All.SendNewMessage(e.SignalTime);
container.Register(Component.For<IHubHandler>()
    .ImplementedBy<HubHandler>()
    .LifestyleSingleton());
container.Resolve<IHubHandler>().StartTimer();
public class HubHandler : IHubHandler
{
    System.Timers.Timer aTimer;
    DateTime lastDate = DateTime.UtcNow;
    IKernel kernel;

    public HubHandler(IKernel kernel)
    {
        this.kernel = kernel;
    }

    public void StartTimer()
    {
        aTimer = new System.Timers.Timer(10000);
        aTimer.Elapsed += new ElapsedEventHandler(SendNewMessage);
        aTimer.Enabled = true;
    }

    public void SendNewMessage(object state, ElapsedEventArgs elapsedEventArgs)
    {
        // Create a container specific to the scope of this timer callback to 
        // resolve dependencies from
        // NOTE: instances resolved from this container will be cleaned up when 
        // the container itself is disposed at the end of the using block
        // NOTE: you must make sure to register the types you will use here with 
        // LifestyleScoped() as well so they will be disposed of when the scope ends
        using(kernel.BeginScope())
        {
            // Resolve our IGdpUow dependency from the scoped container                
            IGdpUow gdpUow = kernel.Resolve<IGdpUow>();

            var gdpConfigurationsRecord = gdpUow.GdpConfigurations.GetByPredicate(a => a.Description.Equals("LastDateTimeMessagesCheck")).SingleOrDefault();

            if (gdpConfigurationsRecord == null)
            {
                throw new ApplicationException("Please set the LastDateTimeMessagesCheck value in GdpConfigurations");
            }

            // Get a hub context for ServerHub
            var serverHub = GlobalHost.ConnectionManager.GetHubContext<ServerHub>();

            // Send a message to all the clients
            serverHub.Clients.All.handleSendNewMessages("");
       }
    }
}
public class ServerHub : Hub
{
    public IGdpUow Uow { get; set; }

    public void GetAllMessages()
    {
        var messagesList = Uow.Messages.GetAll().Select(
            newMessage => new MessageDto
            {
                MessageId = newMessage.MessageId,
                Messagestatus = newMessage.MessageStatus.Description
            });

        Clients.All.handleMessages(messagesList);
    }
}