在排队的后台工作项目中保留主体
Retaining principal inside queued background work item
我正在使用 ASP.Net Web API 2 / .Net 4.5.2。
我试图在对后台工作项进行排队时保留调用主体。为此,我正在尝试:
Thread.CurrentPrincipal = callingPrincipal;
但是当我这样做时,我得到一个 ObjectDisposedException:
System.ObjectDisposedException: Safe handle has been closed
如何将当前主体保留在后台工作项中?
我能以某种方式复制主体吗?
public void Run<T>(Action<T> action)
{
_logger.Debug("Queueing background work item");
var callingPrincipal = Thread.CurrentPrincipal;
HostingEnvironment.QueueBackgroundWorkItem(token =>
{
try
{
// UNCOMMENT - THROWS EXCEPTION
// Thread.CurrentPrincipal = callingPrincipal;
_logger.Debug("Executing queued background work item");
using (var scope = DependencyResolver.BeginLifetimeScope())
{
var service = scope.Resolve<T>();
action(service);
}
}
catch (Exception ex)
{
_logger.Fatal(ex);
}
finally
{
_logger.Debug("Completed queued background work item");
}
});
}
你的问题是Thread.CurrentPrincipal
处理后后台任务正在执行。发生这种情况是因为 ASP.NET 模型——请求在用户上下文中处理,之后与用户对应的所有值都被释放。所以这恰好发生在你的身份上。尝试保存有关用户及其身份的信息,以便稍后模拟。
您可以查看 support article from Microsoft 以模拟 ASP.NET 站点中的操作,但我认为这对您没有帮助:
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)callingPrincipal.Identity).Impersonate();
//Insert your code that runs under the security context of the authenticating user here.
impersonationContext.Undo();
或者,您可以使用 User.Token,像这样:
HostingEnvironment.QueueBackgroundWorkItem(token =>
{
try
{
_logger.Debug("Executing queued background work item");
using (HostingEnvironment.Impersonate(callingPrincipal.Identity))
{
using (var scope = DependencyResolver.BeginLifetimeScope())
{
var service = scope.Resolve<T>();
action(service);
}
}
// UNCOMMENT - THROWS EXCEPTION
// Thread.CurrentPrincipal = callingPrincipal;
}
catch (Exception ex)
{
_logger.Fatal(ex);
}
finally
{
_logger.Debug("Completed queued background work item");
}
});
我建议您检查您的体系结构设计,以便找到一种方法将后台操作移出到其他上下文中,这样用户身份将在其中停留更长时间。例如,其他方式是使用将当前 OperationContext
传递给 Task
:
// store local operation context
var operationContext = OperationContext.Current;
TaskFactory.StartNew(() =>
{
// initialize the current operation context
OperationContext.Current = operationContext;
action();
})
原来 ClaimsPrincipal
现在有一个复制构造函数。
var principal = new ClaimsPrincipal(Thread.CurrentPrincipal);
这似乎可以解决问题,同时保留所有身份和声明信息。完整功能如下:
public void Run<T>(Action<T> action)
{
_logger.Debug("Queueing background work item");
var principal = new ClaimsPrincipal(Thread.CurrentPrincipal);
HostingEnvironment.QueueBackgroundWorkItem(token =>
{
try
{
Thread.CurrentPrincipal = principal;
_logger.Debug("Executing queued background work item");
using (var scope = DependencyResolver.BeginLifetimeScope())
{
var service = scope.Resolve<T>();
action(service);
}
}
catch (Exception ex)
{
_logger.Fatal(ex);
}
finally
{
_logger.Debug("Completed queued background work item");
}
});
}
我正在使用 ASP.Net Web API 2 / .Net 4.5.2。
我试图在对后台工作项进行排队时保留调用主体。为此,我正在尝试:
Thread.CurrentPrincipal = callingPrincipal;
但是当我这样做时,我得到一个 ObjectDisposedException:
System.ObjectDisposedException: Safe handle has been closed
如何将当前主体保留在后台工作项中?
我能以某种方式复制主体吗?
public void Run<T>(Action<T> action)
{
_logger.Debug("Queueing background work item");
var callingPrincipal = Thread.CurrentPrincipal;
HostingEnvironment.QueueBackgroundWorkItem(token =>
{
try
{
// UNCOMMENT - THROWS EXCEPTION
// Thread.CurrentPrincipal = callingPrincipal;
_logger.Debug("Executing queued background work item");
using (var scope = DependencyResolver.BeginLifetimeScope())
{
var service = scope.Resolve<T>();
action(service);
}
}
catch (Exception ex)
{
_logger.Fatal(ex);
}
finally
{
_logger.Debug("Completed queued background work item");
}
});
}
你的问题是Thread.CurrentPrincipal
处理后后台任务正在执行。发生这种情况是因为 ASP.NET 模型——请求在用户上下文中处理,之后与用户对应的所有值都被释放。所以这恰好发生在你的身份上。尝试保存有关用户及其身份的信息,以便稍后模拟。
您可以查看 support article from Microsoft 以模拟 ASP.NET 站点中的操作,但我认为这对您没有帮助:
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext =
((System.Security.Principal.WindowsIdentity)callingPrincipal.Identity).Impersonate();
//Insert your code that runs under the security context of the authenticating user here.
impersonationContext.Undo();
或者,您可以使用 User.Token,像这样:
HostingEnvironment.QueueBackgroundWorkItem(token =>
{
try
{
_logger.Debug("Executing queued background work item");
using (HostingEnvironment.Impersonate(callingPrincipal.Identity))
{
using (var scope = DependencyResolver.BeginLifetimeScope())
{
var service = scope.Resolve<T>();
action(service);
}
}
// UNCOMMENT - THROWS EXCEPTION
// Thread.CurrentPrincipal = callingPrincipal;
}
catch (Exception ex)
{
_logger.Fatal(ex);
}
finally
{
_logger.Debug("Completed queued background work item");
}
});
我建议您检查您的体系结构设计,以便找到一种方法将后台操作移出到其他上下文中,这样用户身份将在其中停留更长时间。例如,其他方式是使用将当前 OperationContext
传递给 Task
:
// store local operation context
var operationContext = OperationContext.Current;
TaskFactory.StartNew(() =>
{
// initialize the current operation context
OperationContext.Current = operationContext;
action();
})
原来 ClaimsPrincipal
现在有一个复制构造函数。
var principal = new ClaimsPrincipal(Thread.CurrentPrincipal);
这似乎可以解决问题,同时保留所有身份和声明信息。完整功能如下:
public void Run<T>(Action<T> action)
{
_logger.Debug("Queueing background work item");
var principal = new ClaimsPrincipal(Thread.CurrentPrincipal);
HostingEnvironment.QueueBackgroundWorkItem(token =>
{
try
{
Thread.CurrentPrincipal = principal;
_logger.Debug("Executing queued background work item");
using (var scope = DependencyResolver.BeginLifetimeScope())
{
var service = scope.Resolve<T>();
action(service);
}
}
catch (Exception ex)
{
_logger.Fatal(ex);
}
finally
{
_logger.Debug("Completed queued background work item");
}
});
}