|
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Diagnostics;
using System.ServiceModel.Diagnostics.Application;
using System.Transactions;
class ImmutableClientRuntime
{
int correlationCount;
bool addTransactionFlowProperties;
IInteractiveChannelInitializer[] interactiveChannelInitializers;
IClientOperationSelector operationSelector;
IChannelInitializer[] channelInitializers;
IClientMessageInspector[] messageInspectors;
Dictionary<string, ProxyOperationRuntime> operations;
ProxyOperationRuntime unhandled;
bool useSynchronizationContext;
bool validateMustUnderstand;
internal ImmutableClientRuntime(ClientRuntime behavior)
{
this.channelInitializers = EmptyArray<IChannelInitializer>.ToArray(behavior.ChannelInitializers);
this.interactiveChannelInitializers = EmptyArray<IInteractiveChannelInitializer>.ToArray(behavior.InteractiveChannelInitializers);
this.messageInspectors = EmptyArray<IClientMessageInspector>.ToArray(behavior.MessageInspectors);
this.operationSelector = behavior.OperationSelector;
this.useSynchronizationContext = behavior.UseSynchronizationContext;
this.validateMustUnderstand = behavior.ValidateMustUnderstand;
this.unhandled = new ProxyOperationRuntime(behavior.UnhandledClientOperation, this);
this.addTransactionFlowProperties = behavior.AddTransactionFlowProperties;
this.operations = new Dictionary<string, ProxyOperationRuntime>();
for (int i = 0; i < behavior.Operations.Count; i++)
{
ClientOperation operation = behavior.Operations[i];
ProxyOperationRuntime operationRuntime = new ProxyOperationRuntime(operation, this);
this.operations.Add(operation.Name, operationRuntime);
}
this.correlationCount = this.messageInspectors.Length + behavior.MaxParameterInspectors;
}
internal int MessageInspectorCorrelationOffset
{
get { return 0; }
}
internal int ParameterInspectorCorrelationOffset
{
get { return this.messageInspectors.Length; }
}
internal int CorrelationCount
{
get { return this.correlationCount; }
}
internal IClientOperationSelector OperationSelector
{
get { return this.operationSelector; }
}
internal ProxyOperationRuntime UnhandledProxyOperation
{
get { return this.unhandled; }
}
internal bool UseSynchronizationContext
{
get { return this.useSynchronizationContext; }
}
internal bool ValidateMustUnderstand
{
get { return validateMustUnderstand; }
set { validateMustUnderstand = value; }
}
internal void AfterReceiveReply(ref ProxyRpc rpc)
{
int offset = this.MessageInspectorCorrelationOffset;
bool outputTiming = DS.MessageInspectorIsEnabled();
Stopwatch sw = null;
if (outputTiming)
{
sw = new Stopwatch();
}
try
{
for (int i = 0; i < this.messageInspectors.Length; i++)
{
if (outputTiming)
{
sw.Restart();
}
this.messageInspectors[i].AfterReceiveReply(ref rpc.Reply, rpc.Correlation[offset + i]);
if (outputTiming)
{
DS.ClientMessageInspectorAfterReceive(this.messageInspectors[i].GetType(), sw.Elapsed);
}
if (TD.ClientMessageInspectorAfterReceiveInvokedIsEnabled())
{
TD.ClientMessageInspectorAfterReceiveInvoked(rpc.EventTraceActivity, this.messageInspectors[i].GetType().FullName);
}
}
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e))
{
throw;
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
}
}
internal void BeforeSendRequest(ref ProxyRpc rpc)
{
int offset = this.MessageInspectorCorrelationOffset;
try
{
bool outputTiming = DS.MessageInspectorIsEnabled();
Stopwatch sw = null;
if (outputTiming)
{
sw = new Stopwatch();
}
for (int i = 0; i < this.messageInspectors.Length; i++)
{
if (outputTiming)
{
sw.Restart();
}
rpc.Correlation[offset + i] = this.messageInspectors[i].BeforeSendRequest(ref rpc.Request, (IClientChannel)rpc.Channel.Proxy);
if (outputTiming)
{
DS.ClientMessageInspectorBeforeSend(this.messageInspectors[i].GetType(), sw.Elapsed);
}
if (TD.ClientMessageInspectorBeforeSendInvokedIsEnabled())
{
TD.ClientMessageInspectorBeforeSendInvoked(rpc.EventTraceActivity, this.messageInspectors[i].GetType().FullName);
}
}
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e))
{
throw;
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
}
if (this.addTransactionFlowProperties)
{
SendTransaction(ref rpc);
}
}
internal void DisplayInitializationUI(ServiceChannel channel)
{
EndDisplayInitializationUI(BeginDisplayInitializationUI(channel, null, null));
}
internal IAsyncResult BeginDisplayInitializationUI(ServiceChannel channel, AsyncCallback callback, object state)
{
return new DisplayInitializationUIAsyncResult(channel, this.interactiveChannelInitializers, callback, state);
}
internal void EndDisplayInitializationUI(IAsyncResult result)
{
DisplayInitializationUIAsyncResult.End(result);
}
// this should not be inlined, since we want to JIT the reference to System.Transactions
// only if transactions are being flowed.
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
static void SendTransaction(ref ProxyRpc rpc)
{
System.ServiceModel.Channels.TransactionFlowProperty.Set(Transaction.Current, rpc.Request);
}
internal void InitializeChannel(IClientChannel channel)
{
try
{
for (int i = 0; i < this.channelInitializers.Length; ++i)
{
this.channelInitializers[i].Initialize(channel);
}
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e))
{
throw;
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
}
}
internal ProxyOperationRuntime GetOperation(MethodBase methodBase, object[] args, out bool canCacheResult)
{
if (this.operationSelector == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException
(SR.GetString(SR.SFxNeedProxyBehaviorOperationSelector2,
methodBase.Name,
methodBase.DeclaringType.Name)));
}
try
{
if (operationSelector.AreParametersRequiredForSelection)
{
canCacheResult = false;
}
else
{
args = null;
canCacheResult = true;
}
bool outputTiming = DS.OperationSelectorIsEnabled();
Stopwatch sw = null;
if (outputTiming)
{
sw = Stopwatch.StartNew();
}
string operationName = operationSelector.SelectOperation(methodBase, args);
if (outputTiming)
{
DS.ClientSelectOperation(operationSelector.GetType(), operationName, sw.Elapsed);
}
ProxyOperationRuntime operation;
if ((operationName != null) && this.operations.TryGetValue(operationName, out operation))
{
return operation;
}
else
{
// did not find the right operation, will not know how
// to invoke the method.
return null;
}
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
if (ErrorBehavior.ShouldRethrowClientSideExceptionAsIs(e))
{
throw;
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperCallback(e);
}
}
internal ProxyOperationRuntime GetOperationByName(string operationName)
{
ProxyOperationRuntime operation = null;
if (this.operations.TryGetValue(operationName, out operation))
return operation;
else
return null;
}
class DisplayInitializationUIAsyncResult : System.Runtime.AsyncResult
{
ServiceChannel channel;
int index = -1;
IInteractiveChannelInitializer[] initializers;
IClientChannel proxy;
static AsyncCallback callback = Fx.ThunkCallback(new AsyncCallback(DisplayInitializationUIAsyncResult.Callback));
internal DisplayInitializationUIAsyncResult(ServiceChannel channel,
IInteractiveChannelInitializer[] initializers,
AsyncCallback callback, object state)
: base(callback, state)
{
this.channel = channel;
this.initializers = initializers;
this.proxy = channel.Proxy as IClientChannel;
this.CallBegin(true);
}
void CallBegin(bool completedSynchronously)
{
while (++this.index < initializers.Length)
{
IAsyncResult result = null;
Exception exception = null;
try
{
result = this.initializers[this.index].BeginDisplayInitializationUI(
this.proxy,
DisplayInitializationUIAsyncResult.callback,
this
);
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
exception = e;
}
if (exception == null)
{
if (!result.CompletedSynchronously)
{
return;
}
this.CallEnd(result, out exception);
}
if (exception != null)
{
this.CallComplete(completedSynchronously, exception);
return;
}
}
this.CallComplete(completedSynchronously, null);
}
static void Callback(IAsyncResult result)
{
if (result.CompletedSynchronously)
{
return;
}
DisplayInitializationUIAsyncResult outer = (DisplayInitializationUIAsyncResult)result.AsyncState;
Exception exception = null;
outer.CallEnd(result, out exception);
if (exception != null)
{
outer.CallComplete(false, exception);
return;
}
outer.CallBegin(false);
}
void CallEnd(IAsyncResult result, out Exception exception)
{
try
{
this.initializers[this.index].EndDisplayInitializationUI(result);
exception = null;
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
exception = e;
}
}
void CallComplete(bool completedSynchronously, Exception exception)
{
this.Complete(completedSynchronously, exception);
}
internal static void End(IAsyncResult result)
{
System.Runtime.AsyncResult.End<DisplayInitializationUIAsyncResult>(result);
}
}
}
}
|