< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Description.XmlName
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Description/ServiceReflector.cs
Line coverage
91%
Covered lines: 21
Uncovered lines: 2
Coverable lines: 23
Total lines: 1061
Line coverage: 91.3%
Branch coverage
100%
Covered branches: 14
Total branches: 14
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor(...)100%11100%
.ctor(...)100%22100%
ValidateEncodedName(...)100%4471.42%
IsNullOrEmpty(...)100%22100%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Description/ServiceReflector.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Diagnostics;
 7using System.Globalization;
 8using System.Reflection;
 9using System.Threading;
 10//using System.Xml;
 11using System.Threading.Tasks;
 12using System.Xml;
 13using CoreWCF.Runtime;
 14
 15namespace CoreWCF.Description
 16{
 17    internal static class NamingHelper
 18    {
 19        internal const string DefaultNamespace = "http://tempuri.org/";
 20        internal const string DefaultServiceName = "service";
 21        internal const string MSNamespace = "http://schemas.microsoft.com/2005/07/ServiceModel";
 22
 23        // simplified rules for appending paths to base URIs. note that this differs from new Uri(baseUri, string)
 24        // 1) CombineUriStrings("http://foo/bar/z", "baz") ==> "http://foo/bar/z/baz"
 25        // 2) CombineUriStrings("http://foo/bar/z/", "baz") ==> "http://foo/bar/z/baz"
 26        // 3) CombineUriStrings("http://foo/bar/z", "/baz") ==> "http://foo/bar/z/baz"
 27        // 4) CombineUriStrings("http://foo/bar/z", "http://baz/q") ==> "http://baz/q"
 28        // 5) CombineUriStrings("http://foo/bar/z", "") ==> ""
 29
 30        internal static string CombineUriStrings(string baseUri, string path)
 31        {
 32            if (Uri.IsWellFormedUriString(path, UriKind.Absolute) || path == string.Empty)
 33            {
 34                return path;
 35            }
 36            else
 37            {
 38                // combine
 39                if (baseUri.EndsWith("/", StringComparison.Ordinal))
 40                {
 41                    return baseUri + (path.StartsWith("/", StringComparison.Ordinal) ? path.Substring(1) : path);
 42                }
 43                else
 44                {
 45                    return baseUri + (path.StartsWith("/", StringComparison.Ordinal) ? path : "/" + path);
 46                }
 47            }
 48        }
 49
 50        internal static string TypeName(Type t)
 51        {
 52            if (t.IsGenericType || t.ContainsGenericParameters)
 53            {
 54                Type[] args = t.GetGenericArguments();
 55                int nameEnd = t.Name.IndexOf('`');
 56                string result = nameEnd > 0 ? t.Name.Substring(0, nameEnd) : t.Name;
 57                result += "Of";
 58                for (int i = 0; i < args.Length; ++i)
 59                {
 60                    result = result + "_" + TypeName(args[i]);
 61                }
 62                return result;
 63            }
 64            else if (t.IsArray)
 65            {
 66                return "ArrayOf" + TypeName(t.GetElementType());
 67            }
 68            else
 69            {
 70                return t.Name;
 71            }
 72        }
 73
 74        // name, ns could have any combination of nulls
 75        internal static XmlQualifiedName GetContractName(Type contractType, string name, string ns)
 76        {
 77            XmlName xmlName = new XmlName(name ?? TypeName(contractType));
 78            // ns can be empty
 79            if (ns == null)
 80            {
 81                ns = DefaultNamespace;
 82            }
 83            return new XmlQualifiedName(xmlName.EncodedName, ns);
 84        }
 85
 86        // name could be null
 87        // logicalMethodName is MethodInfo.Name with Begin removed for async pattern
 88        // return encoded version to be used in OperationDescription
 89        internal static XmlName GetOperationName(string logicalMethodName, string name)
 90        {
 91            return new XmlName(string.IsNullOrEmpty(name) ? logicalMethodName : name);
 92        }
 93
 94        //internal static string GetMessageAction(OperationDescription operation, bool isResponse)
 95        //{
 96        //    ContractDescription contract = operation.DeclaringContract;
 97        //    XmlQualifiedName contractQname = new XmlQualifiedName(contract.Name, contract.Namespace);
 98        //    return GetMessageAction(contractQname, operation.CodeName, null, isResponse);
 99        //}
 100
 101        // name could be null
 102        // logicalMethodName is MethodInfo.Name with Begin removed for async pattern
 103        internal static string GetMessageAction(XmlQualifiedName contractName, string opname, string action, bool isResp
 104        {
 105            if (action != null)
 106            {
 107                return action;
 108            }
 109
 110            System.Text.StringBuilder actionBuilder = new System.Text.StringBuilder(64);
 111            if (string.IsNullOrEmpty(contractName.Namespace))
 112            {
 113                actionBuilder.Append("urn:");
 114            }
 115            else
 116            {
 117                actionBuilder.Append(contractName.Namespace);
 118                if (!contractName.Namespace.EndsWith("/", StringComparison.Ordinal))
 119                {
 120                    actionBuilder.Append('/');
 121                }
 122            }
 123            actionBuilder.Append(contractName.Name);
 124            actionBuilder.Append('/');
 125            action = isResponse ? opname + "Response" : opname;
 126
 127            return CombineUriStrings(actionBuilder.ToString(), action);
 128        }
 129
 130        internal delegate bool DoesNameExist(string name, object nameCollection);
 131        internal static string GetUniqueName(string baseName, DoesNameExist doesNameExist, object nameCollection)
 132        {
 133            for (int i = 0; i < int.MaxValue; i++)
 134            {
 135                string name = i > 0 ? baseName + i : baseName;
 136                if (!doesNameExist(name, nameCollection))
 137                {
 138                    return name;
 139                }
 140            }
 141            Fx.Assert("Too Many Names");
 142            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(string.Format(Cultur
 143        }
 144
 145        internal static void CheckUriProperty(string ns, string propName)
 146        {
 147            if (!Uri.TryCreate(ns, UriKind.RelativeOrAbsolute, out Uri uri))
 148            {
 149                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.Format(SR.SFXUnvalidNamespaceValue, ns, 
 150            }
 151        }
 152
 153        internal static void CheckUriParameter(string ns, string paramName)
 154        {
 155            if (!Uri.TryCreate(ns, UriKind.RelativeOrAbsolute, out Uri uri))
 156            {
 157                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(paramName, SR.Format(SR.SFXUnvalidNamespace
 158            }
 159        }
 160
 161        // Converts names that contain characters that are not permitted in XML names to valid names.
 162        internal static string XmlName(string name)
 163        {
 164            if (string.IsNullOrEmpty(name))
 165            {
 166                return name;
 167            }
 168
 169            if (IsAsciiLocalName(name))
 170            {
 171                return name;
 172            }
 173
 174            if (IsValidNCName(name))
 175            {
 176                return name;
 177            }
 178
 179            return XmlConvert.EncodeLocalName(name);
 180        }
 181
 182        // Transforms an XML name into an object name.
 183        internal static string CodeName(string name)
 184        {
 185            return XmlConvert.DecodeName(name);
 186        }
 187
 188        private static bool IsAlpha(char ch)
 189        {
 190            return (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z');
 191        }
 192
 193        private static bool IsDigit(char ch)
 194        {
 195            return (ch >= '0' && ch <= '9');
 196        }
 197
 198        private static bool IsAsciiLocalName(string localName)
 199        {
 200            Fx.Assert(null != localName, "");
 201            if (!IsAlpha(localName[0]))
 202            {
 203                return false;
 204            }
 205
 206            for (int i = 1; i < localName.Length; i++)
 207            {
 208                char ch = localName[i];
 209                if (!IsAlpha(ch) && !IsDigit(ch))
 210                {
 211                    return false;
 212                }
 213            }
 214            return true;
 215        }
 216
 217        internal static bool IsValidNCName(string name)
 218        {
 219            try
 220            {
 221                XmlConvert.VerifyNCName(name);
 222                return true;
 223            }
 224            catch (XmlException)
 225            {
 226                return false;
 227            }
 228        }
 229    }
 230
 231    [DebuggerDisplay("{_encoded ?? _decoded}")]
 232    internal class XmlName
 233    {
 234        private string _decoded;
 235        private string _encoded;
 236
 237        internal XmlName(string name)
 6374238            : this(name, false)
 239        {
 6374240        }
 241
 24997242        internal XmlName(string name, bool isEncoded)
 243        {
 24997244            if (isEncoded)
 245            {
 18623246                ValidateEncodedName(name, true /*allowNull*/);
 18623247                _encoded = name;
 248            }
 249            else
 250            {
 6374251                _decoded = name;
 252            }
 6374253        }
 254
 255        internal string EncodedName
 256        {
 257            get
 258            {
 76917259                if (_encoded == null)
 260                {
 6192261                    _encoded = NamingHelper.XmlName(_decoded);
 262                }
 263
 76917264                return _encoded;
 265            }
 266        }
 267
 268        internal string DecodedName
 269        {
 270            get
 271            {
 6116272                if (_decoded == null)
 273                {
 2934274                    _decoded = NamingHelper.CodeName(_encoded);
 275                }
 276
 6116277                return _decoded;
 278            }
 279        }
 280
 281        private static void ValidateEncodedName(string name, bool allowNull)
 282        {
 18623283            if (allowNull && name == null)
 284            {
 114285                return;
 286            }
 287
 288            try
 289            {
 18509290                XmlConvert.VerifyNCName(name);
 18509291            }
 0292            catch (XmlException e)
 293            {
 0294                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(name), e.Message);
 295            }
 18509296        }
 297
 66298        private bool IsEmpty { get { return string.IsNullOrEmpty(_encoded) && string.IsNullOrEmpty(_decoded); } }
 299
 300        internal static bool IsNullOrEmpty(XmlName xmlName)
 301        {
 586302            return xmlName == null || xmlName.IsEmpty;
 303        }
 304
 305        //    bool Matches(XmlName xmlName)
 306        //    {
 307        //        return string.Equals(this.EncodedName, xmlName.EncodedName, StringComparison.Ordinal);
 308        //    }
 309
 310        //    public override bool Equals(object obj)
 311        //    {
 312        //        if (object.ReferenceEquals(obj, this))
 313        //        {
 314        //            return true;
 315        //        }
 316
 317        //        if (object.ReferenceEquals(obj, null))
 318        //        {
 319        //            return false;
 320        //        }
 321
 322        //        XmlName xmlName = obj as XmlName;
 323        //        if (xmlName == null)
 324        //        {
 325        //            return false;
 326        //        }
 327
 328        //        return Matches(xmlName);
 329        //    }
 330
 331        //    public override int GetHashCode()
 332        //    {
 333        //        if (string.IsNullOrEmpty(EncodedName))
 334        //            return 0;
 335        //        return EncodedName.GetHashCode();
 336        //    }
 337
 338        //    public override string ToString()
 339        //    {
 340        //        if (encoded == null && decoded == null)
 341        //            return null;
 342        //        if (encoded != null)
 343        //            return encoded;
 344        //        return decoded;
 345        //    }
 346
 347        //    public static bool operator ==(XmlName a, XmlName b)
 348        //    {
 349        //        if (object.ReferenceEquals(a, null))
 350        //        {
 351        //            return object.ReferenceEquals(b, null);
 352        //        }
 353
 354        //        return (a.Equals(b));
 355        //    }
 356
 357        //    public static bool operator !=(XmlName a, XmlName b)
 358        //    {
 359        //        return !(a == b);
 360        //    }
 361    }
 362
 363    internal static class ServiceReflector
 364    {
 365        internal const BindingFlags ServiceModelBindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFla
 366        internal const string BeginMethodNamePrefix = "Begin";
 367        internal const string EndMethodNamePrefix = "End";
 368        internal const string AsyncMethodNameSuffix = "Async";
 369        internal static readonly Type VoidType = typeof(void);
 370        internal static readonly Type taskType = typeof(Task);
 371        internal static readonly Type taskTResultType = typeof(Task<>);
 372        internal static readonly Type CancellationTokenType = typeof(CancellationToken);
 373        internal static readonly Type IProgressType = typeof(IProgress<>);
 374        private static readonly Type s_asyncCallbackType = typeof(AsyncCallback);
 375        private static readonly Type s_asyncResultType = typeof(IAsyncResult);
 376        private static readonly Type s_objectType = typeof(object);
 377        private static readonly Type s_operationContractAttributeType = typeof(OperationContractAttribute);
 378        internal const string SMServiceContractAttributeFullName = "System.ServiceModel.ServiceContractAttribute";
 379        internal const string SMOperationContractAttributeFullName = "System.ServiceModel.OperationContractAttribute";
 380        internal const string SMMessageContractAttributeFullName = "System.ServiceModel.MessageContractAttribute";
 381        internal const string SMMessageHeaderAttributeFullName = "System.ServiceModel.MessageHeaderAttribute";
 382        internal const string SMMessageHeaderArrayAttributeFullName = "System.ServiceModel.MessageHeaderArrayAttribute";
 383        internal const string SMMessagePropertyAttributeFullName = "System.ServiceModel.MessagePropertyAttribute";
 384        internal const string SMMessageBodyMemberAttributeFullName = "System.ServiceModel.MessageBodyMemberAttribute";
 385        internal const string SMMessageParameterAttributeFullName = "System.ServiceModel.MessageParameterAttribute";
 386        internal const string SMXmlSerializerFormatAttributeFullName = "System.ServiceModel.XmlSerializerFormatAttribute
 387        internal const string SMFaultContractAttributeFullName = "System.ServiceModel.FaultContractAttribute";
 388        internal const string SMServiceKnownTypeAttributeFullName = "System.ServiceModel.ServiceKnownTypeAttribute";
 389
 390        internal const string CWCFMessageHeaderAttribute = "CoreWCF.MessageHeaderAttribute";
 391        internal const string CWCFMessageHeaderArrayAttribute = "CoreWCF.MessageHeaderArrayAttribute";
 392        internal const string CWCFMessageBodyMemberAttribute = "CoreWCF.MessageBodyMemberAttribute";
 393        internal const string CWCFMessagePropertyAttribute = "CoreWCF.MessagePropertyAttribute";
 394
 395        internal static Type GetOperationContractProviderType(MethodInfo method)
 396        {
 397            if (GetSingleAttribute<OperationContractAttribute>(method) != null)
 398            {
 399                return s_operationContractAttributeType;
 400            }
 401
 402            IOperationContractAttributeProvider provider = GetFirstAttribute<IOperationContractAttributeProvider>(method
 403            if (provider != null)
 404            {
 405                return provider.GetType();
 406            }
 407
 408            return null;
 409        }
 410
 411        internal static bool IsServiceContractAttributeDefined(Type type)
 412        {
 413            // Fast path for CoreWCF.ServiceContractAttribute
 414            if (type.IsDefined(typeof(ServiceContractAttribute), false))
 415            {
 416                return true;
 417            }
 418
 419            // GetCustomAttributesData doesn't traverse the inheritence chain so this is the equivalent of IsDefined(...
 420            IList<CustomAttributeData> cadList = type.GetCustomAttributesData();
 421            foreach (CustomAttributeData cad in cadList)
 422            {
 423                if (cad.AttributeType.FullName.Equals(SMServiceContractAttributeFullName))
 424                {
 425                    return true;
 426                }
 427            }
 428
 429            return false;
 430        }
 431
 432        // returns the set of root interfaces for the service class (meaning doesn't include callback ifaces)
 433        internal static List<Type> GetInterfaces<TService>() where TService : class
 434        {
 435            List<Type> types = new List<Type>();
 436            bool implicitContract = false;
 437            if (IsServiceContractAttributeDefined(typeof(TService)))
 438            {
 439                implicitContract = true;
 440                types.Add(typeof(TService));
 441            }
 442
 443            if (!implicitContract)
 444            {
 445                Type t = GetAncestorImplicitContractClass<TService>();
 446                if (t != null)
 447                {
 448                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR
 449                }
 450                foreach (MethodInfo method in GetMethodsInternal<TService>())
 451                {
 452                    Type operationContractProviderType = GetOperationContractProviderType(method);
 453                    if (operationContractProviderType == s_operationContractAttributeType)
 454                    {
 455                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Forma
 456                    }
 457                }
 458            }
 459            foreach (Type t in typeof(TService).GetInterfaces())
 460            {
 461                if (IsServiceContractAttributeDefined(t))
 462                {
 463                    if (implicitContract)
 464                    {
 465                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Forma
 466                    }
 467
 468                    types.Add(t);
 469                }
 470            }
 471
 472            return types;
 473        }
 474
 475        private static Type GetAncestorImplicitContractClass<TService>() where TService : class
 476        {
 477            for (Type service = typeof(TService).BaseType; service != null; service = service.BaseType)
 478            {
 479                if (GetSingleAttribute<ServiceContractAttribute>(service) != null)
 480                {
 481                    return service;
 482                }
 483            }
 484
 485            return null;
 486        }
 487
 488        internal static List<Type> GetInheritedContractTypes(Type service)
 489        {
 490            List<Type> types = new List<Type>();
 491            foreach (Type t in service.GetInterfaces())
 492            {
 493                if (GetSingleAttribute<ServiceContractAttribute>(t.GetTypeInfo()) != null)
 494                {
 495                    types.Add(t);
 496                }
 497            }
 498            for (service = service.GetTypeInfo().BaseType; service != null; service = service.GetTypeInfo().BaseType)
 499            {
 500                if (GetSingleAttribute<ServiceContractAttribute>(service.GetTypeInfo()) != null)
 501                {
 502                    types.Add(service);
 503                }
 504            }
 505            return types;
 506        }
 507
 508        internal static object[] GetCustomAttributes(ICustomAttributeProvider attrProvider, Type attrType)
 509        {
 510            return GetCustomAttributes(attrProvider, attrType, false);
 511        }
 512
 513        internal static object[] GetCustomAttributes(ICustomAttributeProvider attrProvider, Type attrType, bool inherit)
 514        {
 515            try
 516            {
 517                return attrProvider.GetDualCustomAttributes(attrType, inherit) ?? Array.Empty<object>();
 518            }
 519            catch (Exception e)
 520            {
 521                if (Fx.IsFatal(e))
 522                {
 523                    throw;
 524                }
 525
 526                // where the exception is CustomAttributeFormatException and the InnerException is a TargetInvocationExc
 527                // drill into the InnerException as this will provide a better error experience (fewer nested InnerExcep
 528                if (e is CustomAttributeFormatException && e.InnerException != null)
 529                {
 530                    e = e.InnerException;
 531                    if (e is TargetInvocationException && e.InnerException != null)
 532                    {
 533                        e = e.InnerException;
 534                    }
 535                }
 536
 537                Type type = attrProvider as Type;
 538                MethodInfo method = attrProvider as MethodInfo;
 539                ParameterInfo param = attrProvider as ParameterInfo;
 540                // there is no good way to know if this is a return type attribute
 541                if (type != null)
 542                {
 543                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 544                        SR.Format(SR.SFxErrorReflectingOnType2, attrType.Name, type.Name), e));
 545                }
 546                else if (method != null)
 547                {
 548                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 549                    SR.Format(SR.SFxErrorReflectingOnMethod3,
 550                                     attrType.Name, method.Name, method.ReflectedType.Name), e));
 551                }
 552                else if (param != null)
 553                {
 554                    method = param.Member as MethodInfo;
 555                    if (method != null)
 556                    {
 557                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 558                            SR.Format(SR.SFxErrorReflectingOnParameter4,
 559                                         attrType.Name, param.Name, method.Name, method.ReflectedType.Name), e));
 560                    }
 561                }
 562                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 563                    SR.Format(SR.SFxErrorReflectionOnUnknown1, attrType.Name), e));
 564            }
 565        }
 566
 567        internal static T GetFirstAttribute<T>(ICustomAttributeProvider attrProvider)
 568            where T : class
 569        {
 570            Type attrType = typeof(T);
 571            object[] attrs = GetCustomAttributes(attrProvider, attrType);
 572            if (attrs.Length == 0)
 573            {
 574                return null;
 575            }
 576            else
 577            {
 578                return attrs[0] as T;
 579            }
 580        }
 581
 582        internal static T GetSingleAttribute<T>(ICustomAttributeProvider attrProvider) where T : class
 583        {
 584            Type attrType = typeof(T);
 585            object[] attrs = GetCustomAttributes(attrProvider, attrType);
 586            if (attrs.Length == 0)
 587            {
 588                return null;
 589            }
 590            else if (attrs.Length > 1)
 591            {
 592                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.too
 593            }
 594            else
 595            {
 596                return attrs[0] as T;
 597            }
 598        }
 599
 600        //static internal T GetSingleAttribute<T>(MethodInfo attrProvider)
 601        //    where T : class
 602        //{
 603        //    Type attrType = typeof(T);
 604        //    object[] attrs = GetCustomAttributes(attrProvider, attrType);
 605        //    if (attrs.Length == 0)
 606        //    {
 607        //        return null;
 608        //    }
 609        //    else if (attrs.Length > 1)
 610        //    {
 611        //        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.t
 612        //    }
 613        //    else
 614        //    {
 615        //        return attrs[0] as T;
 616        //    }
 617        //}
 618        //static internal T GetSingleAttribute<T>(ICustomAttributeProvider attrProvider)
 619        //    where T : class
 620        //{
 621        //    Type attrType = typeof(T);
 622        //    object[] attrs = GetCustomAttributes(attrProvider, attrType);
 623        //    if (attrs.Length == 0)
 624        //    {
 625        //        return null;
 626        //    }
 627        //    else if (attrs.Length > 1)
 628        //    {
 629        //        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.t
 630        //    }
 631        //    else
 632        //    {
 633        //        return attrs[0] as T;
 634        //    }
 635        //}
 636
 637        internal static T GetRequiredSingleAttribute<T>(ICustomAttributeProvider attrProvider)
 638            where T : class
 639        {
 640            T result = GetSingleAttribute<T>(attrProvider);
 641            if (result == null)
 642            {
 643                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.cou
 644            }
 645            return result;
 646        }
 647
 648        internal static T GetSingleAttribute<T>(ICustomAttributeProvider attrProvider, Type[] attrTypeGroup)
 649            where T : class
 650        {
 651            T result = GetSingleAttribute<T>(attrProvider);
 652            if (result != null)
 653            {
 654                Type attrType = typeof(T);
 655                foreach (Type otherType in attrTypeGroup)
 656                {
 657                    if (otherType == attrType)
 658                    {
 659                        continue;
 660                    }
 661                    object[] attrs = GetCustomAttributes(attrProvider, otherType);
 662                    if (attrs != null && attrs.Length > 0)
 663                    {
 664                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Forma
 665                    }
 666                }
 667            }
 668            return result;
 669        }
 670
 671        internal static T GetRequiredSingleAttribute<T>(ICustomAttributeProvider attrProvider, Type[] attrTypeGroup)
 672            where T : class
 673        {
 674            T result = GetSingleAttribute<T>(attrProvider, attrTypeGroup);
 675            if (result == null)
 676            {
 677                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.cou
 678            }
 679            return result;
 680        }
 681
 682        //        static internal Type GetContractType(Type interfaceType)
 683        //        {
 684        //            ServiceContractAttribute contractAttribute;
 685        //            return GetContractTypeAndAttribute(interfaceType, out contractAttribute);
 686        //        }
 687
 688        internal static Type GetContractTypeAndAttribute(Type interfaceType, out ServiceContractAttribute contractAttrib
 689        {
 690            contractAttribute = GetSingleAttribute<ServiceContractAttribute>(interfaceType.GetTypeInfo());
 691            if (contractAttribute != null)
 692            {
 693                return interfaceType;
 694            }
 695
 696            List<Type> types = new List<Type>(GetInheritedContractTypes(interfaceType));
 697            if (types.Count == 0)
 698            {
 699                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.Att
 700            }
 701
 702
 703            foreach (Type potentialContractRoot in types)
 704            {
 705                bool mayBeTheRoot = true;
 706                foreach (Type t in types)
 707                {
 708                    if (!t.IsAssignableFrom(potentialContractRoot))
 709                    {
 710                        mayBeTheRoot = false;
 711                    }
 712                }
 713                if (mayBeTheRoot)
 714                {
 715                    contractAttribute = GetSingleAttribute<ServiceContractAttribute>(potentialContractRoot.GetTypeInfo()
 716                    return potentialContractRoot;
 717                }
 718            }
 719            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 720                SR.Format(SR.SFxNoMostDerivedContract, interfaceType.Name)));
 721        }
 722
 723        private static List<MethodInfo> GetMethodsInternal<TService>() where TService : class
 724        {
 725            List<MethodInfo> methods = new List<MethodInfo>();
 726            foreach (MethodInfo mi in typeof(TService).GetMethods(ServiceModelBindingFlags))
 727            {
 728                if (GetSingleAttribute<OperationContractAttribute>(mi) != null)
 729                {
 730                    methods.Add(mi);
 731                }
 732                else if (GetFirstAttribute<IOperationContractAttributeProvider>(mi) != null)
 733                {
 734                    methods.Add(mi);
 735                }
 736            }
 737            return methods;
 738        }
 739
 740        // The metadata for "in" versus "out" seems to be inconsistent, depending upon what compiler generates it.
 741        // The following code assumes this is the truth table that all compilers will obey:
 742        //
 743        // True Parameter Type     .IsIn      .IsOut    .ParameterType.IsByRef
 744        //
 745        // in                        F          F         F         ...OR...
 746        // in                        T          F         F
 747        //
 748        // in/out                    T          T         T         ...OR...
 749        // in/out                    F          F         T
 750        //
 751        // out                       F          T         T
 752        internal static void ValidateParameterMetadata(MethodInfo methodInfo)
 753        {
 754            ParameterInfo[] parameters = methodInfo.GetParameters();
 755            foreach (ParameterInfo parameter in parameters)
 756            {
 757                if (!parameter.ParameterType.IsByRef)
 758                {
 759                    if (parameter.IsOut)
 760                    {
 761                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 762                            new InvalidOperationException(SR.Format(SR.SFxBadByValueParameterMetadata,
 763                            methodInfo.Name, methodInfo.DeclaringType.Name)));
 764                    }
 765                }
 766                else
 767                {
 768                    if (parameter.IsIn && !parameter.IsOut)
 769                    {
 770                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
 771                            new InvalidOperationException(SR.Format(SR.SFxBadByReferenceParameterMetadata,
 772                            methodInfo.Name, methodInfo.DeclaringType.Name)));
 773                    }
 774                }
 775            }
 776        }
 777
 778        internal static bool FlowsIn(ParameterInfo paramInfo)    // conceptually both "in" and "in/out" params return tr
 779        {
 780            return !paramInfo.IsOut || paramInfo.IsIn;
 781        }
 782        internal static bool FlowsOut(ParameterInfo paramInfo)   // conceptually both "out" and "in/out" params return t
 783        {
 784            return paramInfo.ParameterType.IsByRef;
 785        }
 786
 787        // for async method is the begin method
 788        internal static ParameterInfo[] GetInputParameters(MethodInfo method, bool asyncPattern)
 789        {
 790            int count = 0;
 791            ParameterInfo[] parameters = method.GetParameters();
 792
 793            // length of parameters we care about (-2 for async)
 794            int len = parameters.Length;
 795            if (asyncPattern)
 796            {
 797                len -= 2;
 798            }
 799
 800            // count the ins
 801            for (int i = 0; i < len; i++)
 802            {
 803                if (FlowsIn(parameters[i]))
 804                {
 805                    count++;
 806                }
 807            }
 808
 809            // grab the ins
 810            ParameterInfo[] result = new ParameterInfo[count];
 811            int pos = 0;
 812            for (int i = 0; i < len; i++)
 813            {
 814                ParameterInfo param = parameters[i];
 815                if (FlowsIn(param))
 816                {
 817                    result[pos++] = param;
 818                }
 819            }
 820            return result;
 821        }
 822
 823        // for async method is the end method
 824        internal static ParameterInfo[] GetOutputParameters(MethodInfo method, bool asyncPattern)
 825        {
 826            int count = 0;
 827            ParameterInfo[] parameters = method.GetParameters();
 828
 829            // length of parameters we care about (-1 for async)
 830            int len = parameters.Length;
 831            if (asyncPattern)
 832            {
 833                len -= 1;
 834            }
 835
 836            // count the outs
 837            for (int i = 0; i < len; i++)
 838            {
 839                if (FlowsOut(parameters[i]))
 840                {
 841                    count++;
 842                }
 843            }
 844
 845            // grab the outs
 846            ParameterInfo[] result = new ParameterInfo[count];
 847            int pos = 0;
 848            for (int i = 0; i < len; i++)
 849            {
 850                ParameterInfo param = parameters[i];
 851                if (FlowsOut(param))
 852                {
 853                    result[pos++] = param;
 854                }
 855            }
 856            return result;
 857        }
 858
 859        internal static bool HasOutputParameters(MethodInfo method, bool asyncPattern)
 860        {
 861            ParameterInfo[] parameters = method.GetParameters();
 862
 863            // length of parameters we care about (-1 for async)
 864            int len = parameters.Length;
 865            if (asyncPattern)
 866            {
 867                len -= 1;
 868            }
 869
 870            // count the outs
 871            for (int i = 0; i < len; i++)
 872            {
 873                if (FlowsOut(parameters[i]))
 874                {
 875                    return true;
 876                }
 877            }
 878
 879            return false;
 880        }
 881
 882        private static MethodInfo GetEndMethodInternal(MethodInfo beginMethod)
 883        {
 884            string logicalName = GetLogicalName(beginMethod);
 885            string endMethodName = EndMethodNamePrefix + logicalName;
 886            MemberInfo[] endMethods = beginMethod.DeclaringType.GetMember(endMethodName, ServiceModelBindingFlags);
 887            if (endMethods.Length == 0)
 888            {
 889                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.NoE
 890            }
 891            if (endMethods.Length > 1)
 892            {
 893                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.Mor
 894            }
 895            return (MethodInfo)endMethods[0];
 896        }
 897
 898        internal static MethodInfo GetEndMethod(MethodInfo beginMethod)
 899        {
 900            MethodInfo endMethod = GetEndMethodInternal(beginMethod);
 901
 902            if (!HasEndMethodShape(endMethod))
 903            {
 904                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR.Inv
 905            }
 906
 907            return endMethod;
 908        }
 909
 910        //        static internal XmlName GetOperationName(MethodInfo method)
 911        //        {
 912        //            OperationContractAttribute operationAttribute = GetOperationContractAttribute(method);
 913        //            return NamingHelper.GetOperationName(GetLogicalName(method), operationAttribute.Name);
 914        //        }
 915
 916
 917        internal static bool HasBeginMethodShape(MethodInfo method)
 918        {
 919            ParameterInfo[] parameters = method.GetParameters();
 920            if (!method.Name.StartsWith(BeginMethodNamePrefix, StringComparison.Ordinal) ||
 921                parameters.Length < 2 ||
 922                parameters[parameters.Length - 2].ParameterType != s_asyncCallbackType ||
 923                parameters[parameters.Length - 1].ParameterType != s_objectType ||
 924                method.ReturnType != s_asyncResultType)
 925            {
 926                return false;
 927            }
 928            return true;
 929        }
 930
 931        internal static bool IsBegin(OperationContractAttribute opSettings, MethodInfo method)
 932        {
 933            if (opSettings.AsyncPattern)
 934            {
 935                if (!HasBeginMethodShape(method))
 936                {
 937                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.Format(SR
 938                }
 939
 940                return true;
 941            }
 942            return false;
 943        }
 944
 945        internal static bool IsTask(MethodInfo method)
 946        {
 947            if (method.ReturnType == taskType)
 948            {
 949                return true;
 950            }
 951            if (method.ReturnType.GetTypeInfo().IsGenericType && method.ReturnType.GetGenericTypeDefinition() == taskTRe
 952            {
 953                return true;
 954            }
 955            return false;
 956        }
 957
 958        internal static bool IsTask(MethodInfo method, out Type taskTResult)
 959        {
 960            taskTResult = null;
 961            Type methodReturnType = method.ReturnType;
 962            if (methodReturnType == taskType)
 963            {
 964                taskTResult = VoidType;
 965                return true;
 966            }
 967
 968            if (methodReturnType.GetTypeInfo().IsGenericType && methodReturnType.GetGenericTypeDefinition() == taskTResu
 969            {
 970                taskTResult = methodReturnType.GetGenericArguments()[0];
 971                return true;
 972            }
 973
 974            return false;
 975        }
 976
 977        internal static bool HasEndMethodShape(MethodInfo method)
 978        {
 979            ParameterInfo[] parameters = method.GetParameters();
 980            if (!method.Name.StartsWith(EndMethodNamePrefix, StringComparison.Ordinal) ||
 981                parameters.Length < 1 ||
 982                parameters[parameters.Length - 1].ParameterType != s_asyncResultType)
 983            {
 984                return false;
 985            }
 986            return true;
 987        }
 988
 989        internal static OperationContractAttribute GetOperationContractAttribute(MethodInfo method)
 990        {
 991            OperationContractAttribute operationContractAttribute = GetSingleAttribute<OperationContractAttribute>(metho
 992            if (operationContractAttribute != null)
 993            {
 994                return operationContractAttribute;
 995            }
 996            IOperationContractAttributeProvider operationContractProvider = GetFirstAttribute<IOperationContractAttribut
 997            if (operationContractProvider != null)
 998            {
 999                return operationContractProvider.GetOperationContractAttribute();
 1000            }
 1001            return null;
 1002        }
 1003
 1004        internal static bool IsBegin(MethodInfo method)
 1005        {
 1006            OperationContractAttribute opSettings = GetOperationContractAttribute(method);
 1007            if (opSettings == null)
 1008            {
 1009                return false;
 1010            }
 1011
 1012            return IsBegin(opSettings, method);
 1013        }
 1014
 1015        internal static string GetLogicalName(MethodInfo method)
 1016        {
 1017            bool isAsync = IsBegin(method);
 1018            bool isTask = isAsync ? false : IsTask(method);
 1019            return GetLogicalName(method, isAsync, isTask);
 1020        }
 1021
 1022        internal static string GetLogicalName(MethodInfo method, bool isAsync, bool isTask)
 1023        {
 1024            if (isAsync)
 1025            {
 1026                return method.Name.Substring(BeginMethodNamePrefix.Length);
 1027            }
 1028            else if (isTask && method.Name.EndsWith(AsyncMethodNameSuffix, StringComparison.Ordinal))
 1029            {
 1030                return method.Name.Substring(0, method.Name.Length - AsyncMethodNameSuffix.Length);
 1031            }
 1032            else
 1033            {
 1034                return method.Name;
 1035            }
 1036        }
 1037
 1038        internal static bool HasNoDisposableParameters(MethodInfo methodInfo)
 1039        {
 1040            foreach (ParameterInfo inputInfo in methodInfo.GetParameters())
 1041            {
 1042                if (IsParameterDisposable(inputInfo.ParameterType))
 1043                {
 1044                    return false;
 1045                }
 1046            }
 1047
 1048            if (methodInfo.ReturnParameter != null)
 1049            {
 1050                return (!IsParameterDisposable(methodInfo.ReturnParameter.ParameterType));
 1051            }
 1052
 1053            return true;
 1054        }
 1055
 1056        internal static bool IsParameterDisposable(Type type)
 1057        {
 1058            return ((!type.GetTypeInfo().IsSealed) || typeof(IDisposable).IsAssignableFrom(type));
 1059        }
 1060    }
 1061}