con*_*att 19 c# entity-framework entity-framework-4.1 asp.net-mvc-3
我收到"在创建模型时无法使用上下文." 在我的一个网页中的Web应用程序中出现问题.此特定网页每2-3秒POST一次,以刷新屏幕.根据我的测试,我发现如果我有2个或更多浏览器实例打开到这个页面,几分钟后我收到一个"创建模型时不能使用上下文"来自存储库深处的异常.
此代码调用"服务"来检索所需的数据.此代码在MVC Controller类的自定义授权属性中执行.
// Code in custom "Authorization" attribute on the controller
int? stationId = stationCookieValue; // Read value from cookie
RoomStationModel roomStationModel = RoomStationService.GetRoomStation(stationId); // Error occurs inside this call
Run Code Online (Sandbox Code Playgroud)
这是"RoomStationModel"
public class RoomStationModel
{
[Key]
public int RoomStationId { get; set; }
public int? RoomId { get; set; }
[ForeignKey("RoomId")]
public virtual RoomModel Room { get; set; }
/* Some other data properties.... */
}
public class RoomModel
{
[Key]
public int RoomId { get; set; }
public virtual ICollection<RoomStationModel> Stations { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
以下是上述服务调用的代码:
public RoomStationModel GetRoomStation(int? roomStationId)
{
RoomStationModel roomStationModel = null;
if (roomStationId.HasValue)
{
using (IRepository<RoomStationModel> roomStationRepo = new Repository<RoomStationModel>(Context))
{
roomStationModel = roomStationRepo.FirstOrDefault(rs => rs.RoomStationId == roomStationId.Value, false, new string[] { "Room" });
}
}
return roomStationModel;
}
Run Code Online (Sandbox Code Playgroud)
这是存储库....发生错误的地方
public class Repository<TObject> : IRepository<TObject> where TObject : class
{
protected MyContext Context = null;
public Repository(IDataContext context)
{
Context = context as MyContext;
}
protected DbSet<TObject> DbSet { get { return Context.Set<TObject>(); } }
public virtual TObject FirstOrDefault(Expression<Func<TObject, bool>> predicate, bool track = true, string[] children = null)
{
var objectSet = DbSet.AsQueryable();
if (children != null)
foreach (string child in children)
objectSet = objectSet.Include(child);
if (track)
return objectSet.Where(predicate).FirstOrDefault<TObject>(predicate);
return objectSet.Where(predicate).AsNoTracking().FirstOrDefault<TObject>(predicate);
}
}
Run Code Online (Sandbox Code Playgroud)
错误的屏幕截图:

Stacktrace:
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.InternalContext.Initialize()
at System.Data.Entity.Internal.InternalContext.GetEntitySetAndBaseTypeForType(Type entityType)
at System.Data.Entity.Internal.Linq.InternalSet`1.Initialize()
at System.Data.Entity.Internal.Linq.InternalSet`1.Include(String path)
at System.Data.Entity.Infrastructure.DbQuery`1.Include(String path)
at System.Data.Entity.DbExtensions.Include[T](IQueryable`1 source, String path)
at Vanguard.AssetManager.Data.Repository`1.FirstOrDefault(Expression`1 predicate, Boolean track, String[] children) in C:\Work\VanguardAssetManager\Main\Vanguard.AssetManager.Data\Repository.cs:line 100
at Vanguard.AssetManager.Services.Business.RoomStationService.GetRoomStation(Nullable`1 roomStationId) in C:\Work\VanguardAssetManager\Main\Vanguard.AssetManager.Services\Business\RoomStationService.cs:line 61
at Vanguard.AssetManager.Web.Attributes.RoomStationAuthorizeAttribute.OnAuthorization(AuthorizationContext filterContext) in C:\Work\VanguardAssetManager\Main\Vanguard.AssetManager.Web\Attributes\RoomStationAuthorizeAttribute.cs:line 52
at System.Web.Mvc.ControllerActionInvoker.InvokeAuthorizationFilters(ControllerContext controllerContext, IList`1 filters, ActionDescriptor actionDescriptor)
at System.Web.Mvc.ControllerActionInvoker.InvokeAction(ControllerContext controllerContext, String actionName)
Run Code Online (Sandbox Code Playgroud)
EF版本:4.1(代码优先)
Kit*_*Kit 30
您的存储库是短暂的(您为每次调用创建它,GetRoomStation()但您的实际上下文似乎是长期存在的(RoomServiceStation.Context属性).这意味着对您的Web应用程序的每次调用都将使用相同的上下文.
这是"N层中的EF"场景,您尝试在Web应用程序的架构无状态模型中保留有状态(上下文).所有这些请求都被引导到不同线程上的相同上下文,并且您正在获得竞争条件.
一个线程可以启动您的上下文的第一次初始化以响应请求,另一个线程尝试使用上下文.第二个请求认为上下文已准备就绪,您将获得此异常.如果你有多个上下文尝试在另一个SO线程中建议的同时"旋转",你甚至可以得到这个.
你可以做一些事情.您可以尝试使用悲观锁定来访问您的上下文,但是您会遇到不必要的瓶颈.您可以尝试创建某种"在客户端调用我之前,初始化上下文"代码,但您必须找到一个好的地方来执行此操作,可能使用MSDN线程中建议的"强力"方法.
更好的办法是为后端服务的每个请求创建一个新的上下文.有一些开销,是的,但很少.与悲观锁定相比,开销可能不太可能导致性能下降,并且不会受到应用程序池回收事件的影响,这些事件会扩展到服务器场中的Web应用程序等等.
如果您依赖于更改跟踪或上下文的其他有状态性质,您将失去此权益.在这种情况下,您将不得不提出一种不同的机制来跟踪和最小化数据库命中.
从MSDN文章中总结出来(强调我的):
如果将实体从一个层序列化到另一个层,则建议的模式是将中间层上下文保持足够长的时间以便进行单个服务方法调用.后续调用将启动上下文的新实例以完成每个任务.
EF/WCF/N-tier上的一个帖子也可能会给你一些见解,Jorge的博客文章#5讨论了N-Tiers中的EF(整个系列可能是一个很好的阅读).顺便说一下,我遇到了同样的事情:许多客户同时遇到上下文,导致了这个问题.
这似乎是两件事之一,某种竞争条件或“上下文范围”问题。您应该确保上下文以线程安全的方式初始化,并且上下文不会被不同的线程访问,以防止竞争条件。导致此错误的一个难以发现的原因是在 OnModelCreation 重写中访问模型本身。
| 归档时间: |
|
| 查看次数: |
28759 次 |
| 最近记录: |