|
//-----------------------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
namespace System.ServiceModel.Description
{
using System.Collections.Generic;
using System.Globalization;
using System.Reflection;
using System.Runtime;
using System.ServiceModel;
using System.Xml;
using System.Threading.Tasks;
using System.Threading;
static class NamingHelper
{
internal const string DefaultNamespace = "http://tempuri.org/";
internal const string DefaultServiceName = "service";
internal const string MSNamespace = "http://schemas.microsoft.com/2005/07/ServiceModel";
// simplified rules for appending paths to base URIs. note that this differs from new Uri(baseUri, string)
// 1) CombineUriStrings("http://foo/bar/z", "baz") ==> "http://foo/bar/z/baz"
// 2) CombineUriStrings("http://foo/bar/z/", "baz") ==> "http://foo/bar/z/baz"
// 3) CombineUriStrings("http://foo/bar/z", "/baz") ==> "http://foo/bar/z/baz"
// 4) CombineUriStrings("http://foo/bar/z", "http://baz/q") ==> "http://baz/q"
// 5) CombineUriStrings("http://foo/bar/z", "") ==> ""
internal static string CombineUriStrings(string baseUri, string path)
{
if (Uri.IsWellFormedUriString(path, UriKind.Absolute) || path == String.Empty)
{
return path;
}
else
{
// combine
if (baseUri.EndsWith("/", StringComparison.Ordinal))
{
return baseUri + (path.StartsWith("/", StringComparison.Ordinal) ? path.Substring(1) : path);
}
else
{
return baseUri + (path.StartsWith("/", StringComparison.Ordinal) ? path : "/" + path);
}
}
}
internal static string TypeName(Type t)
{
if (t.IsGenericType || t.ContainsGenericParameters)
{
Type[] args = t.GetGenericArguments();
int nameEnd = t.Name.IndexOf('`');
string result = nameEnd > 0 ? t.Name.Substring(0, nameEnd) : t.Name;
result += "Of";
for (int i = 0; i < args.Length; ++i)
{
result = result + "_" + TypeName(args[i]);
}
return result;
}
else if (t.IsArray)
{
return "ArrayOf" + TypeName(t.GetElementType());
}
else
{
return t.Name;
}
}
// name, ns could have any combination of nulls
internal static XmlQualifiedName GetContractName(Type contractType, string name, string ns)
{
XmlName xmlName = new XmlName(name ?? TypeName(contractType));
// ns can be empty
if (ns == null)
{
ns = DefaultNamespace;
}
return new XmlQualifiedName(xmlName.EncodedName, ns);
}
// name could be null
// logicalMethodName is MethodInfo.Name with Begin removed for async pattern
// return encoded version to be used in OperationDescription
internal static XmlName GetOperationName(string logicalMethodName, string name)
{
return new XmlName(String.IsNullOrEmpty(name) ? logicalMethodName : name);
}
internal static string GetMessageAction(OperationDescription operation, bool isResponse)
{
ContractDescription contract = operation.DeclaringContract;
XmlQualifiedName contractQname = new XmlQualifiedName(contract.Name, contract.Namespace);
return GetMessageAction(contractQname, operation.CodeName, null, isResponse);
}
// name could be null
// logicalMethodName is MethodInfo.Name with Begin removed for async pattern
internal static string GetMessageAction(XmlQualifiedName contractName, string opname, string action, bool isResponse)
{
if (action != null)
{
return action;
}
System.Text.StringBuilder actionBuilder = new System.Text.StringBuilder(64);
if (String.IsNullOrEmpty(contractName.Namespace))
{
actionBuilder.Append("urn:");
}
else
{
actionBuilder.Append(contractName.Namespace);
if (!contractName.Namespace.EndsWith("/", StringComparison.Ordinal))
{
actionBuilder.Append('/');
}
}
actionBuilder.Append(contractName.Name);
actionBuilder.Append('/');
action = isResponse ? opname + "Response" : opname;
return CombineUriStrings(actionBuilder.ToString(), action);
}
internal delegate bool DoesNameExist(string name, object nameCollection);
internal static string GetUniqueName(string baseName, DoesNameExist doesNameExist, object nameCollection)
{
for (int i = 0; i < Int32.MaxValue; i++)
{
string name = i > 0 ? baseName + i : baseName;
if (!doesNameExist(name, nameCollection))
{
return name;
}
}
Fx.Assert("Too Many Names");
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Cannot generate unique name for name {0}", baseName)));
}
internal static void CheckUriProperty(string ns, string propName)
{
Uri uri;
if (!Uri.TryCreate(ns, UriKind.RelativeOrAbsolute, out uri))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.GetString(SR.SFXUnvalidNamespaceValue, ns, propName));
}
internal static void CheckUriParameter(string ns, string paramName)
{
Uri uri;
if (!Uri.TryCreate(ns, UriKind.RelativeOrAbsolute, out uri))
throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(paramName, SR.GetString(SR.SFXUnvalidNamespaceParam, ns));
}
// Converts names that contain characters that are not permitted in XML names to valid names.
internal static string XmlName(string name)
{
if (string.IsNullOrEmpty(name))
return name;
if (IsAsciiLocalName(name))
return name;
if (IsValidNCName(name))
return name;
return XmlConvert.EncodeLocalName(name);
}
// Transforms an XML name into an object name.
internal static string CodeName(string name)
{
return XmlConvert.DecodeName(name);
}
static bool IsAlpha(char ch)
{
return (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z');
}
static bool IsDigit(char ch)
{
return (ch >= '0' && ch <= '9');
}
static bool IsAsciiLocalName(string localName)
{
Fx.Assert(null != localName, "");
if (!IsAlpha(localName[0]))
return false;
for (int i = 1; i < localName.Length; i++)
{
char ch = localName[i];
if (!IsAlpha(ch) && !IsDigit(ch))
return false;
}
return true;
}
internal static bool IsValidNCName(string name)
{
try
{
XmlConvert.VerifyNCName(name);
return true;
}
catch (XmlException)
{
return false;
}
}
}
internal class XmlName
{
string decoded;
string encoded;
internal XmlName(string name)
: this(name, false)
{
}
internal XmlName(string name, bool isEncoded)
{
if (isEncoded)
{
ValidateEncodedName(name, true /*allowNull*/);
encoded = name;
}
else
{
decoded = name;
}
}
internal string EncodedName
{
get
{
if (encoded == null)
encoded = NamingHelper.XmlName(decoded);
return encoded;
}
}
internal string DecodedName
{
get
{
if (decoded == null)
decoded = NamingHelper.CodeName(encoded);
return decoded;
}
}
static void ValidateEncodedName(string name, bool allowNull)
{
if (allowNull && name == null)
return;
try
{
XmlConvert.VerifyNCName(name);
}
catch (XmlException e)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(e.Message, "name"));
}
}
bool IsEmpty { get { return string.IsNullOrEmpty(encoded) && string.IsNullOrEmpty(decoded); } }
internal static bool IsNullOrEmpty(XmlName xmlName)
{
return xmlName == null || xmlName.IsEmpty;
}
bool Matches(XmlName xmlName)
{
return string.Equals(this.EncodedName, xmlName.EncodedName, StringComparison.Ordinal);
}
public override bool Equals(object obj)
{
if (object.ReferenceEquals(obj, this))
{
return true;
}
if (object.ReferenceEquals(obj, null))
{
return false;
}
XmlName xmlName = obj as XmlName;
if (xmlName == null)
{
return false;
}
return Matches(xmlName);
}
public override int GetHashCode()
{
if (string.IsNullOrEmpty(EncodedName))
return 0;
return EncodedName.GetHashCode();
}
public override string ToString()
{
if (encoded == null && decoded == null)
return null;
if (encoded != null)
return encoded;
return decoded;
}
public static bool operator ==(XmlName a, XmlName b)
{
if (object.ReferenceEquals(a, null))
{
return object.ReferenceEquals(b, null);
}
return (a.Equals(b));
}
public static bool operator !=(XmlName a, XmlName b)
{
return !(a == b);
}
}
static internal class ServiceReflector
{
internal const BindingFlags ServiceModelBindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
internal const string BeginMethodNamePrefix = "Begin";
internal const string EndMethodNamePrefix = "End";
internal static readonly Type VoidType = typeof(void);
internal const string AsyncMethodNameSuffix = "Async";
internal static readonly Type taskType = typeof(Task);
internal static readonly Type taskTResultType = typeof(Task<>);
internal static readonly Type CancellationTokenType = typeof(CancellationToken);
internal static readonly Type IProgressType = typeof(IProgress<>);
static readonly Type asyncCallbackType = typeof(AsyncCallback);
static readonly Type asyncResultType = typeof(IAsyncResult);
static readonly Type objectType = typeof(object);
static readonly Type OperationContractAttributeType = typeof(OperationContractAttribute);
static internal Type GetOperationContractProviderType(MethodInfo method)
{
if (GetSingleAttribute<OperationContractAttribute>(method) != null)
{
return OperationContractAttributeType;
}
IOperationContractAttributeProvider provider = GetFirstAttribute<IOperationContractAttributeProvider>(method);
if (provider != null)
{
return provider.GetType();
}
return null;
}
// returns the set of root interfaces for the service class (meaning doesn't include callback ifaces)
static internal List<Type> GetInterfaces(Type service)
{
List<Type> types = new List<Type>();
bool implicitContract = false;
if (service.IsDefined(typeof(ServiceContractAttribute), false))
{
implicitContract = true;
types.Add(service);
}
if (!implicitContract)
{
Type t = GetAncestorImplicitContractClass(service);
if (t != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxContractInheritanceRequiresInterfaces2, service, t)));
}
foreach (MethodInfo method in GetMethodsInternal(service))
{
Type operationContractProviderType = GetOperationContractProviderType(method);
if (operationContractProviderType == OperationContractAttributeType)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ServicesWithoutAServiceContractAttributeCan2, operationContractProviderType.Name, method.Name, service.FullName)));
}
}
}
foreach (Type t in service.GetInterfaces())
{
if (t.IsDefined(typeof(ServiceContractAttribute), false))
{
if (implicitContract)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxContractInheritanceRequiresInterfaces, service, t)));
}
types.Add(t);
}
}
return types;
}
static Type GetAncestorImplicitContractClass(Type service)
{
for (service = service.BaseType; service != null; service = service.BaseType)
{
if (ServiceReflector.GetSingleAttribute<ServiceContractAttribute>(service) != null)
{
return service;
}
}
return null;
}
static internal List<Type> GetInheritedContractTypes(Type service)
{
List<Type> types = new List<Type>();
foreach (Type t in service.GetInterfaces())
{
if (ServiceReflector.GetSingleAttribute<ServiceContractAttribute>(t) != null)
{
types.Add(t);
}
}
for (service = service.BaseType; service != null; service = service.BaseType)
{
if (ServiceReflector.GetSingleAttribute<ServiceContractAttribute>(service) != null)
{
types.Add(service);
}
}
return types;
}
static internal object[] GetCustomAttributes(ICustomAttributeProvider attrProvider, Type attrType)
{
return GetCustomAttributes(attrProvider, attrType, false);
}
static internal object[] GetCustomAttributes(ICustomAttributeProvider attrProvider, Type attrType, bool inherit)
{
try
{
return attrProvider.GetCustomAttributes(attrType, inherit);
}
catch (Exception e)
{
if (Fx.IsFatal(e))
{
throw;
}
// where the exception is CustomAttributeFormatException and the InnerException is a TargetInvocationException,
// drill into the InnerException as this will provide a better error experience (fewer nested InnerExceptions)
if (e is CustomAttributeFormatException && e.InnerException != null)
{
e = e.InnerException;
if (e is TargetInvocationException && e.InnerException != null)
{
e = e.InnerException;
}
}
Type type = attrProvider as Type;
MethodInfo method = attrProvider as MethodInfo;
ParameterInfo param = attrProvider as ParameterInfo;
// there is no good way to know if this is a return type attribute
if (type != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR.GetString(SR.SFxErrorReflectingOnType2, attrType.Name, type.Name), e));
}
else if (method != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR.GetString(SR.SFxErrorReflectingOnMethod3,
attrType.Name, method.Name, method.ReflectedType.Name), e));
}
else if (param != null)
{
method = param.Member as MethodInfo;
if (method != null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR.GetString(SR.SFxErrorReflectingOnParameter4,
attrType.Name, param.Name, method.Name, method.ReflectedType.Name), e));
}
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR.GetString(SR.SFxErrorReflectionOnUnknown1, attrType.Name), e));
}
}
static internal T GetFirstAttribute<T>(ICustomAttributeProvider attrProvider)
where T : class
{
Type attrType = typeof(T);
object[] attrs = GetCustomAttributes(attrProvider, attrType);
if (attrs.Length == 0)
{
return null;
}
else
{
return attrs[0] as T;
}
}
#if !NO_GENERIC
static internal T GetSingleAttribute<T>(ICustomAttributeProvider attrProvider)
where T : class
{
Type attrType = typeof(T);
object[] attrs = GetCustomAttributes(attrProvider, attrType);
if (attrs.Length == 0)
{
return null;
}
else if (attrs.Length > 1)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.tooManyAttributesOfTypeOn2, attrType, attrProvider.ToString())));
}
else
{
return attrs[0] as T;
}
}
#else
static internal object GetSingleAttribute(Type attrType, ICustomAttributeProvider attrProvider)
{
object[] attrs = GetCustomAttributes(attrProvider, attrType);
if (attrs.Length == 0)
{
return null;
}
else if (attrs.Length > 1)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.tooManyAttributesOfTypeOn2, attrType, attrProvider.ToString())));
}
else
{
return attrs[0];
}
}
#endif
#if !NO_GENERIC
static internal T GetRequiredSingleAttribute<T>(ICustomAttributeProvider attrProvider)
where T : class
{
T result = GetSingleAttribute<T>(attrProvider);
if (result == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.couldnTFindRequiredAttributeOfTypeOn2, typeof(T), attrProvider.ToString())));
}
return result;
}
#else
static internal object GetRequiredSingleAttribute(Type attrType, ICustomAttributeProvider attrProvider)
{
object result = GetSingleAttribute(attrType, attrProvider);
if (result == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.couldnTFindRequiredAttributeOfTypeOn2, attrType, attrProvider.ToString())));
}
return result;
}
#endif
#if !NO_GENERIC
static internal T GetSingleAttribute<T>(ICustomAttributeProvider attrProvider, Type[] attrTypeGroup)
where T : class
{
T result = GetSingleAttribute<T>(attrProvider);
if (result != null)
{
Type attrType = typeof(T);
foreach (Type otherType in attrTypeGroup)
{
if (otherType == attrType)
{
continue;
}
object[] attrs = GetCustomAttributes(attrProvider, otherType);
if (attrs != null && attrs.Length > 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxDisallowedAttributeCombination, attrProvider, attrType.FullName, otherType.FullName)));
}
}
}
return result;
}
#else
static internal object GetSingleAttribute(Type attrType, ICustomAttributeProvider attrProvider, Type[] attrTypeGroup)
{
object result = GetSingleAttribute(attrType, attrProvider);
if (result != null)
{
foreach (Type otherType in attrTypeGroup)
{
if (otherType == attrType)
{
continue;
}
object[] attrs = GetCustomAttributes(attrProvider, otherType);
if (attrs != null && attrs.Length > 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.SFxDisallowedAttributeCombination, attrProvider, attrType.FullName, otherType.FullName)));
}
}
}
return result;
}
#endif
#if !NO_GENERIC
static internal T GetRequiredSingleAttribute<T>(ICustomAttributeProvider attrProvider, Type[] attrTypeGroup)
where T : class
{
T result = GetSingleAttribute<T>(attrProvider, attrTypeGroup);
if (result == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.couldnTFindRequiredAttributeOfTypeOn2, typeof(T), attrProvider.ToString())));
}
return result;
}
#else
static internal object GetRequiredSingleAttribute(Type attrType, ICustomAttributeProvider attrProvider, Type[] attrTypeGroup)
{
object result = GetSingleAttribute(attrType, attrProvider, attrTypeGroup);
if (result == null)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.couldnTFindRequiredAttributeOfTypeOn2, attrType, attrProvider.ToString())));
}
return result;
}
#endif
static internal Type GetContractType(Type interfaceType)
{
ServiceContractAttribute contractAttribute;
return GetContractTypeAndAttribute(interfaceType, out contractAttribute);
}
static internal Type GetContractTypeAndAttribute(Type interfaceType, out ServiceContractAttribute contractAttribute)
{
contractAttribute = GetSingleAttribute<ServiceContractAttribute>(interfaceType);
if (contractAttribute != null)
{
return interfaceType;
}
List<Type> types = new List<Type>(GetInheritedContractTypes(interfaceType));
if (types.Count == 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.AttemptedToGetContractTypeForButThatTypeIs1, interfaceType.Name)));
}
foreach (Type potentialContractRoot in types)
{
bool mayBeTheRoot = true;
foreach (Type t in types)
{
if (!t.IsAssignableFrom(potentialContractRoot))
{
mayBeTheRoot = false;
}
}
if (mayBeTheRoot)
{
contractAttribute = GetSingleAttribute<ServiceContractAttribute>(potentialContractRoot);
return potentialContractRoot;
}
}
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
SR.GetString(SR.SFxNoMostDerivedContract, interfaceType.Name)));
}
static List<MethodInfo> GetMethodsInternal(Type interfaceType)
{
List<MethodInfo> methods = new List<MethodInfo>();
foreach (MethodInfo mi in interfaceType.GetMethods(ServiceModelBindingFlags))
{
if (GetSingleAttribute<OperationContractAttribute>(mi) != null)
{
methods.Add(mi);
}
else if (GetFirstAttribute<IOperationContractAttributeProvider>(mi) != null)
{
methods.Add(mi);
}
}
return methods;
}
// The metadata for "in" versus "out" seems to be inconsistent, depending upon what compiler generates it.
// The following code assumes this is the truth table that all compilers will obey:
//
// True Parameter Type .IsIn .IsOut .ParameterType.IsByRef
//
// in F F F ...OR...
// in T F F
//
// in/out T T T ...OR...
// in/out F F T
//
// out F T T
static internal void ValidateParameterMetadata(MethodInfo methodInfo)
{
ParameterInfo[] parameters = methodInfo.GetParameters();
foreach (ParameterInfo parameter in parameters)
{
if (!parameter.ParameterType.IsByRef)
{
if (parameter.IsOut)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new InvalidOperationException(SR.GetString(SR.SFxBadByValueParameterMetadata,
methodInfo.Name, methodInfo.DeclaringType.Name)));
}
}
else
{
if (parameter.IsIn && !parameter.IsOut)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
new InvalidOperationException(SR.GetString(SR.SFxBadByReferenceParameterMetadata,
methodInfo.Name, methodInfo.DeclaringType.Name)));
}
}
}
}
static internal bool FlowsIn(ParameterInfo paramInfo) // conceptually both "in" and "in/out" params return true
{
return !paramInfo.IsOut || paramInfo.IsIn;
}
static internal bool FlowsOut(ParameterInfo paramInfo) // conceptually both "out" and "in/out" params return true
{
return paramInfo.ParameterType.IsByRef;
}
// for async method is the begin method
static internal ParameterInfo[] GetInputParameters(MethodInfo method, bool asyncPattern)
{
int count = 0;
ParameterInfo[] parameters = method.GetParameters();
// length of parameters we care about (-2 for async)
int len = parameters.Length;
if (asyncPattern)
{
len -= 2;
}
// count the ins
for (int i = 0; i < len; i++)
{
if (FlowsIn(parameters[i]))
{
count++;
}
}
// grab the ins
ParameterInfo[] result = new ParameterInfo[count];
int pos = 0;
for (int i = 0; i < len; i++)
{
ParameterInfo param = parameters[i];
if (FlowsIn(param))
{
result[pos++] = param;
}
}
return result;
}
// for async method is the end method
static internal ParameterInfo[] GetOutputParameters(MethodInfo method, bool asyncPattern)
{
int count = 0;
ParameterInfo[] parameters = method.GetParameters();
// length of parameters we care about (-1 for async)
int len = parameters.Length;
if (asyncPattern)
{
len -= 1;
}
// count the outs
for (int i = 0; i < len; i++)
{
if (FlowsOut(parameters[i]))
{
count++;
}
}
// grab the outs
ParameterInfo[] result = new ParameterInfo[count];
int pos = 0;
for (int i = 0; i < len; i++)
{
ParameterInfo param = parameters[i];
if (FlowsOut(param))
{
result[pos++] = param;
}
}
return result;
}
static internal bool HasOutputParameters(MethodInfo method, bool asyncPattern)
{
ParameterInfo[] parameters = method.GetParameters();
// length of parameters we care about (-1 for async)
int len = parameters.Length;
if (asyncPattern)
{
len -= 1;
}
// count the outs
for (int i = 0; i < len; i++)
{
if (FlowsOut(parameters[i]))
{
return true;
}
}
return false;
}
static MethodInfo GetEndMethodInternal(MethodInfo beginMethod)
{
string logicalName = GetLogicalName(beginMethod);
string endMethodName = EndMethodNamePrefix + logicalName;
MemberInfo[] endMethods = beginMethod.DeclaringType.GetMember(endMethodName, ServiceModelBindingFlags);
if (endMethods.Length == 0)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.NoEndMethodFoundForAsyncBeginMethod3, beginMethod.Name, beginMethod.DeclaringType.FullName, endMethodName)));
}
if (endMethods.Length > 1)
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MoreThanOneEndMethodFoundForAsyncBeginMethod3, beginMethod.Name, beginMethod.DeclaringType.FullName, endMethodName)));
}
return (MethodInfo)endMethods[0];
}
static internal MethodInfo GetEndMethod(MethodInfo beginMethod)
{
MethodInfo endMethod = GetEndMethodInternal(beginMethod);
if (!HasEndMethodShape(endMethod))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidAsyncEndMethodSignatureForMethod2, endMethod.Name, endMethod.DeclaringType.FullName)));
}
return endMethod;
}
static internal XmlName GetOperationName(MethodInfo method)
{
OperationContractAttribute operationAttribute = GetOperationContractAttribute(method);
return NamingHelper.GetOperationName(GetLogicalName(method), operationAttribute.Name);
}
static internal bool HasBeginMethodShape(MethodInfo method)
{
ParameterInfo[] parameters = method.GetParameters();
if (!method.Name.StartsWith(BeginMethodNamePrefix, StringComparison.Ordinal) ||
parameters.Length < 2 ||
parameters[parameters.Length - 2].ParameterType != asyncCallbackType ||
parameters[parameters.Length - 1].ParameterType != objectType ||
method.ReturnType != asyncResultType)
{
return false;
}
return true;
}
static internal bool IsBegin(OperationContractAttribute opSettings, MethodInfo method)
{
if (opSettings.AsyncPattern)
{
if (!HasBeginMethodShape(method))
{
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InvalidAsyncBeginMethodSignatureForMethod2, method.Name, method.DeclaringType.FullName)));
}
return true;
}
return false;
}
static internal bool IsTask(MethodInfo method)
{
if (method.ReturnType == taskType)
{
return true;
}
if (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == taskTResultType)
{
return true;
}
return false;
}
static internal bool IsTask(MethodInfo method, out Type taskTResult)
{
taskTResult = null;
Type methodReturnType = method.ReturnType;
if (methodReturnType == taskType)
{
taskTResult = VoidType;
return true;
}
if (methodReturnType.IsGenericType && methodReturnType.GetGenericTypeDefinition() == taskTResultType)
{
taskTResult = methodReturnType.GetGenericArguments()[0];
return true;
}
return false;
}
static internal bool HasEndMethodShape(MethodInfo method)
{
ParameterInfo[] parameters = method.GetParameters();
if (!method.Name.StartsWith(EndMethodNamePrefix, StringComparison.Ordinal) ||
parameters.Length < 1 ||
parameters[parameters.Length - 1].ParameterType != asyncResultType)
{
return false;
}
return true;
}
internal static OperationContractAttribute GetOperationContractAttribute(MethodInfo method)
{
OperationContractAttribute operationContractAttribute = GetSingleAttribute<OperationContractAttribute>(method);
if (operationContractAttribute != null)
{
return operationContractAttribute;
}
IOperationContractAttributeProvider operationContractProvider = GetFirstAttribute<IOperationContractAttributeProvider>(method);
if (operationContractProvider != null)
{
return operationContractProvider.GetOperationContractAttribute();
}
return null;
}
static internal bool IsBegin(MethodInfo method)
{
OperationContractAttribute opSettings = GetOperationContractAttribute(method);
if (opSettings == null)
return false;
return IsBegin(opSettings, method);
}
static internal string GetLogicalName(MethodInfo method)
{
bool isAsync = IsBegin(method);
bool isTask = isAsync ? false : IsTask(method);
return GetLogicalName(method, isAsync, isTask);
}
static internal string GetLogicalName(MethodInfo method, bool isAsync, bool isTask)
{
if (isAsync)
{
return method.Name.Substring(BeginMethodNamePrefix.Length);
}
else if (isTask && method.Name.EndsWith(AsyncMethodNameSuffix, StringComparison.Ordinal))
{
return method.Name.Substring(0, method.Name.Length - AsyncMethodNameSuffix.Length);
}
else
{
return method.Name;
}
}
static internal bool HasNoDisposableParameters(MethodInfo methodInfo)
{
foreach (ParameterInfo inputInfo in methodInfo.GetParameters())
{
if (IsParameterDisposable(inputInfo.ParameterType))
{
return false;
}
}
if (methodInfo.ReturnParameter != null)
{
return (!IsParameterDisposable(methodInfo.ReturnParameter.ParameterType));
}
return true;
}
static internal bool IsParameterDisposable(Type type)
{
return ((!type.IsSealed) || typeof(IDisposable).IsAssignableFrom(type));
}
}
}
|