File: System\ServiceModel\Dispatcher\SyncMethodInvoker.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//-----------------------------------------------------------------------------
// 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 ----
        }
    }
}