在ASP.NET MVC应用程序中,我尝试使用SQL Server的CONTEXT_INFO
来传递当前登录的用户,以便我的审计触发器不仅记录Web服务器登录,而且也是网站的登录。
我无法确定当前用户是否总会被送入数据库服务器上下文。
在后端我设置了一切,设置上下文的sproc,拉动它的函数和DML触发器进行记录,没问题。
应用程序结束更多参与。我订阅了Database.Connection.StateChange
事件,因此我可以捕获每个新打开的连接并相应地设置此上下文。
此外,为了能够在数据层(无法访问Web项目)中检索MVC站点的当前登录ID,我向EF构造函数提供了一个委托,该构造函数将返回用户ID。这也意味着我设置的任何其他外围项目也需要这种依赖,并且它在Web开发期间保留了大部分实现细节:
public class CoreContext : DbContext
{
Func<int> _uidObtainer;
public CoreContext(Func<int> uidObtainer) : base(nameof(CoreContext)) { construct(uidObtainer); }
public CoreContext(Func<int> uidObtainer, string connection) : base(connection) { construct(uidObtainer); }
void construct(Func<int> uidObtainer) {
// disallow updates of the db from our models
Database.SetInitializer<CoreContext>(null);
// catch the connection change so we can update for our userID
_uidObtainer = uidObtainer;
Database.Connection.StateChange += connectionStateChanged;
}
private void connectionStateChanged(object sender, System.Data.StateChangeEventArgs e) {
// set our context info for logging
if (e.OriginalState == System.Data.ConnectionState.Open ||
e.CurrentState != System.Data.ConnectionState.Open) {
return;
}
int uid = _uidObtainer();
var conn = ((System.Data.Entity.Core.EntityClient.EntityConnection)sender).StoreConnection;
var cmd = conn.CreateCommand();
cmd.CommandText = "audit.SetContext";
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.Add(new System.Data.SqlClient.SqlParameter("@DomainUserID", uid));
cmd.ExecuteNonQuery();
}
// etc etc...
在我的MVC项目中,我将拥有如下代码:
context = new Data.CoreContext(() => AppService.UserID());
(利用易于访问的方法作为代理传递,而代理又从HttpContext.Current.User
读取)
这一切都很好,除了一个未知的:
我知道EF Context实例可以跨多个登录用户,因为它是IIS应用程序池的一部分,而不是每个HttpContext
我不知道关于连接池以及如何打开/重新打开连接是安全的,因为我知道每次StateChange
处理程序运行时,我实际上都是从委托中检索新的UserID。
不同地说:单个连接是否可以打开并在两个单独的HttpContext
实例的范围内使用?我相信是的,看到如何执行其他任何事情(至少不是我所知道的)。
我该怎么做才能确保每个连接都获得当前的HttpContext
?
(可能相关的说明:EF本身之外没有UoW / Repository模式,数据上下文通常每个控制器实例化一次)
答案 0 :(得分:0)
我看到:每个控制器的一个上下文通常是不正确的。相反,我应该为每个请求使用一个上下文,除了其他优点之外,还确保我的场景也能正常运行。
我找到了这个答案,解释了其背后的原因:One DbContext per web request... why?
我找到了这个答案,它简明扼要地解释了如何通过main
和BeginRequest
来实现:One DbContext per request in ASP.NET MVC (without IOC container)
(下面粘贴第二个答案的代码以防止链接)
EndRequest
在你的EntityContext类中......
protected virtual void Application_BeginRequest()
{
HttpContext.Current.Items["_EntityContext"] = new EntityContext();
}
protected virtual void Application_EndRequest()
{
var entityContext = HttpContext.Current.Items["_EntityContext"] as EntityContext;
if (entityContext != null)
entityContext.Dispose();
}