< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Description.ServiceMetadataBehavior
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Description/ServiceMetadataBehavior.cs
Line coverage
62%
Covered lines: 110
Uncovered lines: 66
Coverable lines: 176
Total lines: 486
Line coverage: 62.5%
Branch coverage
60%
Covered branches: 89
Total branches: 148
Branch coverage: 60.1%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Description/ServiceMetadataBehavior.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.Collections.ObjectModel;
 7using System.ComponentModel;
 8using System.Linq;
 9using System.Text;
 10using System.Xml;
 11using CoreWCF.Channels;
 12using CoreWCF.Collections.Generic;
 13using CoreWCF.Dispatcher;
 14using CoreWCF.Runtime;
 15using CoreWCF.Security;
 16
 17namespace CoreWCF.Description
 18{
 19    public class ServiceMetadataBehavior : IServiceBehavior
 20    {
 21        public const string MexContractName = "IMetadataExchange";
 22        internal const string MexContractNamespace = "http://schemas.microsoft.com/2006/04/mex";
 23        private Uri _httpGetUrl;
 24        private Uri _httpsGetUrl;
 25        private Uri _externalMetadataLocation = null;
 26        private MetadataExporter _metadataExporter = null;
 027        private static ContractDescription s_mexContract = null;
 028        private static readonly object s_thisLock = new object();
 29
 4530        public bool HttpGetEnabled { get; set; } = false;
 31
 32        [TypeConverter(typeof(UriTypeConverter))]
 33        public Uri HttpGetUrl
 34        {
 035            get { return _httpGetUrl; }
 36            set
 37            {
 138                if (value != null && value.IsAbsoluteUri && value.Scheme != Uri.UriSchemeHttp)
 39                {
 040                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.Format(SR.SFxServiceMetadataBehavior
 041                            nameof(HttpGetUrl), Uri.UriSchemeHttp, value.ToString(), value.Scheme));
 42                }
 43
 144                _httpGetUrl = value;
 145            }
 46        }
 47
 3148        public bool HttpsGetEnabled { get; set; } = false;
 49
 50        [TypeConverter(typeof(UriTypeConverter))]
 51        public Uri HttpsGetUrl
 52        {
 053            get { return _httpsGetUrl; }
 54            set
 55            {
 056                if (value != null && value.IsAbsoluteUri && value.Scheme != Uri.UriSchemeHttps)
 57                {
 058                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SR.Format(SR.SFxServiceMetadataBehavior
 059                        nameof(HttpsGetUrl), Uri.UriSchemeHttps, value.ToString(), value.Scheme));
 60                }
 61
 062                _httpsGetUrl = value;
 063            }
 64        }
 65
 66        [TypeConverter(typeof(UriTypeConverter))]
 67        public Uri ExternalMetadataLocation
 68        {
 4969            get { return _externalMetadataLocation; }
 70            set
 71            {
 072                if (value != null && value.IsAbsoluteUri && !(value.Scheme == Uri.UriSchemeHttp || value.Scheme == Uri.U
 73                {
 074                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(ExternalMetadataLocation), SR.Fo
 75                }
 76
 077                _externalMetadataLocation = value;
 078            }
 79        }
 80
 81        public MetadataExporter MetadataExporter
 82        {
 83            get
 84            {
 2485                if (_metadataExporter == null)
 86                {
 2387                    _metadataExporter = new WsdlExporter();
 88                }
 89
 2490                return _metadataExporter;
 91            }
 92            set
 93            {
 094                _metadataExporter = value;
 095            }
 96        }
 97
 98        internal static ContractDescription MexContract
 99        {
 100            get
 101            {
 0102                EnsureMexContractDescription();
 0103                return s_mexContract;
 104            }
 105        }
 106
 25107        void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase) { }
 108
 57109        void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Coll
 110
 111        void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase)
 112        {
 25113            if (description == null)
 114            {
 0115                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(description));
 116            }
 117
 25118            if (serviceHostBase == null)
 119            {
 0120                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(serviceHostBase));
 121            }
 122
 25123            ApplyBehavior(description, serviceHostBase);
 25124        }
 125
 126        private void ApplyBehavior(ServiceDescription description, ServiceHostBase host)
 127        {
 25128            ServiceMetadataExtension mex = ServiceMetadataExtension.EnsureServiceMetadataExtension(host);
 25129            SetExtensionProperties(description, host, mex);
 25130        }
 131
 132        private void SetExtensionProperties(ServiceDescription description, ServiceHostBase host, ServiceMetadataExtensi
 133        {
 25134            mex.ExternalMetadataLocation = ExternalMetadataLocation;
 25135            mex.Initializer = new MetadataExtensionInitializer(this, description, host);
 25136            mex.HttpGetEnabled = HttpGetEnabled;
 25137            mex.HttpsGetEnabled = HttpsGetEnabled;
 138
 25139            mex.HttpGetUrl = host.GetVia(Uri.UriSchemeHttp, GetFirstEndpointUriForScheme(Uri.UriSchemeHttp, _httpGetUrl,
 25140            mex.HttpsGetUrl = host.GetVia(Uri.UriSchemeHttps, GetFirstEndpointUriForScheme(Uri.UriSchemeHttps, _httpsGet
 141
 116142            foreach (ChannelDispatcherBase dispatcherBase in host.ChannelDispatchers)
 143            {
 33144                if (dispatcherBase is ChannelDispatcher dispatcher && IsMetadataTransferDispatcher(description, dispatch
 145                {
 0146                    mex.MexEnabled = true;
 0147                    throw new NotImplementedException();
 148                    //mex.MexUrl = dispatcher.Listener.Uri;
 149
 150                    //if (dynamicUpdateBehavior != null)
 151                    //{
 152                    //    foreach (EndpointDispatcher endpointDispatcher in dispatcher.Endpoints)
 153                    //    {
 154                    //        if (!endpointDispatcher.AddressFilterSetExplicit)
 155                    //        {
 156                    //            endpointDispatcher.AddressFilter = new MatchAllMessageFilter();
 157                    //        }
 158                    //    }
 159                    //}
 160                    //break;
 161                }
 162            }
 25163        }
 164
 165        private static Uri GetFirstEndpointUriForScheme(string uriScheme, Uri configuredGetUrl, ServiceDescription descr
 50166            => configuredGetUrl
 50167                ?? description?.Endpoints?.FirstOrDefault(endpoint =>
 57168                        string.Equals(endpoint?.Address?.Uri?.Scheme, uriScheme, StringComparison.Ordinal))
 50169                   ?.Address?.Uri
 50170                ?? new Uri(string.Empty, UriKind.Relative);
 171
 172        private static EndpointDispatcher GetListenerByID(SynchronizedCollection<ChannelDispatcherBase> channelDispatche
 173        {
 102174            for (int i = 0; i < channelDispatchers.Count; ++i)
 175            {
 51176                if (channelDispatchers[i] is ChannelDispatcher channelDispatcher)
 177                {
 140178                    for (int j = 0; j < channelDispatcher.Endpoints.Count; ++j)
 179                    {
 51180                        EndpointDispatcher endpointDispatcher = channelDispatcher.Endpoints[j];
 51181                        if (endpointDispatcher.Id == id)
 182                        {
 32183                            return endpointDispatcher;
 184                        }
 185                    }
 186                }
 187            }
 188
 0189            return null;
 190        }
 191
 192        private static bool IsMetadataTransferDispatcher(ServiceDescription description, ChannelDispatcher channelDispat
 193        {
 33194            if (BehaviorMissingObjectNullOrServiceImplements(description, channelDispatcher))
 195            {
 0196                return false;
 197            }
 198
 132199            foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
 200            {
 33201                if (endpointDispatcher.ContractName == MexContractName
 33202                    && endpointDispatcher.ContractNamespace == MexContractNamespace)
 203                {
 0204                    return true;
 205                }
 206            }
 207
 33208            return false;
 0209        }
 210
 211        private static bool BehaviorMissingObjectNullOrServiceImplements(ServiceDescription description, object obj)
 212        {
 33213            if (obj == null)
 214            {
 0215                return true;
 216            }
 217
 33218            if (description.Behaviors != null && description.Behaviors.Find<ServiceMetadataBehavior>() == null)
 219            {
 0220                return true;
 221            }
 222
 33223            if (description.ServiceType != null && description.ServiceType.GetInterface(typeof(IMetadataExchange).Name) 
 224            {
 0225                return true;
 226            }
 227
 33228            return false;
 229        }
 230
 231        internal static bool IsHttpGetMetadataDispatcher(ServiceDescription description, ChannelDispatcher channelDispat
 232        {
 0233            if (description.Behaviors.Find<ServiceMetadataBehavior>() == null)
 234            {
 0235                return false;
 236            }
 237
 0238            foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints)
 239            {
 0240                if (endpointDispatcher.ContractName == ServiceMetadataExtension.HttpGetImpl.ContractName
 0241                    && endpointDispatcher.ContractNamespace == ServiceMetadataExtension.HttpGetImpl.ContractNamespace)
 242                {
 0243                    return true;
 244                }
 245            }
 246
 0247            return false;
 0248        }
 249
 250        internal static bool IsMetadataEndpoint(ServiceDescription description, ServiceEndpoint endpoint)
 251        {
 0252            if (BehaviorMissingObjectNullOrServiceImplements(description, endpoint))
 253            {
 0254                return false;
 255            }
 256
 0257            return IsMetadataEndpoint(endpoint);
 258
 259        }
 260
 261        private static bool IsMetadataEndpoint(ServiceEndpoint endpoint)
 262        {
 0263            return endpoint.Contract.Name == MexContractName
 0264                    && endpoint.Contract.Namespace == MexContractNamespace;
 265        }
 266
 267        internal static bool IsMetadataImplementedType(ServiceDescription description, Type type)
 268        {
 0269            if (BehaviorMissingObjectNullOrServiceImplements(description, type))
 270            {
 0271                return false;
 272            }
 273
 0274            return type == typeof(IMetadataExchange);
 275        }
 276
 277        internal static bool IsMetadataImplementedType(Type type)
 278        {
 0279            return type == typeof(IMetadataExchange);
 280        }
 281
 282        private static void EnsureMexContractDescription()
 283        {
 0284            if (s_mexContract == null)
 285            {
 0286                lock (s_thisLock)
 287                {
 0288                    if (s_mexContract == null)
 289                    {
 0290                        s_mexContract = CreateMexContract();
 291                    }
 0292                }
 293            }
 0294        }
 295
 296        private static ContractDescription CreateMexContract()
 297        {
 298            // Using ServiceMetadataBehavior as a dummy type to pass to GetContract as it doesn't actually need the type
 299            // to be passed.
 0300            ContractDescription mexContract = ContractDescription.GetContract<ServiceMetadataBehavior>(typeof(IMetadataE
 0301            foreach (OperationDescription operation in mexContract.Operations)
 302            {
 0303                ((KeyedByTypeCollection<IOperationBehavior>)operation.OperationBehaviors).Find<OperationBehaviorAttribut
 304            }
 305
 0306            mexContract.ContractBehaviors.Add(new ServiceMetadataContractBehavior(true));
 0307            return mexContract;
 308        }
 309
 310        internal class MetadataExtensionInitializer
 311        {
 312            private readonly ServiceMetadataBehavior _behavior;
 313            private readonly ServiceDescription _description;
 314            private readonly ServiceHostBase _host;
 315            private Exception _metadataGenerationException = null;
 316
 25317            internal MetadataExtensionInitializer(ServiceMetadataBehavior behavior, ServiceDescription description, Serv
 318            {
 25319                _behavior = behavior;
 25320                _description = description;
 25321                _host = host;
 25322            }
 323
 324            internal MetadataSet GenerateMetadata()
 325            {
 24326                if (_behavior.ExternalMetadataLocation == null || _behavior.ExternalMetadataLocation.ToString() == strin
 327                {
 24328                    if (_metadataGenerationException != null)
 329                    {
 0330                        throw _metadataGenerationException;
 331                    }
 332
 333                    try
 334                    {
 24335                        MetadataExporter exporter = _behavior.MetadataExporter;
 24336                        XmlQualifiedName serviceName = new XmlQualifiedName(_description.Name, _description.Namespace);
 24337                        Collection<ServiceEndpoint> exportedEndpoints = new Collection<ServiceEndpoint>();
 112338                        foreach (ServiceEndpoint endpoint in _description.Endpoints)
 339                        {
 32340                            ServiceMetadataContractBehavior contractBehavior = ((KeyedByTypeCollection<IContractBehavior
 341
 342                            // if contract behavior exists, generate metadata when the behavior allows metadata generati
 343                            // if contract behavior doesn't exist, generate metadata only for non system endpoints
 32344                            if ((contractBehavior != null && !contractBehavior.MetadataGenerationDisabled) ||
 32345                                (contractBehavior == null && !endpoint.IsSystemEndpoint))
 346                            {
 32347                                EndpointAddress address = null;
 32348                                EndpointDispatcher endpointDispatcher = GetListenerByID(_host.ChannelDispatchers, endpoi
 32349                                if (endpointDispatcher != null)
 350                                {
 32351                                    address = endpointDispatcher.EndpointAddress;
 352                                }
 353
 32354                                ServiceEndpoint exportedEndpoint = new ServiceEndpoint(endpoint.Contract)
 32355                                {
 32356                                    Binding = endpoint.Binding,
 32357                                    Name = endpoint.Name,
 32358                                    Address = address
 32359                                };
 128360                                foreach (IEndpointBehavior behavior in endpoint.EndpointBehaviors)
 361                                {
 32362                                    exportedEndpoint.EndpointBehaviors.Add(behavior);
 363                                }
 364
 32365                                exportedEndpoints.Add(exportedEndpoint);
 366                            }
 367                        }
 368
 24369                        if (exporter is WsdlExporter wsdlExporter)
 370                        {
 371                            // Fix issue with shared exporter. Need to do comparison of Type objects as "is" will return
 24372                            if (exporter.GetType() == typeof(WsdlExporter))
 373                            {
 24374                                exporter = wsdlExporter = wsdlExporter.Clone();
 375                            }
 376
 377                            // Pass the BindingParameterCollection into the ExportEndpoints method so that the binding p
 378                            // The binding parameters are used in BuildChannelListener, during which they can modify the
 379                            // be communicated in the WSDL. For example, in the case of Multi-Auth, the AuthenticationSc
 380                            // to set the AuthenticationSchemes supported by the virtual directory on the HttpTransportB
 381                            // to be in the WSDL, so that clients know what authentication schemes are supported by the 
 382                            Fx.Assert(_host != null, "ServiceHostBase field on MetadataExtensionInitializer should never
 24383                            wsdlExporter.ExportEndpoints(exportedEndpoints, serviceName, GetBindingParameters(_host, exp
 384                        }
 385                        else
 386                        {
 0387                            foreach (ServiceEndpoint endpoint in exportedEndpoints)
 388                            {
 0389                                exporter.ExportEndpoint(endpoint);
 390                            }
 391                        }
 392
 393                        //if (exporter.Errors.Count > 0 && DiagnosticUtility.ShouldTraceWarning)
 394                        //{
 395                        //    TraceWsdlExportErrors(exporter);
 396                        //}
 397
 24398                        return exporter.GetGeneratedMetadata();
 399                    }
 0400                    catch (Exception e)
 401                    {
 0402                        _metadataGenerationException = e;
 0403                        throw;
 404                    }
 405                }
 406
 0407                return null;
 24408            }
 409
 410            private BindingParameterCollection GetBindingParameters(ServiceHostBase serviceHost, Collection<ServiceEndpo
 411            {
 24412                BindingParameterCollection parameters = new BindingParameterCollection();
 254413                foreach (IServiceBehavior behavior in serviceHost.Description.Behaviors)
 414                {
 103415                    behavior.AddBindingParameters(serviceHost.Description, serviceHost, endpoints, parameters);
 416                }
 417
 112418                foreach (ServiceEndpoint endpoint in endpoints)
 419                {
 32420                    AddBindingParametersForSecurityContractInformation(endpoint, parameters);
 128421                    foreach (IContractBehavior icb in endpoint.Contract.ContractBehaviors)
 422                    {
 32423                        icb.AddBindingParameters(endpoint.Contract, endpoint, parameters);
 424                    }
 425
 128426                    foreach (IEndpointBehavior ieb in endpoint.EndpointBehaviors)
 427                    {
 32428                        ieb.AddBindingParameters(endpoint, parameters);
 429                    }
 430
 382431                    foreach (OperationDescription op in endpoint.Contract.Operations)
 432                    {
 1272433                        foreach (IOperationBehavior iob in op.OperationBehaviors)
 434                        {
 477435                            iob.AddBindingParameters(op, parameters);
 436                        }
 437                    }
 438                }
 439
 24440                return parameters;
 441            }
 442
 443            internal static void AddBindingParametersForSecurityContractInformation(ServiceEndpoint endpoint, BindingPar
 444            {
 445                // get Contract info security needs, and put in BindingParameterCollection
 32446                ISecurityCapabilities isc = null;
 32447                BindingElementCollection elements = endpoint.Binding.CreateBindingElements();
 152448                for (int i = 0; i < elements.Count; ++i)
 449                {
 54450                    if (!(elements[i] is ITransportTokenAssertionProvider))
 451                    {
 51452                        ISecurityCapabilities tmp = elements[i].GetProperty<ISecurityCapabilities>(new BindingContext(ne
 51453                        if (tmp != null)
 454                        {
 10455                            isc = tmp;
 10456                            break;
 457                        }
 458                    }
 459                }
 460
 32461                if (isc != null)
 462                {
 463                    // ensure existence of binding parameter
 10464                    ChannelProtectionRequirements requirements = parameters.Find<ChannelProtectionRequirements>();
 10465                    if (requirements == null)
 466                    {
 3467                        requirements = new ChannelProtectionRequirements();
 3468                        parameters.Add(requirements);
 469                    }
 470
 10471                    MessageEncodingBindingElement encoding = elements.Find<MessageEncodingBindingElement>();
 472                    // use endpoint.Binding.Version
 10473                    if (encoding != null && encoding.MessageVersion.Addressing == AddressingVersion.None)
 474                    {
 475                        // This binding does not support response actions, so...
 0476                        requirements.Add(ChannelProtectionRequirements.CreateFromContractAndUnionResponseProtectionRequi
 477                    }
 478                    else
 479                    {
 10480                        requirements.Add(ChannelProtectionRequirements.CreateFromContract(endpoint.Contract, isc));
 481                    }
 482                }
 32483            }
 484        }
 485    }
 486}

Methods/Properties

.cctor()
HttpGetEnabled()
HttpGetUrl()
HttpGetUrl(System.Uri)
HttpsGetEnabled()
HttpsGetUrl()
HttpsGetUrl(System.Uri)
ExternalMetadataLocation()
ExternalMetadataLocation(System.Uri)
MetadataExporter()
MetadataExporter(CoreWCF.Description.MetadataExporter)
MexContract()
CoreWCF.Description.IServiceBehavior.Validate(CoreWCF.Description.ServiceDescription,CoreWCF.ServiceHostBase)
CoreWCF.Description.IServiceBehavior.AddBindingParameters(CoreWCF.Description.ServiceDescription,CoreWCF.ServiceHostBase,System.Collections.ObjectModel.Collection`1<CoreWCF.Description.ServiceEndpoint>,CoreWCF.Channels.BindingParameterCollection)
CoreWCF.Description.IServiceBehavior.ApplyDispatchBehavior(CoreWCF.Description.ServiceDescription,CoreWCF.ServiceHostBase)
ApplyBehavior(CoreWCF.Description.ServiceDescription,CoreWCF.ServiceHostBase)
SetExtensionProperties(CoreWCF.Description.ServiceDescription,CoreWCF.ServiceHostBase,CoreWCF.Description.ServiceMetadataExtension)
GetFirstEndpointUriForScheme(System.String,System.Uri,CoreWCF.Description.ServiceDescription)
GetListenerByID(CoreWCF.Collections.Generic.SynchronizedCollection`1<CoreWCF.Dispatcher.ChannelDispatcherBase>,System.String)
IsMetadataTransferDispatcher(CoreWCF.Description.ServiceDescription,CoreWCF.Dispatcher.ChannelDispatcher)
BehaviorMissingObjectNullOrServiceImplements(CoreWCF.Description.ServiceDescription,System.Object)
IsHttpGetMetadataDispatcher(CoreWCF.Description.ServiceDescription,CoreWCF.Dispatcher.ChannelDispatcher)
IsMetadataEndpoint(CoreWCF.Description.ServiceDescription,CoreWCF.Description.ServiceEndpoint)
IsMetadataEndpoint(CoreWCF.Description.ServiceEndpoint)
IsMetadataImplementedType(CoreWCF.Description.ServiceDescription,System.Type)
IsMetadataImplementedType(System.Type)
EnsureMexContractDescription()
CreateMexContract()
.ctor(CoreWCF.Description.ServiceMetadataBehavior,CoreWCF.Description.ServiceDescription,CoreWCF.ServiceHostBase)
GenerateMetadata()
GetBindingParameters(CoreWCF.ServiceHostBase,System.Collections.ObjectModel.Collection`1<CoreWCF.Description.ServiceEndpoint>)
AddBindingParametersForSecurityContractInformation(CoreWCF.Description.ServiceEndpoint,CoreWCF.Channels.BindingParameterCollection)