throw new InvalidOperationException(Resources.FormatException_UseMiddleMutlipleInvokes(InvokeMethodName, InvokeAsyncMethodName));
}
if (invokeMethods.Length == 0)
{
throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoInvokeMethod(InvokeMethodName, InvokeAsyncMethodName, middleware));
}
var methodInfo = invokeMethods[0];
if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
{
throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNonTaskReturnType(InvokeMethodName, InvokeAsyncMethodName, nameof(Task)));
}
var parameters = methodInfo.GetParameters();
if (parameters.Length == 0 || parameters[0].ParameterType != typeof(HttpContext))
{
throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoParameters(InvokeMethodName, InvokeAsyncMethodName, nameof(HttpContext)));
}
var ctorArgs = new object[args.Length + 1];
ctorArgs[0] = next;
Array.Copy(args, 0, ctorArgs, 1, args.Length);
var instance = ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs);
throw new InvalidOperationException(Resources.FormatException_UseMiddleMutlipleInvokes(InvokeMethodName, InvokeAsyncMethodName));
}
if (invokeMethods.Length == 0)
{
throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoInvokeMethod(InvokeMethodName, InvokeAsyncMethodName, middleware));
}
var methodInfo = invokeMethods[0];
if (!typeof(Task).IsAssignableFrom(methodInfo.ReturnType))
{
throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNonTaskReturnType(InvokeMethodName, InvokeAsyncMethodName, nameof(Task)));
}
var parameters = methodInfo.GetParameters();
if (parameters.Length == 0 || parameters[0].ParameterType != typeof(HttpContext))
{
throw new InvalidOperationException(Resources.FormatException_UseMiddlewareNoParameters(InvokeMethodName, InvokeAsyncMethodName, nameof(HttpContext)));
}
var ctorArgs = new object[args.Length + 1];
ctorArgs[0] = next;
Array.Copy(args, 0, ctorArgs, 1, args.Length);
var instance = ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs);
/// Instantiate a type with constructor arguments provided directly and/or from an <see cref="IServiceProvider"/>.
/// </summary>
/// <param name="provider">The service provider used to resolve dependencies</param>
/// <param name="instanceType">The type to activate</param>
/// <param name="parameters">Constructor arguments not provided by the <paramref name="provider"/>.</param>
/// <returns>An activated object of type instanceType</returns>
public static object CreateInstance(IServiceProvider provider, Type instanceType, params object[] parameters)
{
int bestLength = -1;
var seenPreferred = false;
ConstructorMatcher bestMatcher = default;
if (!instanceType.GetTypeInfo().IsAbstract)
{
foreach (var constructor in instanceType
.GetTypeInfo()
.DeclaredConstructors)
{
if (!constructor.IsStatic && constructor.IsPublic)
{
var matcher = new ConstructorMatcher(constructor);
var isPreferred = constructor.IsDefined(typeof(ActivatorUtilitiesConstructorAttribute), false);
var length = matcher.Match(parameters);
if (isPreferred)
{
if (seenPreferred)
{
ThrowMultipleCtorsMarkedWithAttributeException();
}
if (length == -1)
{
ThrowMarkedCtorDoesNotTakeAllProvidedArguments();
}
}
if (isPreferred || bestLength < length)
{
bestLength = length;
bestMatcher = matcher;
}
seenPreferred |= isPreferred;
}
}
}
if (bestLength == -1)
{
var message = $"A suitable constructor for type '{instanceType}' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.";
throw new InvalidOperationException(message);
}
return bestMatcher.CreateInstance(provider);
}
/// <summary>
/// Create a delegate that will instantiate a type with constructor arguments provided directly
/// and/or from an <see cref="IServiceProvider"/>.
/// </summary>
/// <param name="instanceType">The type to activate</param>
/// <param name="argumentTypes">
/// The types of objects, in order, that will be passed to the returned function as its second parameter
/// </param>
/// <returns>
/// A factory that will instantiate instanceType using an <see cref="IServiceProvider"/>
/// and an argument array containing objects matching the types defined in argumentTypes
/// </returns>
public static ObjectFactory CreateFactory(Type instanceType, Type[] argumentTypes)
{
FindApplicableConstructor(instanceType, argumentTypes, out ConstructorInfo constructor, out int?[] parameterMap);
var provider = Expression.Parameter(typeof(IServiceProvider), "provider");
var argumentArray = Expression.Parameter(typeof(object[]), "argumentArray");
var factoryExpressionBody = BuildFactoryExpression(constructor, parameterMap, provider, argumentArray);
var factoryLamda = Expression.Lambda<Func<IServiceProvider, object[], object>>(
factoryExpressionBody, provider, argumentArray);
var result = factoryLamda.Compile();
return result.Invoke;
}
/// <summary>
/// Instantiate a type with constructor arguments provided directly and/or from an <see cref="IServiceProvider"/>.
/// </summary>
/// <typeparam name="T">The type to activate</typeparam>
/// <param name="provider">The service provider used to resolve dependencies</param>
/// <param name="parameters">Constructor arguments not provided by the <paramref name="provider"/>.</param>
/// <returns>An activated object of type T</returns>
public static T CreateInstance<T>(IServiceProvider provider, params object[] parameters)
var message = $"A suitable constructor for type '{instanceType}' could not be located. Ensure the type is concrete and services are registered for all parameters of a public constructor.";
throw new InvalidOperationException(message);
}
}
// Tries to find constructor based on provided argument types
private static bool TryFindMatchingConstructor(
Type instanceType,
Type[] argumentTypes,
ref ConstructorInfo matchingConstructor,
ref int?[] parameterMap)
{
foreach (var constructor in instanceType.GetTypeInfo().DeclaredConstructors)
{
if (constructor.IsStatic || !constructor.IsPublic)
{
continue;
}
if (TryCreateParameterMap(constructor.GetParameters(), argumentTypes, out int?[] tempParameterMap))
{
if (matchingConstructor != null)
{
throw new InvalidOperationException($"Multiple constructors accepting all given argument types have been found in type '{instanceType}'. There should only be one applicable constructor.");
}
matchingConstructor = constructor;
parameterMap = tempParameterMap;
}
}
return matchingConstructor != null;
}
// Tries to find constructor marked with ActivatorUtilitiesConstructorAttribute
private static bool TryFindPreferredConstructor(
Type instanceType,
Type[] argumentTypes,
ref ConstructorInfo matchingConstructor,
ref int?[] parameterMap)
{
var seenPreferred = false;
foreach (var constructor in instanceType.GetTypeInfo().DeclaredConstructors)
{
if (constructor.IsStatic || !constructor.IsPublic)
{
continue;
}
if (constructor.IsDefined(typeof(ActivatorUtilitiesConstructorAttribute), false))
{
if (seenPreferred)
{
ThrowMultipleCtorsMarkedWithAttributeException();
}
if (!TryCreateParameterMap(constructor.GetParameters(), argumentTypes, out int?[] tempParameterMap))
{
ThrowMarkedCtorDoesNotTakeAllProvidedArguments();
}
matchingConstructor = constructor;
parameterMap = tempParameterMap;
seenPreferred = true;
}
}
return matchingConstructor != null;
}
// Creates an injective parameterMap from givenParameterTypes to assignable constructorParameters.
// Returns true if each given parameter type is assignable to a unique; otherwise, false.
private static bool TryCreateParameterMap(ParameterInfo[] constructorParameters, Type[] argumentTypes, out int?[] parameterMap)
{
parameterMap = new int?[constructorParameters.Length];
for (var i = 0; i < argumentTypes.Length; i++)
{
var foundMatch = false;
var givenParameter = argumentTypes[i].GetTypeInfo();
for (var j = 0; j < constructorParameters.Length; j++)
{
if (parameterMap[j] != null)
{
// This ctor parameter has already been matched
continue;
}
if (constructorParameters[j].ParameterType.GetTypeInfo().IsAssignableFrom(givenParameter))
{
foundMatch = true;
parameterMap[j] = i;
break;
}
}
if (!foundMatch)
{
return false;
}
}
return true;
}
private struct ConstructorMatcher
{
private readonly ConstructorInfo _constructor;
private readonly ParameterInfo[] _parameters;
private readonly object[] _parameterValues;
public ConstructorMatcher(ConstructorInfo constructor)
{
_constructor = constructor;
_parameters = _constructor.GetParameters();
_parameterValues = new object[_parameters.Length];
}
public int Match(object[] givenParameters)
{
var applyIndexStart = 0;
var applyExactLength = 0;
for (var givenIndex = 0; givenIndex != givenParameters.Length; givenIndex++)
{
var givenType = givenParameters[givenIndex]?.GetType().GetTypeInfo();
public object CreateInstance(IServiceProvider provider)
{
for (var index = 0; index != _parameters.Length; index++)
{
if (_parameterValues[index] == null)
{
var value = provider.GetService(_parameters[index].ParameterType);
if (value == null)
{
if (!ParameterDefaultValue.TryGetDefaultValue(_parameters[index], out var defaultValue))
{
throw new InvalidOperationException($"Unable to resolve service for type '{_parameters[index].ParameterType}' while attempting to activate '{_constructor.DeclaringType}'.");
throw new InvalidOperationException($"Constructor marked with {nameof(ActivatorUtilitiesConstructorAttribute)} does not accept all given argument types.");