< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Configuration.UseMiddlewareFramingConnectionHandshakeExtensions
Assembly: CoreWCF.NetFramingBase
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetFramingBase/src/CoreWCF/Configuration/UseMiddlewareFramingConnectionHandshakeExtensions.cs
Line coverage
48%
Covered lines: 42
Uncovered lines: 45
Coverable lines: 87
Total lines: 184
Line coverage: 48.2%
Branch coverage
27%
Covered branches: 6
Total branches: 22
Branch coverage: 27.2%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.cctor()100%110%
UseMiddleware(...)100%11100%
UseMiddleware(...)42.85%141471.92%
Compile(...)0%660%
GetService(...)0%220%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.NetFramingBase/src/CoreWCF/Configuration/UseMiddlewareFramingConnectionHandshakeExtensions.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.Linq;
 6using System.Linq.Expressions;
 7using System.Reflection;
 8using System.Threading.Tasks;
 9using CoreWCF.Channels.Framing;
 10using Microsoft.Extensions.DependencyInjection;
 11
 12namespace CoreWCF.Configuration
 13{
 14    /// <summary>
 15    /// Extension methods for adding typed middleware to a <see cref="IFramingConnectionHandshakeBuilder"/>.
 16    /// </summary>
 17    public static class UseMiddlewareFramingConnectionHandshakeExtensions
 18    {
 19        internal const string OnConnectedAsyncMethodName = "OnConnectedAsync";
 20
 021        private static readonly MethodInfo s_getServiceInfo = typeof(UseMiddlewareFramingConnectionHandshakeExtensions).
 22
 23        /// <summary>
 24        /// Adds a middleware type to the connection handshake pipeline.
 25        /// </summary>
 26        /// <typeparam name="TMiddleware">The middleware type.</typeparam>
 27        /// <param name="app">The <see cref="IFramingConnectionHandshakeBuilder"/> instance.</param>
 28        /// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
 29        /// <returns>The <see cref="IFramingConnectionHandshakeBuilder"/> instance.</returns>
 30        public static IFramingConnectionHandshakeBuilder UseMiddleware<TMiddleware>(this IFramingConnectionHandshakeBuil
 31        {
 58132            return app.UseMiddleware(typeof(TMiddleware), args);
 33        }
 34
 35        /// <summary>
 36        /// Adds a middleware type to the connection handshake pipeline.
 37        /// </summary>
 38        /// <param name="app">The <see cref="IFramingConnectionHandshakeBuilder"/> instance.</param>
 39        /// <param name="middleware">The middleware type.</param>
 40        /// <param name="args">The arguments to pass to the middleware type instance's constructor.</param>
 41        /// <returns>The <see cref="IFramingConnectionHandshakeBuilder"/> instance.</returns>
 42        public static IFramingConnectionHandshakeBuilder UseMiddleware(this IFramingConnectionHandshakeBuilder app, Type
 43        {
 58144            IServiceProvider handshakeServices = app.HandshakeServices;
 58145            return app.Use(next =>
 58146            {
 58147                MethodInfo[] methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);
 58148                MethodInfo[] invokeMethods = methods.Where(m =>
 315449                    string.Equals(m.Name, OnConnectedAsyncMethodName, StringComparison.Ordinal)
 58150                    ).ToArray();
 58151
 58152                if (invokeMethods.Length > 1)
 58153                {
 58154                    // TODO: String resources
 055                    throw new InvalidOperationException($"Resources.FormatException_UseMiddleMultipleInvokes({OnConnecte
 58156                }
 58157
 58158                if (invokeMethods.Length == 0)
 58159                {
 58160                    // TODO: String resources
 061                    throw new InvalidOperationException($"Resources.FormatException_UseMiddlewareNoInvokeMethod({OnConne
 58162                }
 58163
 58164                MethodInfo methodInfo = invokeMethods[0];
 58165                if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
 58166                {
 58167                    // TODO: String resources
 068                    throw new InvalidOperationException($"Resources.FormatException_UseMiddlewareNonTaskReturnType({OnCo
 58169                }
 58170
 58171                ParameterInfo[] parameters = methodInfo.GetParameters();
 58172                if (parameters.Length == 0 || parameters[0].ParameterType != typeof(FramingConnection))
 58173                {
 58174                    // TODO: String resources
 075                    throw new InvalidOperationException($"Resources.FormatException_UseMiddlewareNoParameters({OnConnect
 58176                }
 58177
 58178                object[] ctorArgs = new object[args.Length + 1];
 58179                ctorArgs[0] = next;
 58180                Array.Copy(args, 0, ctorArgs, 1, args.Length);
 58181                object instance = ActivatorUtilities.CreateInstance(app.HandshakeServices, middleware, ctorArgs);
 58182                if (parameters.Length == 1)
 58183                {
 58184                    return (HandshakeDelegate)methodInfo.CreateDelegate(typeof(HandshakeDelegate), instance);
 58185                }
 58186
 087                Func<object, FramingConnection, IServiceProvider, Task> factory = Compile<object>(methodInfo, parameters
 58188
 089                return context =>
 090                {
 091                    IServiceProvider serviceProvider = handshakeServices;
 092                    if (serviceProvider == null)
 093                    {
 094                        // TODO: String resources
 095                        throw new InvalidOperationException($"Resources.FormatException_UseMiddlewareIServiceProviderNot
 096                    }
 097
 098                    return factory(instance, context, serviceProvider);
 099                };
 581100            });
 101        }
 102
 103        private static Func<T, FramingConnection, IServiceProvider, Task> Compile<T>(MethodInfo methodInfo, ParameterInf
 104        {
 105            // If we call something like
 106            //
 107            // public class Middleware
 108            // {
 109            //    public Task Invoke(ConnectionContext context, ILoggerFactory loggerFactory)
 110            //    {
 111            //
 112            //    }
 113            // }
 114            //
 115
 116            // We'll end up with something like this:
 117            //   Generic version:
 118            //
 119            //   Task Invoke(Middleware instance, ConnectionContext httpContext, IServiceProvider provider)
 120            //   {
 121            //      return instance.Invoke(httpContext, (ILoggerFactory)UseMiddlewareConnectionHandshakeExtensions.GetSe
 122            //   }
 123
 124            //   Non generic version:
 125            //
 126            //   Task Invoke(object instance, ConnectionContext httpContext, IServiceProvider provider)
 127            //   {
 128            //      return ((Middleware)instance).Invoke(httpContext, (ILoggerFactory)UseMiddlewareConnectionHandshakeEx
 129            //   }
 130
 0131            Type middleware = typeof(T);
 132
 0133            ParameterExpression connectionContextArg = Expression.Parameter(typeof(FramingConnection), "connectionContex
 0134            ParameterExpression providerArg = Expression.Parameter(typeof(IServiceProvider), "serviceProvider");
 0135            ParameterExpression instanceArg = Expression.Parameter(middleware, "middleware");
 136
 0137            var methodArguments = new Expression[parameters.Length];
 0138            methodArguments[0] = connectionContextArg;
 0139            for (int i = 1; i < parameters.Length; i++)
 140            {
 0141                Type parameterType = parameters[i].ParameterType;
 0142                if (parameterType.IsByRef)
 143                {
 144                    // TODO: String resources
 0145                    throw new NotSupportedException($"Resources.FormatException_InvokeDoesNotSupportRefOrOutParams({OnCo
 146                }
 147
 0148                var parameterTypeExpression = new Expression[]
 0149                {
 0150                    providerArg,
 0151                    Expression.Constant(parameterType, typeof(Type)),
 0152                    Expression.Constant(methodInfo.DeclaringType, typeof(Type))
 0153                };
 154
 0155                MethodCallExpression getServiceCall = Expression.Call(s_getServiceInfo, parameterTypeExpression);
 0156                methodArguments[i] = Expression.Convert(getServiceCall, parameterType);
 157            }
 158
 0159            Expression middlewareInstanceArg = instanceArg;
 0160            if (methodInfo.DeclaringType != typeof(T))
 161            {
 0162                middlewareInstanceArg = Expression.Convert(middlewareInstanceArg, methodInfo.DeclaringType);
 163            }
 164
 0165            MethodCallExpression body = Expression.Call(middlewareInstanceArg, methodInfo, methodArguments);
 166
 0167            var lambda = Expression.Lambda<Func<T, FramingConnection, IServiceProvider, Task>>(body, instanceArg, connec
 168
 0169            return lambda.Compile();
 170        }
 171
 172        private static object GetService(IServiceProvider sp, Type type, Type middleware)
 173        {
 0174            object service = sp.GetService(type);
 0175            if (service == null)
 176            {
 177                // TODO: String resources
 0178                throw new InvalidOperationException($"Resources.FormatException_InvokeMiddlewareNoService({type}, {middl
 179            }
 180
 0181            return service;
 182        }
 183    }
 184}