-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathServiceAHost.cs
110 lines (94 loc) · 2.62 KB
/
ServiceAHost.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
using System;
using System.ServiceModel;
using System.Threading.Tasks;
using System.ServiceModel.Channels;
using System.Reflection;
namespace DotNet462WcfAsyncFlowBug.Host
{
[ServiceContract]
interface IServiceA
{
[OperationContract]
Task<string> Foo();
}
class ServiceA : IServiceA
{
public async Task<string> Foo()
{
var client = new Client.ServiceBClient();
var result1 = await ServiceCallWithHeader(client, "1");
var result2 = await ServiceCallWithHeader(client, "2");
return $"{result1} and {result2}";
}
private async Task<string> ServiceCallWithHeader(Client.ServiceBClient client, string headerValue)
{
// We can avoid this issue by disabling the new async flow logic in .Net Framework 4.6.2 via an
// internal static method.
//
//typeof(OperationContext)
// .GetMethod("DisableAsyncFlow", BindingFlags.Static | BindingFlags.NonPublic)
// .Invoke(null, null);
try
{
// Pattern for the code below directed by the MSDN article for the OperationContextScope:
// https://msdn.microsoft.com/en-us/library/system.servicemodel.operationcontextscope(v=vs.110).aspx
Task<string> task = null;
using (new OperationContextScope(client.InnerChannel))
{
AddAuthorizationHeader(headerValue);
task = client.BarAsync();
}
return await task;
// The first implicit call to OperationContextScope's Dispose method will leave the scope 'stack'
// in a bad state. The second call will throw the exception we catch below.
}
catch (InvalidOperationException e)
{
// Place breakpoint here to inspect the exception generated by the second call to
// OperationContextScope's Dispose method.
throw;
}
}
private static void AddAuthorizationHeader(string headerValue)
{
var header = MessageHeader.CreateHeader("Authorization", String.Empty, headerValue);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
}
}
class ServiceAHost : IDisposable
{
private ServiceHost host;
private bool disposed;
public ServiceAHost()
{
InitializeServiceHost();
SetEndpoint();
host.Open();
}
private void InitializeServiceHost()
{
var serviceType = typeof(ServiceA);
host = new ServiceHost(serviceType, Addresses.ServiceAUri);
}
private void SetEndpoint()
{
host.AddServiceEndpoint(typeof(IServiceA), new WSHttpBinding(), String.Empty);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposed)
return;
if (disposing)
{
host.Close();
((IDisposable)host).Dispose();
}
disposed = true;
}
}
}