|
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Dispatcher
{
using System;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.Diagnostics;
using System.Security;
using System.ServiceModel.Description;
using System.ServiceModel.Diagnostics;
using System.ServiceModel.Diagnostics.Application;
using System.Runtime;
class AsyncMethodInvoker : IOperationInvoker
{
MethodInfo beginMethod;
MethodInfo endMethod;
InvokeBeginDelegate invokeBeginDelegate;
InvokeEndDelegate invokeEndDelegate;
int inputParameterCount;
int outputParameterCount;
public AsyncMethodInvoker(MethodInfo beginMethod, MethodInfo endMethod)
{
if (beginMethod == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("beginMethod"));
if (endMethod == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("endMethod"));
this.beginMethod = beginMethod;
this.endMethod = endMethod;
}
public MethodInfo BeginMethod
{
get { return this.beginMethod; }
}
public MethodInfo EndMethod
{
get { return this.endMethod; }
}
public bool IsSynchronous
{
get { return false; }
}
public object[] AllocateInputs()
{
return EmptyArray.Allocate(this.InputParameterCount);
}
public object Invoke(object instance, object[] inputs, out object[] outputs)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
}
internal static void CreateActivityInfo(ref ServiceModelActivity activity, ref Activity boundActivity)
{
if (DiagnosticUtility.ShouldUseActivity)
{
activity = ServiceModelActivity.CreateAsyncActivity();
TraceUtility.UpdateAsyncOperationContextWithActivity(activity);
boundActivity = ServiceModelActivity.BoundOperation(activity, true);
}
else if (TraceUtility.MessageFlowTracingOnly)
{
Guid activityId = TraceUtility.GetReceivedActivityId(OperationContext.Current);
if (activityId != Guid.Empty)
{
DiagnosticTraceBase.ActivityId = activityId;
}
}
else if (TraceUtility.ShouldPropagateActivity)
{
//Message flow tracing only scenarios use a light-weight ActivityID management logic
Guid activityId = ActivityIdHeader.ExtractActivityId(OperationContext.Current.IncomingMessage);
if (activityId != Guid.Empty)
{
boundActivity = Activity.CreateActivity(activityId);
}
TraceUtility.UpdateAsyncOperationContextWithActivity(activityId);
}
}
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
if (instance == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNoServiceObject)));
if (inputs == null)
{
if (this.InputParameterCount > 0)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceNull, this.InputParameterCount)));
}
else if (inputs.Length != this.InputParameterCount)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceInvalid, this.InputParameterCount, inputs.Length)));
StartOperationInvokePerformanceCounters(this.beginMethod.Name.Substring(ServiceReflector.BeginMethodNamePrefix.Length));
IAsyncResult returnValue;
bool callFailed = true;
bool callFaulted = false;
ServiceModelActivity activity = null;
try
{
Activity boundActivity = null;
CreateActivityInfo(ref activity, ref boundActivity);
StartOperationInvokeTrace(this.beginMethod.Name);
using (boundActivity)
{
if (DiagnosticUtility.ShouldUseActivity)
{
string activityName = null;
if (this.endMethod == null)
{
activityName = SR.GetString(SR.ActivityExecuteMethod,
this.beginMethod.DeclaringType.FullName, this.beginMethod.Name);
}
else
{
activityName = SR.GetString(SR.ActivityExecuteAsyncMethod,
this.beginMethod.DeclaringType.FullName, this.beginMethod.Name,
this.endMethod.DeclaringType.FullName, this.endMethod.Name);
}
ServiceModelActivity.Start(activity, activityName, ActivityType.ExecuteUserCode);
}
returnValue = this.InvokeBeginDelegate(instance, inputs, callback, state);
callFailed = false;
}
}
catch (System.Security.SecurityException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException());
}
catch (Exception e)
{
TraceUtility.TraceUserCodeException(e, this.beginMethod);
if (e is FaultException)
{
callFaulted = true;
callFailed = false;
}
throw;
}
finally
{
ServiceModelActivity.Stop(activity);
// An exception during the InvokeBegin will not call InvokeEnd,
// so we complete the trace and performance counters here.
if (callFailed || callFaulted)
{
StopOperationInvokeTrace(callFailed, callFaulted, this.EndMethod.Name);
StopOperationInvokePerformanceCounters(callFailed, callFaulted, endMethod.Name.Substring(ServiceReflector.EndMethodNamePrefix.Length));
}
}
return returnValue;
}
internal static void GetActivityInfo(ref ServiceModelActivity activity, ref Activity boundOperation)
{
if (TraceUtility.MessageFlowTracingOnly)
{
if (null != OperationContext.Current)
{
Guid activityId = TraceUtility.GetReceivedActivityId(OperationContext.Current);
if (activityId != Guid.Empty)
{
DiagnosticTraceBase.ActivityId = activityId;
}
}
}
else if (DiagnosticUtility.ShouldUseActivity || TraceUtility.ShouldPropagateActivity)
{
object activityInfo = TraceUtility.ExtractAsyncOperationContextActivity();
if (activityInfo != null)
{
if (DiagnosticUtility.ShouldUseActivity)
{
activity = activityInfo as ServiceModelActivity;
boundOperation = ServiceModelActivity.BoundOperation(activity, true);
}
else if (TraceUtility.ShouldPropagateActivity)
{
if (activityInfo is Guid)
{
Guid activityId = (Guid)activityInfo;
boundOperation = Activity.CreateActivity(activityId);
}
}
}
}
}
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
object returnVal;
if (instance == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNoServiceObject)));
outputs = EmptyArray.Allocate(this.OutputParameterCount);
bool callFailed = true;
bool callFaulted = false;
ServiceModelActivity activity = null;
try
{
Activity boundOperation = null;
GetActivityInfo(ref activity, ref boundOperation);
using (boundOperation)
{
returnVal = this.InvokeEndDelegate(instance, outputs, result);
callFailed = false;
}
}
catch (SecurityException e)
{
DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException());
}
catch (FaultException)
{
callFaulted = true;
callFailed = false;
throw;
}
finally
{
ServiceModelActivity.Stop(activity);
StopOperationInvokeTrace(callFailed, callFaulted, this.endMethod.Name);
StopOperationInvokePerformanceCounters(callFailed, callFaulted, this.endMethod.Name.Substring(ServiceReflector.EndMethodNamePrefix.Length));
}
return returnVal;
}
internal static void StartOperationInvokeTrace(string methodName)
{
if (TD.OperationInvokedIsEnabled())
{
OperationContext context = OperationContext.Current;
EventTraceActivity eventTraceActivity = null;
if (context != null && context.IncomingMessage != null)
{
eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(context.IncomingMessage);
}
if (TD.OperationInvokedIsEnabled())
{
TD.OperationInvoked(eventTraceActivity, methodName, TraceUtility.GetCallerInfo(OperationContext.Current));
}
if (TD.OperationCompletedIsEnabled() || TD.OperationFaultedIsEnabled() || TD.OperationFailedIsEnabled())
{
TraceUtility.UpdateAsyncOperationContextWithStartTime(eventTraceActivity, DateTime.UtcNow.Ticks);
}
}
}
internal static void StopOperationInvokeTrace(bool callFailed, bool callFaulted, string methodName)
{
if (!(TD.OperationCompletedIsEnabled() ||
TD.OperationFaultedIsEnabled() ||
TD.OperationFailedIsEnabled()))
{
return;
}
EventTraceActivity eventTraceActivity;
long startTime;
TraceUtility.ExtractAsyncOperationStartTime(out eventTraceActivity, out startTime);
long duration = TraceUtility.GetUtcBasedDurationForTrace(startTime);
if (callFailed)
{
if (TD.OperationFailedIsEnabled())
{
TD.OperationFailed(eventTraceActivity, methodName, duration);
}
}
else if (callFaulted)
{
if (TD.OperationFaultedIsEnabled())
{
TD.OperationFaulted(eventTraceActivity, methodName, duration);
}
}
else
{
if (TD.OperationCompletedIsEnabled())
{
TD.OperationCompleted(eventTraceActivity, methodName, duration);
}
}
}
internal static void StartOperationInvokePerformanceCounters(string methodName)
{
if (PerformanceCounters.PerformanceCountersEnabled)
{
PerformanceCounters.MethodCalled(methodName);
}
}
internal static void StopOperationInvokePerformanceCounters(bool callFailed, bool callFaulted, string methodName)
{
if (PerformanceCounters.PerformanceCountersEnabled)
{
if (callFailed)
{
PerformanceCounters.MethodReturnedError(methodName);
}
else if (callFaulted)
{
PerformanceCounters.MethodReturnedFault(methodName);
}
else
{
PerformanceCounters.MethodReturnedSuccess(methodName);
}
}
}
InvokeBeginDelegate InvokeBeginDelegate
{
get
{
EnsureIsInitialized();
return invokeBeginDelegate;
}
}
InvokeEndDelegate InvokeEndDelegate
{
get
{
EnsureIsInitialized();
return invokeEndDelegate;
}
}
int InputParameterCount
{
get
{
EnsureIsInitialized();
return this.inputParameterCount;
}
}
int OutputParameterCount
{
get
{
EnsureIsInitialized();
return this.outputParameterCount;
}
}
void EnsureIsInitialized()
{
if (this.invokeBeginDelegate == null)
{
// Only pass locals byref because InvokerUtil may store temporary results in the byref.
// If two threads both reference this.count, temporary results may interact.
int inputParameterCount;
InvokeBeginDelegate invokeBeginDelegate = new InvokerUtil().GenerateInvokeBeginDelegate(this.beginMethod, out inputParameterCount);
this.inputParameterCount = inputParameterCount;
int outputParameterCount;
InvokeEndDelegate invokeEndDelegate = new InvokerUtil().GenerateInvokeEndDelegate(this.endMethod, out outputParameterCount);
this.outputParameterCount = outputParameterCount;
this.invokeEndDelegate = invokeEndDelegate;
this.invokeBeginDelegate = invokeBeginDelegate; // must set this last due to ----
}
}
}
}
|