e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
273 lines
11 KiB
C#
273 lines
11 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.ServiceModel.Dispatcher
|
|
{
|
|
using System;
|
|
using System.Reflection;
|
|
using System.Runtime.Diagnostics;
|
|
using System.ServiceModel.Diagnostics;
|
|
using System.ServiceModel.Diagnostics.Application;
|
|
using System.Globalization;
|
|
using System.Threading;
|
|
using System.Collections;
|
|
using System.Diagnostics;
|
|
using System.Security;
|
|
using System.Runtime;
|
|
|
|
class SyncMethodInvoker : IOperationInvoker
|
|
{
|
|
Type type;
|
|
string methodName;
|
|
MethodInfo method;
|
|
InvokeDelegate invokeDelegate;
|
|
int inputParameterCount;
|
|
int outputParameterCount;
|
|
|
|
public SyncMethodInvoker(MethodInfo method)
|
|
{
|
|
if (method == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("method"));
|
|
|
|
this.method = method;
|
|
}
|
|
|
|
public SyncMethodInvoker(Type type, string methodName)
|
|
{
|
|
if (type == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("type"));
|
|
|
|
if (methodName == null)
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("methodName"));
|
|
|
|
this.type = type;
|
|
this.methodName = methodName;
|
|
}
|
|
|
|
public bool IsSynchronous
|
|
{
|
|
get { return true; }
|
|
}
|
|
|
|
public MethodInfo Method
|
|
{
|
|
get
|
|
{
|
|
if (method == null)
|
|
method = type.GetMethod(methodName);
|
|
return method;
|
|
}
|
|
}
|
|
|
|
public string MethodName
|
|
{
|
|
get
|
|
{
|
|
if (methodName == null)
|
|
methodName = method.Name;
|
|
return methodName;
|
|
}
|
|
}
|
|
|
|
public object[] AllocateInputs()
|
|
{
|
|
EnsureIsInitialized();
|
|
|
|
return EmptyArray.Allocate(this.inputParameterCount);
|
|
}
|
|
|
|
public object Invoke(object instance, object[] inputs, out object[] outputs)
|
|
{
|
|
EnsureIsInitialized();
|
|
|
|
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)));
|
|
|
|
outputs = EmptyArray.Allocate(this.outputParameterCount);
|
|
|
|
long startCounter = 0;
|
|
long stopCounter = 0;
|
|
long beginOperation = 0;
|
|
bool callSucceeded = false;
|
|
bool callFaulted = false;
|
|
|
|
if (PerformanceCounters.PerformanceCountersEnabled)
|
|
{
|
|
PerformanceCounters.MethodCalled(this.MethodName);
|
|
try
|
|
{
|
|
if (System.ServiceModel.Channels.UnsafeNativeMethods.QueryPerformanceCounter(out startCounter) == 0)
|
|
{
|
|
startCounter = -1;
|
|
}
|
|
}
|
|
catch (SecurityException securityException)
|
|
{
|
|
DiagnosticUtility.TraceHandledException(securityException, TraceEventType.Warning);
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
|
|
new SecurityException(SR.GetString(
|
|
SR.PartialTrustPerformanceCountersNotEnabled), securityException));
|
|
}
|
|
}
|
|
|
|
EventTraceActivity eventTraceActivity = null;
|
|
if (TD.OperationCompletedIsEnabled() ||
|
|
TD.OperationFaultedIsEnabled() ||
|
|
TD.OperationFailedIsEnabled())
|
|
{
|
|
beginOperation = DateTime.UtcNow.Ticks;
|
|
OperationContext context = OperationContext.Current;
|
|
if (context != null && context.IncomingMessage != null)
|
|
{
|
|
eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(context.IncomingMessage);
|
|
}
|
|
}
|
|
|
|
object returnValue;
|
|
try
|
|
{
|
|
ServiceModelActivity activity = null;
|
|
IDisposable boundActivity = null;
|
|
if (DiagnosticUtility.ShouldUseActivity)
|
|
{
|
|
activity = ServiceModelActivity.CreateBoundedActivity(true);
|
|
boundActivity = activity;
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
using (boundActivity)
|
|
{
|
|
if (DiagnosticUtility.ShouldUseActivity)
|
|
{
|
|
ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityExecuteMethod, this.method.DeclaringType.FullName, this.method.Name), ActivityType.ExecuteUserCode);
|
|
}
|
|
if (TD.OperationInvokedIsEnabled())
|
|
{
|
|
TD.OperationInvoked(eventTraceActivity, this.MethodName, TraceUtility.GetCallerInfo(OperationContext.Current));
|
|
}
|
|
returnValue = this.invokeDelegate(instance, inputs, outputs);
|
|
callSucceeded = true;
|
|
}
|
|
}
|
|
catch (System.ServiceModel.FaultException)
|
|
{
|
|
callFaulted = true;
|
|
throw;
|
|
}
|
|
catch (System.Security.SecurityException e)
|
|
{
|
|
DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException());
|
|
}
|
|
finally
|
|
{
|
|
if (PerformanceCounters.PerformanceCountersEnabled)
|
|
{
|
|
long elapsedTime = 0;
|
|
if (startCounter >= 0 && System.ServiceModel.Channels.UnsafeNativeMethods.QueryPerformanceCounter(out stopCounter) != 0)
|
|
{
|
|
elapsedTime = stopCounter - startCounter;
|
|
}
|
|
|
|
if (callSucceeded) // call succeeded
|
|
{
|
|
PerformanceCounters.MethodReturnedSuccess(this.MethodName, elapsedTime);
|
|
}
|
|
else if (callFaulted) // call faulted
|
|
{
|
|
PerformanceCounters.MethodReturnedFault(this.MethodName, elapsedTime);
|
|
}
|
|
else // call failed
|
|
{
|
|
PerformanceCounters.MethodReturnedError(this.MethodName, elapsedTime);
|
|
}
|
|
}
|
|
|
|
if (beginOperation != 0)
|
|
{
|
|
if (callSucceeded)
|
|
{
|
|
if (TD.OperationCompletedIsEnabled())
|
|
{
|
|
TD.OperationCompleted(eventTraceActivity, this.methodName,
|
|
TraceUtility.GetUtcBasedDurationForTrace(beginOperation));
|
|
}
|
|
}
|
|
else if (callFaulted)
|
|
{
|
|
if (TD.OperationFaultedIsEnabled())
|
|
{
|
|
TD.OperationFaulted(eventTraceActivity, this.methodName,
|
|
TraceUtility.GetUtcBasedDurationForTrace(beginOperation));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (TD.OperationFailedIsEnabled())
|
|
{
|
|
TD.OperationFailed(eventTraceActivity, this.methodName,
|
|
TraceUtility.GetUtcBasedDurationForTrace(beginOperation));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
|
|
public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
|
|
}
|
|
|
|
void EnsureIsInitialized()
|
|
{
|
|
if (this.invokeDelegate == null)
|
|
{
|
|
EnsureIsInitializedCore();
|
|
}
|
|
}
|
|
|
|
void EnsureIsInitializedCore()
|
|
{
|
|
// 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;
|
|
int outputParameterCount;
|
|
InvokeDelegate invokeDelegate = new InvokerUtil().GenerateInvokeDelegate(this.Method, out inputParameterCount, out outputParameterCount);
|
|
this.outputParameterCount = outputParameterCount;
|
|
this.inputParameterCount = inputParameterCount;
|
|
this.invokeDelegate = invokeDelegate; // must set this last due to ----
|
|
}
|
|
}
|
|
}
|