Операция не может быть завершена, так как DbContext был удален с помощью EF5 SignalR и Windsor Castle как IoC.

Я работаю над проектом со следующими технологиями:

  • Версия Entity Framework: 5
  • Миграция Entity Framework
  • СигналR версии 1.1.2
  • IoC: Виндзорский замок
  • Дотнет Фреймворк 4.5
  • веб-API
  • Визуальная студия 2012
  • SQL Server экспресс 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)

public class EFRepository<T> : IRepository<T> where T : class
{
    public EFRepository(DbContext dbContext)
    {
        if (dbContext == null)
            throw new ArgumentNullException("dbContext");
        DbContext = dbContext;
        DbSet = DbContext.Set<T>();
    }

    protected DbContext DbContext { get; set; }

    protected DbSet<T> DbSet { get; set; }

    public virtual IQueryable<T> GetAll()
    {
        return DbSet;
    }

    public virtual IQueryable<T> GetAllIncluding(params Expression<Func<T, object>>[] includeProperties)
    {
        IQueryable<T> query = DbContext.Set<T>();
        foreach (var includeProperty in includeProperties)
        {
            query = query.Include(includeProperty);
        }

        return query;
    }

    public virtual T GetById(long id)
    {
        return DbSet.Find(id);
    }

    public virtual IQueryable<T> GetByPredicate(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
    {
        IQueryable<T> query = DbContext.Set<T>().Where(predicate);
        return query;
    }

    public virtual IQueryable<T> GetByPredicateIncluding(System.Linq.Expressions.Expression<Func<T, bool>> predicate, params Expression<Func<T, object>>[] includeProperties)
    {
        IQueryable<T> query = DbContext.Set<T>().Where(predicate);
        foreach (var includeProperty in includeProperties)
        {
            query = query.Include(includeProperty);
        }

        return query;
    }

    public virtual void Upsert(T entity, Func<T, bool> insertExpression)
    {
        if (insertExpression.Invoke(entity))
        {
            Add(entity);
        }
        else
        {
            Update(entity);
        }
    }

    public virtual void Add(T entity)
    {
        DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
        if (dbEntityEntry.State != EntityState.Detached)
        {
            dbEntityEntry.State = EntityState.Added;
        }
        else
        {
            DbSet.Add(entity);
        }
    }

    public virtual void Update(T entity)
    {
        DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
        if (dbEntityEntry.State == EntityState.Detached)
        {
            DbSet.Attach(entity);
        }
        dbEntityEntry.State = EntityState.Modified;
    }

    public virtual void Delete(T entity)
    {
        DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
        if (dbEntityEntry.State != EntityState.Deleted)
        {
            dbEntityEntry.State = EntityState.Deleted;
        }
        else
        {
            DbSet.Attach(entity);
            DbSet.Remove(entity);
        }
    }

    public virtual void Delete(int id)
    {
        var entity = GetById(id);
        if (entity == null) return; // not found; assume already deleted.
        Delete(entity);
    }
}

Установщик концентраторов

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());            
    }
}

IocConfig.cs

using System.Web.Routing;
using Microsoft.AspNet.SignalR;

namespace CompanyGdpSoftware.Server.Ui.Web
{
    using System.Web.Http;
    using System.Web.Mvc;
    using Castle.Windsor;
    using CommonServiceLocator.WindsorAdapter;
    using Infrastructure;
    using Microsoft.Practices.ServiceLocation;

    public static class IocConfig
    {
        public static IWindsorContainer Container { get; private set; }

        public static void RegisterIoc(HttpConfiguration config)
        {
            var signalrDependencyContainer = new WindsorContainer().Install(new HubsInstaller());
            var signalrDependency = new SignalrDependencyResolver(signalrDependencyContainer.Kernel);
            GlobalHost.DependencyResolver = signalrDependency;
            //RouteTable.Routes.MapHubs(signalrDependency); // Needed to remove the parameter when moved from SignalR RC to 1.1.2
            RouteTable.Routes.MapHubs(); // Used this one when moving to SignalR release update.

            // Set the dependency resolver for Web API.
            var webApicontainer = new WindsorContainer().Install(new WebWindsorInstaller());
            GlobalConfiguration.Configuration.DependencyResolver = new WebApiWindsorDependencyResolver(webApicontainer);

            // Set the dependency resolver for Mvc Controllers
            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); 
        }
    }
}

UoW (единица работы)

