< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Description.ServiceDescription<T>
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Description/ServiceDescription.cs
Line coverage
100%
Covered lines: 12
Uncovered lines: 0
Coverable lines: 12
Total lines: 345
Line coverage: 100%
Branch coverage
100%
Covered branches: 6
Total branches: 6
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%66100%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/Description/ServiceDescription.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.Diagnostics;
 8using System.Linq;
 9using System.Linq.Expressions;
 10using System.Reflection;
 11using CoreWCF.Collections.Generic;
 12using CoreWCF.Dispatcher;
 13using CoreWCF.Runtime;
 14using Microsoft.Extensions.DependencyInjection;
 15
 16namespace CoreWCF.Description
 17{
 18    public class ServiceDescription
 19    {
 20        private string _configurationName;
 21        private XmlName _serviceName;
 22
 23        public ServiceDescription() { }
 24
 25        public ServiceDescription(IEnumerable<ServiceEndpoint> endpoints) : this()
 26        {
 27            if (endpoints == null)
 28            {
 29                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(endpoints));
 30            }
 31
 32            foreach (ServiceEndpoint endpoint in endpoints)
 33            {
 34                Endpoints.Add(endpoint);
 35            }
 36        }
 37
 38        public string Name
 39        {
 40            get
 41            {
 42                if (_serviceName != null)
 43                {
 44                    return _serviceName.EncodedName;
 45                }
 46                else if (ServiceType != null)
 47                {
 48                    return NamingHelper.XmlName(ServiceType.Name);
 49                }
 50                else
 51                {
 52                    return NamingHelper.DefaultServiceName;
 53                }
 54            }
 55            set
 56            {
 57                if (string.IsNullOrEmpty(value))
 58                {
 59                    _serviceName = null;
 60                }
 61                else
 62                {
 63                    // the XmlName ctor validate the value
 64                    _serviceName = new XmlName(value, true /*isEncoded*/);
 65                }
 66            }
 67        }
 68
 69        public string Namespace { get; set; } = NamingHelper.DefaultNamespace;
 70
 71        internal IServiceProvider ServiceProvider { get; set; }
 72
 73        // This was KeyedByTypeCollection, maybe change to Collection<IServiceBehavior>
 74        public KeyedByTypeCollection<IServiceBehavior> Behaviors { get; } = new KeyedByTypeCollection<IServiceBehavior>(
 75
 76        public string ConfigurationName
 77        {
 78            get { return _configurationName; }
 79            set
 80            {
 81                _configurationName = value ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(va
 82            }
 83        }
 84
 85        public ServiceEndpointCollection Endpoints { get; } = new ServiceEndpointCollection();
 86
 87        public Type ServiceType { get; set; }
 88
 89        internal static void AddBehaviors<TService>(ServiceDescription serviceDescription, IEnumerable<IServiceBehavior>
 90        {
 91            TypeLoader<TService>.ApplyServiceInheritance<IServiceBehavior, KeyedByTypeCollection<IServiceBehavior>>(
 92                serviceDescription.Behaviors, GetIServiceBehaviorAttributes);
 93
 94            if (injectedBehaviors != null)
 95            {
 96                // Only add IServiceBehavior from DI if concrete type not already added
 97                // TODO: Add logging to state when an injected behavior has been skipped
 98                foreach(var behavior in injectedBehaviors)
 99                {
 100                    if (!serviceDescription.Behaviors.Contains(behavior.GetType()))
 101                    {
 102                        serviceDescription.Behaviors.Add(behavior);
 103                    }
 104                }
 105            }
 106
 107            ServiceBehaviorAttribute serviceBehavior = EnsureBehaviorAttribute(serviceDescription);
 108
 109            if (serviceBehavior.Name != null)
 110            {
 111                serviceDescription.Name = new XmlName(serviceBehavior.Name).EncodedName;
 112            }
 113
 114            if (serviceBehavior.Namespace != null)
 115            {
 116                serviceDescription.Namespace = serviceBehavior.Namespace;
 117            }
 118
 119            if (string.IsNullOrEmpty(serviceBehavior.ConfigurationName))
 120            {
 121                serviceDescription.ConfigurationName = typeof(TService).FullName;
 122            }
 123            else
 124            {
 125                serviceDescription.ConfigurationName = serviceBehavior.ConfigurationName;
 126            }
 127        }
 128
 129        public static ServiceDescription GetService<TService>() where TService : class
 130        {
 131            // TODO: Make ServiceDescription generic?
 132            var description = new ServiceDescription
 133            {
 134                ServiceType = typeof(TService)
 135            };
 136
 137            AddBehaviors<TService>(description);
 138            SetupSingleton(description, (TService)null);
 139            return description;
 140        }
 141
 142        public static ServiceDescription GetService<TService>(TService serviceImplementation) where TService : class
 143        {
 144            if (serviceImplementation == null)
 145            {
 146                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(serviceImplementation));
 147            }
 148
 149            ServiceDescription description = new ServiceDescription
 150            {
 151                // TODO: What if the concrete type is different that the generic type?
 152                ServiceType = typeof(TService) //serviceImplementation.GetType();
 153            };
 154
 155            if (serviceImplementation is IServiceBehavior behavior)
 156            {
 157                description.Behaviors.Add(behavior);
 158            }
 159
 160            AddBehaviors<TService>(description);
 161            SetupSingleton(description, serviceImplementation);
 162            return description;
 163        }
 164
 165        internal static TService CreateImplementation<TService>() where TService : class
 166        {
 167            if (!InvokerUtil.HasDefaultConstructor(typeof(TService)))
 168            {
 169                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 170                    SR.Format(SR.SFxNoDefaultConstructor, typeof(TService).FullName)));
 171            }
 172
 173            return (TService)InvokerUtil.GenerateCreateInstanceDelegate(typeof(TService))();
 174        }
 175
 176        //internal static object CreateImplementation(Type serviceType)
 177        //{
 178        //    var constructors = serviceType.GetConstructors(TypeLoader.DefaultBindingFlags);
 179        //    ConstructorInfo constructor = null;
 180        //    foreach (var constr in constructors)
 181        //    {
 182        //        if (constr.GetParameters().Length == 0)
 183        //        {
 184        //            constructor = constr;
 185        //            break;
 186        //        }
 187        //    }
 188
 189        //    if (constructor == null)
 190        //    {
 191        //        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 192        //            SR.SFxNoDefaultConstructor));
 193        //    }
 194
 195        //    return constructor.Invoke(null, null);
 196        //}
 197
 198        internal ServiceCredentials EnsureCredentials()
 199        {
 200            ServiceCredentials c = Behaviors.Find<ServiceCredentials>();
 201
 202            if (c == null)
 203            {
 204                c = ServiceProvider?.GetRequiredService<ServiceCredentials>() ?? new ServiceCredentials();
 205                Behaviors.Add(c);
 206            }
 207
 208            return c;
 209        }
 210
 211        private static ServiceBehaviorAttribute EnsureBehaviorAttribute(ServiceDescription description)
 212        {
 213            ServiceBehaviorAttribute attr = description.Behaviors.Find<ServiceBehaviorAttribute>();
 214
 215            if (attr == null)
 216            {
 217                attr = new ServiceBehaviorAttribute();
 218                description.Behaviors.Insert(0, attr);
 219            }
 220
 221            return attr;
 222        }
 223
 224        // This method ensures that the description object graph is structurally sound and that none
 225        // of the fundamental SFx framework assumptions have been violated.
 226        internal void EnsureInvariants()
 227        {
 228            for (int i = 0; i < Endpoints.Count; i++)
 229            {
 230                ServiceEndpoint endpoint = Endpoints[i];
 231                if (endpoint == null)
 232                {
 233                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.AChannelS
 234                }
 235                endpoint.EnsureInvariants();
 236            }
 237        }
 238
 239        private static void GetIServiceBehaviorAttributes(Type currentServiceType, KeyedByTypeCollection<IServiceBehavio
 240        {
 241            foreach (IServiceBehavior behaviorAttribute in ServiceReflector.GetCustomAttributes(currentServiceType, type
 242            {
 243                behaviors.Add(behaviorAttribute);
 244            }
 245        }
 246
 247        internal static void SetupSingleton<TService>(ServiceDescription serviceDescription, TService implementation) wh
 248        {
 249            ServiceBehaviorAttribute serviceBehavior = EnsureBehaviorAttribute(serviceDescription);
 250            if (serviceBehavior.InstanceContextMode == InstanceContextMode.Single)
 251            {
 252                if (implementation == null)
 253                {
 254                    // implementation will only be null if not provided using DI
 255                    implementation = CreateImplementation<TService>();
 256                    serviceBehavior.SetHiddenSingleton(implementation);
 257                }
 258                else
 259                {
 260                    serviceBehavior.SetWellKnownSingleton(implementation);
 261                }
 262            }
 263        }
 264
 265        internal static void SetupSingleton<TService>(ServiceDescription serviceDescription, IServiceProvider services) 
 266        {
 267            ServiceBehaviorAttribute serviceBehavior = serviceDescription.Behaviors.Find<ServiceBehaviorAttribute>();
 268            Debug.Assert(serviceBehavior != null, "EnsureServiceBehavior should have ensured the serviceBehavior");
 269
 270            if (serviceBehavior.InstanceContextMode == InstanceContextMode.Single)
 271            {
 272                TService implementation = services.GetService<TService>();
 273                if (implementation == null)
 274                {
 275                    implementation = CreateImplementation<TService>();
 276                    serviceBehavior.SetHiddenSingleton(implementation);
 277                }
 278                else
 279                {
 280                    serviceBehavior.SetWellKnownSingleton(implementation);
 281                }
 282            }
 283        }
 284
 285        private class ReflectedContractCollection : KeyedCollection<Type, ContractDescription>
 286        {
 287            public ReflectedContractCollection()
 288                : base(null, 4)
 289            {
 290            }
 291
 292            protected override Type GetKeyForItem(ContractDescription item)
 293            {
 294                if (item == null)
 295                {
 296                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(item));
 297                }
 298
 299                return item.ContractType;
 300            }
 301
 302            public IDictionary<string, ContractDescription> ToImplementedContracts()
 303            {
 304                Dictionary<string, ContractDescription> implementedContracts = new Dictionary<string, ContractDescriptio
 305                foreach (ContractDescription contract in Items)
 306                {
 307                    implementedContracts.Add(GetConfigKey(contract), contract);
 308                }
 309                return implementedContracts;
 310            }
 311
 312            internal static string GetConfigKey(ContractDescription contract)
 313            {
 314                return contract.ConfigurationName;
 315            }
 316        }
 317    }
 318
 319    internal class ServiceDescription<TService> : ServiceDescription where TService : class
 320    {
 583321        public ServiceDescription(IEnumerable<IServiceBehavior> injectedBehaviors, IServiceProvider services)
 322        {
 583323            ServiceType = typeof(TService);
 583324            ServiceProvider = services;
 325            // Clone IServiceBehavior DI services implementing ICloneable to allow per service override.
 583326            var behaviors = injectedBehaviors.ToList();
 327
 583328            if (services is IKeyedServiceProvider keyedServiceProvider)
 329            {
 583330                behaviors.AddRange(keyedServiceProvider.GetKeyedServices<IServiceBehavior>(ServiceType));
 331            }
 332
 2486333            for (int i = 0; i < behaviors.Count; i++)
 334            {
 660335                if(behaviors[i] is ICloneable cloneable)
 336                {
 585337                    behaviors[i] = (IServiceBehavior)cloneable.Clone();
 338                }
 339            }
 340
 583341            AddBehaviors<TService>(this, behaviors);
 583342            SetupSingleton<TService>(this, services);
 582343        }
 344    }
 345}