1 //-----------------------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //-----------------------------------------------------------------------------
4 
5 namespace System.ServiceModel.Dispatcher
6 {
7     using System;
8     using System.Reflection;
9     using System.Runtime.Diagnostics;
10     using System.ServiceModel.Diagnostics;
11     using System.ServiceModel.Diagnostics.Application;
12     using System.Globalization;
13     using System.Threading;
14     using System.Collections;
15     using System.Diagnostics;
16     using System.Security;
17     using System.Runtime;
18 
19     class SyncMethodInvoker : IOperationInvoker
20     {
21         Type type;
22         string methodName;
23         MethodInfo method;
24         InvokeDelegate invokeDelegate;
25         int inputParameterCount;
26         int outputParameterCount;
27 
SyncMethodInvoker(MethodInfo method)28         public SyncMethodInvoker(MethodInfo method)
29         {
30             if (method == null)
31                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("method"));
32 
33             this.method = method;
34         }
35 
SyncMethodInvoker(Type type, string methodName)36         public SyncMethodInvoker(Type type, string methodName)
37         {
38             if (type == null)
39                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("type"));
40 
41             if (methodName == null)
42                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("methodName"));
43 
44             this.type = type;
45             this.methodName = methodName;
46         }
47 
48         public bool IsSynchronous
49         {
50             get { return true; }
51         }
52 
53         public MethodInfo Method
54         {
55             get
56             {
57                 if (method == null)
58                     method = type.GetMethod(methodName);
59                 return method;
60             }
61         }
62 
63         public string MethodName
64         {
65             get
66             {
67                 if (methodName == null)
68                     methodName = method.Name;
69                 return methodName;
70             }
71         }
72 
AllocateInputs()73         public object[] AllocateInputs()
74         {
75             EnsureIsInitialized();
76 
77             return EmptyArray.Allocate(this.inputParameterCount);
78         }
79 
Invoke(object instance, object[] inputs, out object[] outputs)80         public object Invoke(object instance, object[] inputs, out object[] outputs)
81         {
82             EnsureIsInitialized();
83 
84             if (instance == null)
85                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxNoServiceObject)));
86             if (inputs == null)
87             {
88                 if (this.inputParameterCount > 0)
89                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceNull, this.inputParameterCount)));
90             }
91             else if (inputs.Length != this.inputParameterCount)
92                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxInputParametersToServiceInvalid, this.inputParameterCount, inputs.Length)));
93 
94             outputs = EmptyArray.Allocate(this.outputParameterCount);
95 
96             long startCounter = 0;
97             long stopCounter = 0;
98             long beginOperation = 0;
99             bool callSucceeded = false;
100             bool callFaulted = false;
101 
102             if (PerformanceCounters.PerformanceCountersEnabled)
103             {
104                 PerformanceCounters.MethodCalled(this.MethodName);
105                 try
106                 {
107                     if (System.ServiceModel.Channels.UnsafeNativeMethods.QueryPerformanceCounter(out startCounter) == 0)
108                     {
109                         startCounter = -1;
110                     }
111                 }
112                 catch (SecurityException securityException)
113                 {
114                     DiagnosticUtility.TraceHandledException(securityException, TraceEventType.Warning);
115                     throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
116                         new SecurityException(SR.GetString(
117                                 SR.PartialTrustPerformanceCountersNotEnabled), securityException));
118                 }
119             }
120 
121             EventTraceActivity eventTraceActivity = null;
122             if (TD.OperationCompletedIsEnabled() ||
123                     TD.OperationFaultedIsEnabled() ||
124                     TD.OperationFailedIsEnabled())
125             {
126                 beginOperation = DateTime.UtcNow.Ticks;
127                 OperationContext context = OperationContext.Current;
128                 if (context != null && context.IncomingMessage != null)
129                 {
130                     eventTraceActivity = EventTraceActivityHelper.TryExtractActivity(context.IncomingMessage);
131                 }
132             }
133 
134             object returnValue;
135             try
136             {
137                 ServiceModelActivity activity = null;
138                 IDisposable boundActivity = null;
139                 if (DiagnosticUtility.ShouldUseActivity)
140                 {
141                     activity = ServiceModelActivity.CreateBoundedActivity(true);
142                     boundActivity = activity;
143                 }
144                 else if (TraceUtility.MessageFlowTracingOnly)
145                 {
146                     Guid activityId = TraceUtility.GetReceivedActivityId(OperationContext.Current);
147                     if (activityId != Guid.Empty)
148                     {
149                         DiagnosticTraceBase.ActivityId = activityId;
150                     }
151                 }
152                 else if (TraceUtility.ShouldPropagateActivity)
153                 {
154                     //Message flow tracing only scenarios use a light-weight ActivityID management logic
155                     Guid activityId = ActivityIdHeader.ExtractActivityId(OperationContext.Current.IncomingMessage);
156                     if (activityId != Guid.Empty)
157                     {
158                         boundActivity = Activity.CreateActivity(activityId);
159                     }
160                 }
161 
162                 using (boundActivity)
163                 {
164                     if (DiagnosticUtility.ShouldUseActivity)
165                     {
166                         ServiceModelActivity.Start(activity, SR.GetString(SR.ActivityExecuteMethod, this.method.DeclaringType.FullName, this.method.Name), ActivityType.ExecuteUserCode);
167                     }
168                     if (TD.OperationInvokedIsEnabled())
169                     {
170                         TD.OperationInvoked(eventTraceActivity, this.MethodName, TraceUtility.GetCallerInfo(OperationContext.Current));
171                     }
172                     returnValue = this.invokeDelegate(instance, inputs, outputs);
173                     callSucceeded = true;
174                 }
175             }
176             catch (System.ServiceModel.FaultException)
177             {
178                 callFaulted = true;
179                 throw;
180             }
181             catch (System.Security.SecurityException e)
182             {
183                 DiagnosticUtility.TraceHandledException(e, TraceEventType.Warning);
184                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(AuthorizationBehavior.CreateAccessDeniedFaultException());
185             }
186             finally
187             {
188                 if (PerformanceCounters.PerformanceCountersEnabled)
189                 {
190                     long elapsedTime = 0;
191                     if (startCounter >= 0 && System.ServiceModel.Channels.UnsafeNativeMethods.QueryPerformanceCounter(out stopCounter) != 0)
192                     {
193                         elapsedTime = stopCounter - startCounter;
194                     }
195 
196                     if (callSucceeded) // call succeeded
197                     {
198                         PerformanceCounters.MethodReturnedSuccess(this.MethodName, elapsedTime);
199                     }
200                     else if (callFaulted) // call faulted
201                     {
202                         PerformanceCounters.MethodReturnedFault(this.MethodName, elapsedTime);
203                     }
204                     else // call failed
205                     {
206                         PerformanceCounters.MethodReturnedError(this.MethodName, elapsedTime);
207                     }
208                 }
209 
210                 if (beginOperation != 0)
211                 {
212                     if (callSucceeded)
213                     {
214                         if (TD.OperationCompletedIsEnabled())
215                         {
216                             TD.OperationCompleted(eventTraceActivity, this.methodName,
217                                 TraceUtility.GetUtcBasedDurationForTrace(beginOperation));
218                         }
219                     }
220                     else if (callFaulted)
221                     {
222                         if (TD.OperationFaultedIsEnabled())
223                         {
224                             TD.OperationFaulted(eventTraceActivity, this.methodName,
225                                 TraceUtility.GetUtcBasedDurationForTrace(beginOperation));
226                         }
227                     }
228                     else
229                     {
230                         if (TD.OperationFailedIsEnabled())
231                         {
232                             TD.OperationFailed(eventTraceActivity, this.methodName,
233                                 TraceUtility.GetUtcBasedDurationForTrace(beginOperation));
234                         }
235                     }
236                 }
237             }
238 
239             return returnValue;
240         }
241 
InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)242         public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
243         {
244             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
245         }
246 
InvokeEnd(object instance, out object[] outputs, IAsyncResult result)247         public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
248         {
249             throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException());
250         }
251 
EnsureIsInitialized()252         void EnsureIsInitialized()
253         {
254             if (this.invokeDelegate == null)
255             {
256                 EnsureIsInitializedCore();
257             }
258         }
259 
EnsureIsInitializedCore()260         void EnsureIsInitializedCore()
261         {
262             // Only pass locals byref because InvokerUtil may store temporary results in the byref.
263             // If two threads both reference this.count, temporary results may interact.
264             int inputParameterCount;
265             int outputParameterCount;
266             InvokeDelegate invokeDelegate = new InvokerUtil().GenerateInvokeDelegate(this.Method, out inputParameterCount, out outputParameterCount);
267             this.outputParameterCount = outputParameterCount;
268             this.inputParameterCount = inputParameterCount;
269             this.invokeDelegate = invokeDelegate;  // must set this last due to ----
270         }
271     }
272 }
273