< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.Queue.Common.Configuration.QueueMiddlewareBuilderExtension
Assembly: CoreWCF.Queue
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Queue/src/CoreWCF/Queue/Common/Configuration/QueueMiddlewareBuilderExtension.cs
Line coverage
42%
Covered lines: 42
Uncovered lines: 58
Coverable lines: 100
Total lines: 158
Line coverage: 42%
Branch coverage
23%
Covered branches: 6
Total branches: 26
Branch coverage: 23%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
UseMiddleware(...)100%11100%
UseMiddleware(...)42.85%141465.07%
Compile(...)0%10100%
GetService(...)0%220%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Queue/src/CoreWCF/Queue/Common/Configuration/QueueMiddlewareBuilderExtension.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 Microsoft.Extensions.DependencyInjection;
 10
 11namespace CoreWCF.Queue.Common.Configuration
 12{
 13    public static class QueueMiddlewareBuilderExtension
 14    {
 15        private const string InvokeAsyncMethodName = "InvokeAsync";
 16
 17        public static IQueueMiddlewareBuilder UseMiddleware<TMiddleware>(this IQueueMiddlewareBuilder app,
 18            params object[] args)
 19        {
 10020            return app.UseMiddleware(typeof(TMiddleware), args);
 21        }
 22
 23        public static IQueueMiddlewareBuilder UseMiddleware(this IQueueMiddlewareBuilder app, Type middleware,
 24            params object[] args)
 25        {
 10026            IServiceProvider handshakeServices = app.Services;
 10027            return app.Use(next =>
 10028            {
 10029                MethodInfo[] methods = middleware.GetMethods(BindingFlags.Instance | BindingFlags.Public);
 10030                MethodInfo[] invokeMethods = methods.Where(m =>
 50031                    string.Equals(m.Name, InvokeAsyncMethodName, StringComparison.Ordinal)
 10032                ).ToArray();
 10033
 10034                if (invokeMethods.Length > 1)
 10035                {
 10036                    // TODO: String resources
 037                    throw new InvalidOperationException(
 038                        $"Resources.FormatException_UseMiddleMultipleInvokes({InvokeAsyncMethodName}");
 10039                }
 10040
 10041                if (invokeMethods.Length == 0)
 10042                {
 10043                    // TODO: String resources
 044                    throw new InvalidOperationException(
 045                        $"Resources.FormatException_UseMiddlewareNoInvokeMethod({InvokeAsyncMethodName}, {middleware}");
 10046                }
 10047
 10048                MethodInfo methodInfo = invokeMethods[0];
 10049                if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
 10050                {
 10051                    // TODO: String resources
 052                    throw new InvalidOperationException(
 053                        $"Resources.FormatException_UseMiddlewareNonTaskReturnType({InvokeAsyncMethodName}, {nameof(Task
 10054                }
 10055
 10056                ParameterInfo[] parameters = methodInfo.GetParameters();
 10057                if (parameters.Length == 0 || parameters[0].ParameterType != typeof(QueueMessageContext))
 10058                {
 10059                    // TODO: String resources
 060                    throw new InvalidOperationException(
 061                        $"Resources.FormatException_UseMiddlewareNoParameters({InvokeAsyncMethodName}, {nameof(QueueMess
 10062                }
 10063
 10064                object[] ctorArgs = new object[args.Length + 1];
 10065                ctorArgs[0] = next;
 10066                Array.Copy(args, 0, ctorArgs, 1, args.Length);
 10067                object instance = ActivatorUtilities.CreateInstance(app.Services, middleware, ctorArgs);
 10068                if (parameters.Length == 1)
 10069                {
 10070                    return (QueueMessageDispatcherDelegate)methodInfo.CreateDelegate(typeof(QueueMessageDispatcherDelega
 10071                }
 10072
 073                Func<object, QueueMessageContext, IServiceProvider, Task> factory =
 074                    Compile<object>(methodInfo, parameters);
 10075
 076                return context =>
 077                {
 078                    IServiceProvider serviceProvider = handshakeServices;
 079                    if (serviceProvider == null)
 080                    {
 081                        // TODO: String resources
 082                        throw new InvalidOperationException(
 083                            $"Resources.FormatException_UseMiddlewareIServiceProviderNotAvailable({nameof(IServiceProvid
 084                    }
 085
 086                    return factory(instance, context, serviceProvider);
 087                };
 10088            });
 89        }
 90
 91
 92        private static Func<T, QueueMessageContext, IServiceProvider, Task> Compile<T>(MethodInfo methodInfo,
 93            ParameterInfo[] parameters)
 94        {
 095            Type middleware = typeof(T);
 096            ParameterExpression connectionContextArg =
 097                Expression.Parameter(typeof(QueueMessageContext), "connectionContext");
 098            ParameterExpression providerArg = Expression.Parameter(typeof(IServiceProvider), "serviceProvider");
 099            ParameterExpression instanceArg = Expression.Parameter(middleware, "middleware");
 100
 0101            var methodArguments = new Expression[parameters.Length];
 0102            methodArguments[0] = connectionContextArg;
 0103            for (int i = 1; i < parameters.Length; i++)
 104            {
 0105                Type parameterType = parameters[i].ParameterType;
 0106                if (parameterType.IsByRef)
 107                {
 108                    // TODO: String resources
 0109                    throw new NotSupportedException(
 0110                        $"Resources.FormatException_InvokeDoesNotSupportRefOrOutParams({InvokeAsyncMethodName})");
 111                }
 112
 0113                var parameterTypeExpression = new Expression[]
 0114                {
 0115                    providerArg, Expression.Constant(parameterType, typeof(Type)),
 0116                    Expression.Constant(methodInfo.DeclaringType, typeof(Type))
 0117                };
 118
 0119                var getServiceInfo = typeof(QueueMiddlewareBuilderExtension).GetMethod(nameof(GetService),
 0120                    BindingFlags.NonPublic | BindingFlags.Static);
 0121                if (getServiceInfo == null)
 122                {
 0123                    throw new InvalidOperationException($"Resources.FormatException_UseMiddlewareGetServiceMethodNotFoun
 124                }
 125
 0126                MethodCallExpression getServiceCall = Expression.Call(getServiceInfo, parameterTypeExpression);
 0127                methodArguments[i] = Expression.Convert(getServiceCall, parameterType);
 128            }
 129
 0130            Expression middlewareInstanceArg = instanceArg;
 0131            if (methodInfo.DeclaringType != typeof(T) && methodInfo.DeclaringType != null)
 132            {
 0133                middlewareInstanceArg = Expression.Convert(middlewareInstanceArg, methodInfo.DeclaringType);
 134            }
 135
 0136            MethodCallExpression body = Expression.Call(middlewareInstanceArg, methodInfo, methodArguments);
 137
 0138            var lambda =
 0139                Expression.Lambda<Func<T, QueueMessageContext, IServiceProvider, Task>>(body, instanceArg,
 0140                    connectionContextArg, providerArg);
 141
 0142            return lambda.Compile();
 143        }
 144
 145        private static object GetService(IServiceProvider sp, Type type, Type middleware)
 146        {
 0147            object service = sp.GetService(type);
 0148            if (service == null)
 149            {
 150                // TODO: String resources
 0151                throw new InvalidOperationException(
 0152                    $"Resources.FormatException_InvokeMiddlewareNoService({type}, {middleware})");
 153            }
 154
 0155            return service;
 156        }
 157    }
 158}