WCF- iClientMessageInspector-后方的错误本金

发布于 2025-02-07 05:42:21 字数 1920 浏览 2 评论 0 原文

上下文

我有.NET Framework 4.6.1 WebAPI应用程序。该应用程序调用各种Web服务。因此,我已经实现了 iclientMessageInspector 以进行一些登录 WCF(SOAP)请求/答复。

但是

,在一段时间后,我意识到有些答复是在另一个校长下记录的,即校长A提出请求并收到答复,但响应却在校长B中记录下来。

以下是该实现的简化简约示例演示这个问题。

    public class MyClientMessageInspector : IClientMessageInspector
    {
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            var correlationState = new CorrelationState
            {
                Guid = Guid.NewGuid()
            };

            // Principal A
            Debug.WriteLine(Thread.CurrentPrincipal);

            // Guid: 2abf9a7b-dac2-4c0d-b38d-1cdfb95405a7
            Debug.WriteLine(correlationState.Guid);

            return correlationState;
        }

        public void AfterReceiveReply(ref Message reply, object correlationStateObject)
        {
            var correlationState = (CorrelationState) correlationStateObject;

            // Principal B - How come???
            Debug.WriteLine(Thread.CurrentPrincipal);            

            // Guid: 2abf9a7b-dac2-4c0d-b38d-1cdfb95405a7 (matches Guid from request)
            Debug.WriteLine(correlationState.Guid);
        }
    }

thread.currentprincipal httpcontext.currentuser 仅在 global.asax.asax.cs 中设置在 application_postauthenticaterequest

该应用程序大量使用异步/等待范式,几乎所有异步调用(包括Web服务的呼叫)随后是 .configureawait(false)。但是,我的理解是 thread.currentprincipal 是在线程之间流动的,无需使用 configureawait(false)。这似乎是正确的,因为我的所有其他日志都是在正确的主体下制作的,即使是在之后发生的那些日志。

问题

是否有解释,为什么 thread.currentprincipal eaterreceivereply 包含不​​同的主体?我知道如何解决这个问题 - 我可以在 beforesendrequest 之后发送主体 coloreLation> correlationState object。但是在这样做之前,我需要理解为什么我的代码的行为与预期的不同,以及是否有比解决方案更好的解决方案。

Context

I've got .NET Framework 4.6.1 WebApi application. This application calls various web services. Therefore I've made an implementation of IClientMessageInspector in order to do some logging
of WCF (SOAP) requests/replies.

Issue

However after some time I've realized that some replies are logged under a different principal, i.e. principal A makes a request and receives a reply and yet the response is logged under principal B.

Below is a simplified minimalistic example of the implementation just to demonstrate the issue.

    public class MyClientMessageInspector : IClientMessageInspector
    {
        public object BeforeSendRequest(ref Message request, IClientChannel channel)
        {
            var correlationState = new CorrelationState
            {
                Guid = Guid.NewGuid()
            };

            // Principal A
            Debug.WriteLine(Thread.CurrentPrincipal);

            // Guid: 2abf9a7b-dac2-4c0d-b38d-1cdfb95405a7
            Debug.WriteLine(correlationState.Guid);

            return correlationState;
        }

        public void AfterReceiveReply(ref Message reply, object correlationStateObject)
        {
            var correlationState = (CorrelationState) correlationStateObject;

            // Principal B - How come???
            Debug.WriteLine(Thread.CurrentPrincipal);            

            // Guid: 2abf9a7b-dac2-4c0d-b38d-1cdfb95405a7 (matches Guid from request)
            Debug.WriteLine(correlationState.Guid);
        }
    }

Both Thread.CurrentPrincipal and HttpContext.CurrentUser are only set in the Global.asax.cs in the Application_PostAuthenticateRequest event.

The application heavily utilizes async/await paradigm and almost every async call (including calls of the web services) is followed by .ConfigureAwait(false). However my understanding is that Thread.CurrentPrincipal is flowed between threads reagardless of the usage of ConfigureAwait(false). That seems to be true since all my other logs are made under a correct principal, even those that happen after AfterReceiveReply.

Question

Is there an explanation why Thread.CurrentPrincipal in AfterReceiveReply contains a different principal? I know how to workaround this issue - I could send the principal between BeforeSendRequest and AfterReceiveReply within the CorrelationState object. But before doing so I need to understand why my code behaves differently than expected and also if there is possibly a better solution than the workaround.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

半衬遮猫 2025-02-14 05:42:21

当您在使用螺纹池的应用程序上使用.configureawait(false)时,可以选择池中的任何线程以继续执行。其中一些线程可能与您的原始线程具有相同的上下文,而其他线程可能具有不同的上下文。一旦使用.configureawait(false),您就无法控制什么线程接管。

这里有一个更详细的描述:

上面的文章谈论使用.configureawait(false)。您曾经在呼叫堆栈中的任何位置拨打.phait()或。重要的是,只有当您的代码实际上在等待某件事时,才会发生这种情况。如果您的异步方法恰好具有他们需要继续的数据,他们将很乐意保留在其原始线程上,并且上下文变量将匹配。

同样,使用.configureawait(false)运行异步时,您可以从第一个线程发送到另一个线程,然后如果它是免费的,则返回到第一个线程,并且代码需要等待网络读取的内容。该线程池意味着您的线程数量有限,并且大多数涉及线程的操作实际上并没有旋转一个全新的螺纹。

一些进一步的阅读可能会有所帮助:

When you use .ConfigureAwait(false) on an application with a threadpool any of the threads in the pool might be chosen to continue execution. Some of those threads might have the same context as your originating thread, others might have different contexts. You have no control over what thread takes over once you use .ConfigureAwait(false).

There is a more detailed description of what's going on here: https://medium.com/rubrikkgroup/understanding-async-avoiding-deadlocks-e41f8f2c6f5d

The above article talks about using .Result and Task.Run, not .ConfigureAwait(false) however .ConfigureAwait(false) effectively does this behind the scenes anyway if you ever call a .wait() or .result on the call anywhere in your call stack. Importantly this only happens if your code is actually waiting for something. If your async methods happen to have the data they need to continue they will happily stay on their original thread and the context variables will match.

Also when running Async with .ConfigureAwait(false) you can be sent from your first thread to another thread, then back to your first thread if it's free and the code needed to wait for something like a network read. The threadpool means you have a limited number of threads that can be called on and most operations that involve threads don't actually spin up a completely new one.

Some further reading that might help:
https://devblogs.microsoft.com/dotnet/configureawait-faq/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文