- r - 以节省内存的方式增长 data.frame
- ruby-on-rails - ruby/ruby on rails 内存泄漏检测
- android - 无法解析导入android.support.v7.app
- UNIX 域套接字与共享内存(映射文件)
根据我在网上阅读的内容,安全(线程主体)、文化等上下文相关的项目应该在工作执行单元的范围内跨异步线程流动。
不过,我遇到了非常令人困惑且具有潜在危险的错误。我注意到我线程的 CurrentPrincipal 在异步执行过程中丢失了。
这是一个示例 ASP.NET Web API 场景:
首先,让我们设置一个简单的 Web API 配置,其中包含两个用于测试的委托(delegate)处理程序。
他们所做的就是写出调试信息并传递请求/响应,除了第一个“DummyHandler”,它设置线程的主体以及一段要在上下文中共享的数据(请求的相关 ID) .
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.MessageHandlers.Add(new DummyHandler());
config.MessageHandlers.Add(new AnotherDummyHandler());
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
public class DummyHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
CallContext.LogicalSetData("rcid", request.GetCorrelationId());
Thread.CurrentPrincipal = new ClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new[]{ new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "dgdev") }, "myauthisthebest")));
Debug.WriteLine("Dummy Handler Thread: {0}", Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine("User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
Debug.WriteLine("RCID: {0}", CallContext.LogicalGetData("rcid"));
return base.SendAsync(request, cancellationToken)
.ContinueWith(task =>
{
Debug.WriteLine("Dummy Handler Thread: {0}", Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine("User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
Debug.WriteLine("RCID: {0}", CallContext.LogicalGetData("rcid"));
return task.Result;
});
}
}
public class AnotherDummyHandler : MessageProcessingHandler
{
protected override HttpRequestMessage ProcessRequest(HttpRequestMessage request, CancellationToken cancellationToken)
{
Debug.WriteLine(" Another Dummy Handler Thread: {0}", Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(" User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
Debug.WriteLine(" RCID: {0}", CallContext.LogicalGetData("rcid"));
return request;
}
protected override HttpResponseMessage ProcessResponse(HttpResponseMessage response, CancellationToken cancellationToken)
{
Debug.WriteLine(" Another Dummy Handler Thread: {0}", Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(" User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
Debug.WriteLine(" RCID: {0}", CallContext.LogicalGetData("rcid"));
return response;
}
}
很简单。接下来让我们添加一个 ApiController 来处理 HTTP POST,就好像您正在上传文件一样。
public class UploadController : ApiController
{
public async Task<HttpResponseMessage> PostFile()
{
Debug.WriteLine(" Thread: {0}", Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(" User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
Debug.WriteLine(" RCID: {0}", CallContext.LogicalGetData("rcid"));
if (!Request.Content.IsMimeMultipartContent())
{
throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
}
try
{
await Request.Content.ReadAsMultipartAsync(
new MultipartFormDataStreamProvider(
HttpRuntime.AppDomainAppPath + @"upload\temp"));
Debug.WriteLine(" Thread: {0}", Thread.CurrentThread.ManagedThreadId);
Debug.WriteLine(" User: {0}", (Object)Thread.CurrentPrincipal.Identity.Name);
Debug.WriteLine(" RCID: {0}", CallContext.LogicalGetData("rcid"));
return new HttpResponseMessage(HttpStatusCode.Created);
}
catch (Exception e)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, e);
}
}
}
在使用 Fiddler 运行测试后,这是我收到的输出:
Dummy Handler Thread: 63
User: dgdev
RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
Another Dummy Handler Thread: 63
User: dgdev
RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
Thread: 63
User: dgdev
RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
Thread: 77
User: <<< PRINCIPAL IS LOST AFTER ASYNC
RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
Another Dummy Handler Thread: 63
User: <<< PRINCIPAL IS STILL LOST
RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
Dummy Handler Thread: 65
User: dgdev <<< PRINCIPAL IS BACK?!?
RCID: 6d542847-4ceb-4511-85e5-d1b5bf3be476
为了让事情更困惑,当我将以下内容附加到异步行时:
await Request.Content.ReadAsMultipartAsync(
new MultipartFormDataStreamProvider(..same as before..))
.ConfigureAwait(false); <<<<<<
我现在收到这个输出:
Dummy Handler Thread: 40
User: dgdev
RCID: 8d944500-cb52-4362-8537-dab405fa12a2
Another Dummy Handler Thread: 40
User: dgdev
RCID: 8d944500-cb52-4362-8537-dab405fa12a2
Thread: 40
User: dgdev
RCID: 8d944500-cb52-4362-8537-dab405fa12a2
Thread: 65
User: dgdev <<< PRINCIPAL IS HERE!
RCID: 8d944500-cb52-4362-8537-dab405fa12a2
Another Dummy Handler Thread: 65
User: <<< PRINCIPAL IS LOST
RCID: 8d944500-cb52-4362-8537-dab405fa12a2
Dummy Handler Thread: 40
User: dgdev
RCID: 8d944500-cb52-4362-8537-dab405fa12a2
这里的重点是。异步后面的代码实际上调用了我的业务逻辑,或者只需要正确设置安全上下文。存在潜在的完整性问题。
任何人都可以帮助阐明正在发生的事情吗?
提前致谢。
最佳答案
我没有所有的答案,但我可以帮助填空并猜测问题。
默认情况下,ASP.NET SynchronizationContext
会流动,但是 the way it flows identity is a bit weird .它实际上流向 HttpContext.Current.User
,然后将 Thread.CurrentPrincipal
设置为它。因此,如果您只是设置 Thread.CurrentPrincipal
,您将看不到它正确流动。
事实上,您会看到以下行为:
Thread.CurrentPrincipal
开始,该线程将拥有相同的主体,直到它重新进入 ASP.NET 上下文。Thread.CurrentPrincipal
被清除(因为它被设置为 HttpContext.Current.User
)。Thread.CurrentPrincipal
。将此应用于您的原始代码和输出:
CurrentPrincipal
后从线程 63 同步报告的,因此它们都具有预期值。async
方法,从而进入 ASP.NET 上下文并清除它可能拥有的任何 CurrentPrincipal
。ProcessResponse
。它重新进入 ASP.NET 上下文,清除其 Thread.CurrentPrincipal
。ContinueWith
中),因此它只保留它之前碰巧拥有的任何 CurrentPrincipal
。我假设它的 CurrentPrincipal
是早期测试运行遗留下来的。更新后的代码将 PostFile
更改为在 ASP.NET 上下文之外运行它的第二部分。所以它选择线程 65,它恰好设置了 CurrentPrincipal
。由于它在 ASP.NET 上下文之外,因此未清除 CurrentPrincipal
。
所以,在我看来,ExecutionContext
运行良好。我确定 Microsoft 已经测试了 ExecutionContext
流出了 wazoo;否则世界上的每个 ASP.NET 应用程序都会有严重的安全漏洞。需要注意的是,这段代码中的 Thread.CurrentPrincipal
只是指当前用户的声明,并不代表实际的模拟。
如果我的猜测是正确的,那么修复就非常简单:在 SendAsync
中,更改这一行:
Thread.CurrentPrincipal = new ClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new[]{ new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "dgdev") }, "myauthisthebest")));
为此:
HttpContext.Current.User = new ClaimsPrincipal(new ClaimsPrincipal(new ClaimsIdentity(new[]{ new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "dgdev") }, "myauthisthebest")));
Thread.CurrentPrincipal = HttpContext.Current.User;
关于c# - 使用 ASP.NET Web API,我的 ExecutionContext 不在异步操作中流动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15964244/
我有一个 .Net Framework 控制台应用程序,可以在 Azure 中成功将其发布为 WebJob 并查看它的运行情况。当我尝试向函数添加 ExecutionContext 参数时,我收到上述
我有以下测试用例: test("test future") { import scala.concurrent.ExecutionContext.global import scala
ExecutionContext 可用于函数参数。 但是,它不能通过依赖注入(inject)供其他方法使用,包括 Functions 的构造函数,如下所示: public class Func
ExecutionContext 可用于函数参数。 但是,它不能通过依赖注入(inject)供其他方法使用,包括 Functions 的构造函数,如下所示: public class Func
有人知道 ExecutionContext.Capture() 和 ExecutionContext.Run(context, work, state) 是否很昂贵吗? 它是否会降低性能,因此建议谨慎
我想知道哪个ExecutionContext我应该在 scalatest % 2.2.6 上使用(以及为什么)运行我的 future 并模拟 future 。 class Foo { def f
我一直在开发一个中小型 Web 应用程序,大约有 10 个端点。它应该可以同时处理数百个并发请求。 由于我公司的政策,我必须为我的 Controller 使用 javax.ws.rs,所以每个 Con
我有以下代码: object KafkaApi { private implicit val main: ExecutionContextExecutor = ExecutionContext.g
考虑以下代码: private static async Task Main(string[] args) { await SetValueInAsyncMethod(); Print
在每个方法中传递 ExecutionContext 是否更符合 Scala 习惯,例如 class Foo { def bar(a: Int, b: Int)(implicit ec: Exe
我试图发现 ExecutionContext实际上适用于 .NET Framework 4.0 及更高版本。文档说,在使用 Thread.Start 和大多数线程池操作时,托管原则、同步、区域设置和用
假设我想知道给定 ExecutionContext 中有多少个线程. 所以我正在写一个这样的函数 def count(implicit ec: ExecutionContext): Int = {
我知道,当您通过调用 BeginInvoke() 或 ThreadPool.QueueUserWorkItem(...) 并行运行某些方法时,.NET 框架正在捕获包含代码访问安全信息和其他一些内容的
在 scala 中使用 future 时,默认行为是使用默认的 Implicits.global 执行上下文。看来这默认为每个处理器提供一个可用线程。在更传统的线程 Web 应用程序中,当 futur
我有一个 Spring 批处理作业,它使用如下 Web 参数执行: https://localhost:8443/batch/async/orz003A?id=123&name=test 我已将这些参
我希望将隐式 ExecutionContext 传递给部分实现的特征。 在代码示例中: import scala.concurrent.Future trait Processor[T,R] {
我正在使用 Scala 2.10 future 创建一个异步库。库的构造函数采用一系列实现特定特征的用户定义对象,然后库类上的方法将一些数据逐个发送到用户定义对象中。我希望用户提供ExecutionC
这是一个相当笼统的问题,但希望是一个合理的问题。什么时候ExecutionContext#reportFailure(Throwable)叫? Scala 标准库中似乎没有调用它。我想我也许应该在某些
当我制作 future ,或应用类似 onSuccess 的方法和 map ,我可以为它们指定 ExecutionContext 。 例如, val f = future { // code }
我有这两个错误: Error:(39, 20) Cannot find an implicit ExecutionContext. You might pass an (implicit ec: Ex
我是一名优秀的程序员,十分优秀!