我正在使用以下技术开发一个项目:
- 实体框架版本:5
- 实体框架迁移
- SignalR 版本 1.1.2
- 国际奥委会:温莎城堡
- 点网框架 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);
}
}
和新班级
集线器处理程序
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());
}
}
集线器处理程序
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("");
}
}
注册中心.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 中......