public class GdpUow : IGdpUow, IDisposable
    {
        public GdpUow(IRepositoryProvider repositoryProvider)
        {
            CreateDbContext();

            repositoryProvider.DbContext = DbContext;
            RepositoryProvider = repositoryProvider;
        }

        public IRepository<Branch> Branches { get { return GetStandardRepo<Branch>(); } }

        public void Commit()
        {
            DbContext.SaveChanges();
        }

        protected void CreateDbContext()
        {
            DbContext = new GdpSoftwareDbContext();

            // Do NOT enable proxied entities, else serialization fails
            DbContext.Configuration.ProxyCreationEnabled = false;

            // Load navigation properties explicitly (avoid serialization trouble)
            DbContext.Configuration.LazyLoadingEnabled = false;

            // Because Web API will perform validation, I don't need/want EF to do so
            DbContext.Configuration.ValidateOnSaveEnabled = false;
        }

        protected IRepositoryProvider RepositoryProvider { get; set; }

        private IRepository<T> GetStandardRepo<T>() where T : class
        {
            return RepositoryProvider.GetRepositoryForEntityType<T>();
        }
        private T GetRepo<T>() where T : class
        {
            return RepositoryProvider.GetRepository<T>();
        }

        private GdpSoftwareDbContext DbContext { get; set; }

        #region IDisposable

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (!disposing)
            {
                return;
            }

            if (DbContext != null)
            {
                DbContext.Dispose();
                DbContext = null;
            }
        }
        #endregion
    }
}

Извлечь из ServerHub

    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;

        public IGdpUow Uow { get; set; }

        DateTime lastDate = DateTime.UtcNow;

        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)
        {
            SendNewMessage(e.SignalTime);
        }

        public void SendNewMessage(DateTime SignalTime)
        {
            // TODO: This is throwing the error: The operation cannot be completed because the DbContext has been disposed
            var configurationsRecord = this.Uow.GdpConfigurations.GetByPredicate(a => a.Description.Equals("LastDateTimeCheck")).SingleOrDefault();
            if (configurationsRecord == null)
            {
                throw new ApplicationException("Please set the LastDateTimeCheck value");
            }
        }

        // 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);
        }

    }

ОБНОВЛЕНИЕ Я добавил это, что предложил Дрю... до сих пор не повезло

    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);
        }
    }

и новый класс

HubHandler

    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);
        }
    }
}

ОБНОВЛЕНИЕ 2

Теперь я переместил таймер из Hub в HubHandler. Также я установил пакет Nuget для использования LifeStyle.HybridPerWebRequestTransient для GdpUow и RepositoryProvider. Все та же проблема.

Концентратор серверов

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);
        }
    }
}

Установщик концентратора

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());
    }
}

HubHandler

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("");
    }
}

RegisterHubs.cs

public static class RegisterHubs
{
    public static void Start()
    {
        // Register the default hubs route: ~/signalr
        var signalrDependencyContainer = new WindsorContainer().Install(new HubsInstaller());
        var signalrDependency = new SignalrDependencyResolver(signalrDependencyContainer.Kernel);
        GlobalHost.DependencyResolver = signalrDependency;
        RouteTable.Routes.MapHubs();
    }
}

ОБНОВЛЕНИЕ 3

Я получаю сообщение об ошибке от Виндзора...

Если я поставлю это как последнюю строку в IoC.config (которая вызывается в Application_Start)

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

Я получил:

No component for supporting the service GdpSoftware.Server.Ui.Web.Hubs.IHubHandler was found

То же самое, если я удалю его из IoC.config и попытаюсь использовать его как последнюю строку в Application_Start.

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

Если я добавлю

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

в ControllersInstaller я получаю

Can't create component 'GdpSoftware.Server.Ui.Web.Hubs.HubHandler' as it has dependencies to be satisfied. (Service 'Castle.Windsor.IWindsorContainer' which was not registered)

Где/как я могу использовать

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

Это мой текущий IoC.config

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();
    }
}

и это мой Application_Start

    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);
    }

Я даже не понимаю, почему это должно быть в ControllersInstaller, а не в HubInstaller...


person polonskyg    schedule 05.07.2013    source источник
comment
Какова вся трассировка стека для исключения?   -  person Steven V    schedule 05.07.2013


Ответы (2)


Мне кажется, что вы вводите свой UoW в концентратор, но ожидаете использовать экземпляр в обратном вызове таймера. Проблема в том, что экземпляр концентратора и его зависимости будут логически очищены (например, удалены) после того, как он обработает последнее полученное сообщение, поэтому, когда срабатывает обратный вызов таймера, он находит уже удаленный экземпляр.

Логику такого типа, основанную на таймере, лучше перенести из концентратора в отдельный класс, который разрешает контекст концентратора для запуска сообщений, когда это необходимо. Итак, вот пример того, как может выглядеть логика для получения и отправки сообщения в хаб в этом классе:

   // 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);

Хитрость для вас будет заключаться в том, чтобы работать с контейнером, чтобы создать область жизненного цикла, когда срабатывает таймер, чтобы у вас были экземпляры зависимостей, которые вам нужны, специфичные для этого одного запуска события. Здесь, в StackOverflow и в Интернете в целом, есть много примеров того, как делать подобные вещи, поэтому я не буду подробно описывать здесь их особенности.

ОБНОВЛЕНИЕ

Я провел небольшое исследование Windsor (обычно я использую Autofac/Ninject), поэтому теперь я могу предоставить вам лучший пример кода. Давайте начнем с того, что вы назвали своим HubHandler классом. Он должен быть разработан как синглтон, который вы регистрируете в контейнере в своей программе установки, а затем разрешаете и позже разрешаете при запуске запускать таймер. Итак, что-то вроде этого в вашем HubInstaller::Install:

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

