[coop] Temporarily restore MonoThreadInfo when TLS destructor runs. Fixes #43099
[mono.git] / mcs / class / referencesource / System.ServiceModel / System / ServiceModel / OperationContextScope.cs
1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4
5 namespace System.ServiceModel
6 {
7     using System;
8     using System.ServiceModel.Channels;
9     using System.Threading;
10
11     public sealed class OperationContextScope : IDisposable
12     {
13         [ThreadStatic]
14         static OperationContextScope currentScope;
15
16         OperationContext currentContext;
17         bool disposed;
18         readonly OperationContext originalContext = OperationContext.Current;
19         readonly OperationContextScope originalScope = OperationContextScope.currentScope;
20         readonly Thread thread = Thread.CurrentThread;
21
22         public OperationContextScope(IContextChannel channel)
23         {
24             this.PushContext(new OperationContext(channel));
25         }
26
27         public OperationContextScope(OperationContext context)
28         {
29             this.PushContext(context);
30         }
31
32         public void Dispose()
33         {
34             if (!this.disposed)
35             {
36                 this.disposed = true;
37                 this.PopContext();
38             }
39         }
40
41         void PushContext(OperationContext context)
42         {
43             this.currentContext = context;
44             OperationContextScope.currentScope = this;
45             OperationContext.Current = this.currentContext;
46         }
47
48         void PopContext()
49         {
50             if (this.thread != Thread.CurrentThread)
51                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInvalidContextScopeThread0)));
52
53             if (OperationContextScope.currentScope != this)
54                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInterleavedContextScopes0)));
55
56             if (OperationContext.Current != this.currentContext)
57                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxContextModifiedInsideScope0)));
58
59             OperationContextScope.currentScope = this.originalScope;
60             OperationContext.Current = this.originalContext;
61
62             if (this.currentContext != null)
63                 this.currentContext.SetClientReply(null, false);
64         }
65     }
66 }
67