Затем где-то в области запуска вашего приложения после установки контейнера (например, Application_Start, если ASP.NET) вы хотите запустить таймер на зарегистрированном IHubHandler:

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

Затем вы должны изменить свой класс HubHandler, чтобы он выглядел примерно так:

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("");
       }
    }
}

Затем просто обновите свой класс ServerHub, чтобы он больше не знал/не делал ничего с IHubHandler:

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 в вашем контейнере, и тогда SignalR увидит/использует этот экземпляр, а не отступит и создаст свой собственный. Это разъединение позволит вам протестировать класс HubHandler с фиктивной/поддельной реализацией IConnectionManager, что, вероятно, желательно.

person Drew Marsh    schedule 05.07.2013
comment
Итак, вы говорите, что нужно создать еще один класс с таймером и обработчиком для onTimeEvent и отправить клиентов HubConnectionContext в этот новый класс (мне нужно вызвать client.something для передачи сообщений через SignalR прослушивающим клиентам. Я прав? ? - person polonskyg; 08.07.2013
comment
Правильно, я добавлю немного больше деталей к ответу. - person Drew Marsh; 08.07.2013
comment
Дрю, большое спасибо, я добавил этот фрагмент кода (в вопросе, который я показываю). Я вижу экземпляры serverHub и gdpUow, но продолжаю получать одно и то же сообщение об ошибке. Я пропустил что-то из вашего предложения? Спасибо еще раз! - person polonskyg; 08.07.2013
comment
Я переместил таймер из Hub в HubHandler. Можешь ли ты проверить, не о тебе ли ты подумал? Я добавил код после текста под названием ОБНОВЛЕНИЕ 2. Большое спасибо!!! - person polonskyg; 10.07.2013
comment
Нет, это по-прежнему неправильно, потому что время жизни вашего класса HubHandler по-прежнему привязано к самому классу-концентратору. Я потратил некоторое время на изучение того, как работает единство (обычно я использую Autofac/Ninject), поэтому позвольте мне обновить свой ответ, чтобы я мог дать вам точный код. - person Drew Marsh; 10.07.2013
comment
Я реализовал все, кроме последнего, думаю, что я не могу понять, что я могу делать неправильно. Он говорит, что не может создать компонент IHubHandler для вызова StartTimer. Вы случайно не знаете, что там не так? Я добавил код в ОБНОВЛЕНИЕ 3 выше. Спасибо! - person polonskyg; 10.07.2013
comment
Опять же, это мой недостаток знаний в Виндзоре. Необходимо использовать IKernel и BeginScope. Я снова обновляю свой ответ. - person Drew Marsh; 10.07.2013
comment
ммм... странно... я получаю сообщение об ошибке Не удалось импортировать метод в kernel.BeginScope(). Resharpers предлагает импортировать Castle.MicroKernel.LifestyleExtensions.BeginScope (это Ikernel), но выдает эту ошибку. Ты знаешь почему? - person polonskyg; 10.07.2013
comment
Да, вам нужно использовать пространство имен Castle.MicroKernel.Lifestyle, чтобы получить метод расширения BeginScope. Я не знаю, почему у Resharper могут возникнуть проблемы с выяснением/добавлением оператора использования для этого. Просто сделайте это вручную и посмотрите, что произойдет. - person Drew Marsh; 10.07.2013
comment
Оно работает!!! Дрю, у меня нет слов, чтобы отблагодарить тебя за всю твою помощь! большое спасибо!!! - person polonskyg; 10.07.2013
comment
@polonskyg: добрался сюда и увидел, что вы решили проблему с помощью Дрю Марш. Хороший! Мне просто любопытно: вы продолжали использовать HybridPerWebRequestTransient? - person Leniel Maccaferri; 11.07.2013
comment
@LenielMacaferi это совершенно верно. Мне все еще нужно было использовать HybridPerWebRequestTransient, иначе я получаю HttpContext.Current равно null. PerWebRequestLifestyle можно использовать только в ASP.Net. Большое спасибо, я тоже нажму на стрелку вверх на вашем ответе. - person polonskyg; 11.07.2013

Как я вижу, вы делаете много абстракций... это делает все намного сложнее, чем должно быть.

Судя по описанию проблемы, она действительно связана с образом жизни, настроенным в Виндзоре.

Я могу вам посоветовать: попробуйте HybridPerWebRequestTransient стиль жизни, доступный в этом пакете NuGet. Это решило ту самую ошибку, с которой я столкнулся при попытке создать экземпляр DbContext внутри производного класса, который реализует класс SignalR.Hub.

Убедитесь, что вы внимательно прочитали эти сообщения:

Гибридный образ жизни в Виндзоре

SignalR OnDisconnected Task and Dependency Injection with Castle Windsor — Гибридный образ жизни спешит на помощь.

person Leniel Maccaferri    schedule 09.07.2013
comment
Я уже читал ваш блог, очень интересно, и я добавил сюда код... но я не знаю, может я что-то упустил, потому что он не работает. Если возможно, обратите внимание на то, что я добавил под названием ОБНОВЛЕНИЕ 2. Спасибо!!! - person polonskyg; 10.07.2013