diff --git a/src/SoapCore/MembersWithAttributeCache.cs b/src/SoapCore/MembersWithAttributeCache.cs index 2a98cb1a..f88cc273 100644 --- a/src/SoapCore/MembersWithAttributeCache.cs +++ b/src/SoapCore/MembersWithAttributeCache.cs @@ -1,13 +1,14 @@ -using System; -using System.Collections.Concurrent; - -namespace SoapCore -{ - internal static partial class ReflectionExtensions - { - private static class MembersWithAttributeCache where TAttribute : Attribute - { - public static ConcurrentDictionary[]> CacheEntries = new(); - } - } -} +using System; +using System.Collections.Concurrent; + +namespace SoapCore +{ + internal static partial class ReflectionExtensions + { + private static class MembersWithAttributeCache + where TAttribute : Attribute + { + public static ConcurrentDictionary[]> CacheEntries = new(); + } + } +} diff --git a/src/SoapCore/ReflectionExtensions.cs b/src/SoapCore/ReflectionExtensions.cs index 5ea4e198..7271eda1 100644 --- a/src/SoapCore/ReflectionExtensions.cs +++ b/src/SoapCore/ReflectionExtensions.cs @@ -1,200 +1,200 @@ -using System; -using System.Collections; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using System.Runtime.Serialization; - -namespace SoapCore -{ - /// Extensions to . - internal static partial class ReflectionExtensions - { - /// Searches for the public method with the specified name and generic arguments. - /// The current . - /// The string containing the name of the public generic method to get. - /// - /// An array of types to be substituted for the type parameters of the generic method definition. - /// - /// More than one suitable method is found. - /// is null. - /// - /// A object representing the public constructed method formed by substituting the elements of for the type parameters.-or- null. - /// - internal static MethodInfo GetGenericMethod(this Type type, string name, params Type[] typeArguments) - { - if (name == null) - { - throw new ArgumentNullException(nameof(name)); - } - - if (typeArguments == null) - { - throw new ArgumentNullException(nameof(typeArguments)); - } - - if (typeArguments.Any(t => t == null)) - { - throw new ArgumentNullException(nameof(typeArguments)); - } - - var methods = type.GetMethods() - .Where(method => method.IsPublic) - .Where(method => method.IsGenericMethod) - .Where(method => method.Name == name) - .Where(method => - { - // check if genericArguments match with typeArguments - var genericArguments = method.GetGenericArguments(); - if (genericArguments.Length != typeArguments.Length) - { - return false; - } - - for (var i = 0; i < genericArguments.Length; i++) - { - var genericArgument = genericArguments[i]; - var typeArgument = typeArguments[i]; - if (!genericArgument.GetGenericParameterConstraints().All(constraint => constraint.IsAssignableFrom(typeArgument))) - { - return false; - } - } - - return true; - }); - MethodInfo result = null; - foreach (var method in methods) - { - if (result != null) - { - throw new AmbiguousMatchException(); - } - - result = method; - } - - return result?.MakeGenericMethod(typeArguments); - } - - /// - /// Gets the field or property members of the specific type. - /// - /// The type to look for field or property members for - /// An enumerable containing members which are fields or properties - internal static IEnumerable GetPropertyOrFieldMembers(this Type type) => - type.GetFields() - .Cast() - .Concat(type.GetProperties()); - - /// - /// Gets the field or property type of a member. Returns null if the member is neither a field or - /// a property member - /// - /// The member to get the field or property type - /// The return type of the member, null if it could not be determined - internal static Type GetPropertyOrFieldType(this MemberInfo memberInfo) - { - if (memberInfo is FieldInfo fi) - { - return fi.FieldType; - } - - if (memberInfo is PropertyInfo pi) - { - return pi.PropertyType; - } - - return null; - } - - internal static void SetValueToPropertyOrField(this MemberInfo memberInfo, object obj, object value) - { - if (memberInfo is FieldInfo fi) - { - fi.SetValue(obj, value); - } - else if (memberInfo is PropertyInfo pi) - { - pi.SetValue(obj, value); - } - else - { - throw new NotImplementedException("Cannot set value of parameter type from " + memberInfo.GetType()?.Name); - } - } - - internal static object GetPropertyOrFieldValue(this MemberInfo memberInfo, object obj) - { - if (memberInfo is FieldInfo fi) - { - return fi.GetValue(obj); - } - - if (memberInfo is PropertyInfo pi) - { - return pi.GetValue(obj); - } - - throw new NotImplementedException($"Unable to get value out of member with type {memberInfo.GetType()}"); - } - - internal static IEnumerable> GetMembersWithAttribute(this Type type) - where TAttribute : Attribute - { - // return from p in GetPropertyOrFieldMembers(type) - // let attr = p.GetCustomAttribute() - // where attr != null - // select new MemberWithAttribute(p, attr); - return MembersWithAttributeCache.CacheEntries.GetOrAdd(type, ComputeMembersWithAttribute); - } - - private static MemberWithAttribute[] ComputeMembersWithAttribute(Type type) - where TAttribute : Attribute - { - var res = from p in GetPropertyOrFieldMembers(type) - let attr = p.GetCustomAttribute() - where attr != null - select new MemberWithAttribute(p, attr); - - return res.ToArray(); - } - - internal static bool TryGetBaseTypeWithKnownTypes(this Type type, out Type result) - { - if (type is null) - { - throw new ArgumentNullException(nameof(type)); - } - - if (type.IsEnum || type.IsPrimitive || type.IsValueType) - { - result = null; - return false; - } - - if (type.IsArray || typeof(IEnumerable).IsAssignableFrom(type)) - { - result = null; - return false; - } - - Type baseType = type.GetTypeInfo().BaseType; - if (baseType is null || baseType.Name.Equals("Object")) - { - result = null; - return false; - } - - bool hasKnownTypes = baseType - .GetCustomAttributes() - .Any(); - - result = hasKnownTypes - ? baseType - : null; - return hasKnownTypes; - } - } -} +using System; +using System.Collections; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Runtime.Serialization; + +namespace SoapCore +{ + /// Extensions to . + internal static partial class ReflectionExtensions + { + /// Searches for the public method with the specified name and generic arguments. + /// The current . + /// The string containing the name of the public generic method to get. + /// + /// An array of types to be substituted for the type parameters of the generic method definition. + /// + /// More than one suitable method is found. + /// is null. + /// + /// A object representing the public constructed method formed by substituting the elements of for the type parameters.-or- null. + /// + internal static MethodInfo GetGenericMethod(this Type type, string name, params Type[] typeArguments) + { + if (name == null) + { + throw new ArgumentNullException(nameof(name)); + } + + if (typeArguments == null) + { + throw new ArgumentNullException(nameof(typeArguments)); + } + + if (typeArguments.Any(t => t == null)) + { + throw new ArgumentNullException(nameof(typeArguments)); + } + + var methods = type.GetMethods() + .Where(method => method.IsPublic) + .Where(method => method.IsGenericMethod) + .Where(method => method.Name == name) + .Where(method => + { + // check if genericArguments match with typeArguments + var genericArguments = method.GetGenericArguments(); + if (genericArguments.Length != typeArguments.Length) + { + return false; + } + + for (var i = 0; i < genericArguments.Length; i++) + { + var genericArgument = genericArguments[i]; + var typeArgument = typeArguments[i]; + if (!genericArgument.GetGenericParameterConstraints().All(constraint => constraint.IsAssignableFrom(typeArgument))) + { + return false; + } + } + + return true; + }); + MethodInfo result = null; + foreach (var method in methods) + { + if (result != null) + { + throw new AmbiguousMatchException(); + } + + result = method; + } + + return result?.MakeGenericMethod(typeArguments); + } + + /// + /// Gets the field or property members of the specific type. + /// + /// The type to look for field or property members for + /// An enumerable containing members which are fields or properties + internal static IEnumerable GetPropertyOrFieldMembers(this Type type) => + type.GetFields() + .Cast() + .Concat(type.GetProperties()); + + /// + /// Gets the field or property type of a member. Returns null if the member is neither a field or + /// a property member + /// + /// The member to get the field or property type + /// The return type of the member, null if it could not be determined + internal static Type GetPropertyOrFieldType(this MemberInfo memberInfo) + { + if (memberInfo is FieldInfo fi) + { + return fi.FieldType; + } + + if (memberInfo is PropertyInfo pi) + { + return pi.PropertyType; + } + + return null; + } + + internal static void SetValueToPropertyOrField(this MemberInfo memberInfo, object obj, object value) + { + if (memberInfo is FieldInfo fi) + { + fi.SetValue(obj, value); + } + else if (memberInfo is PropertyInfo pi) + { + pi.SetValue(obj, value); + } + else + { + throw new NotImplementedException("Cannot set value of parameter type from " + memberInfo.GetType()?.Name); + } + } + + internal static object GetPropertyOrFieldValue(this MemberInfo memberInfo, object obj) + { + if (memberInfo is FieldInfo fi) + { + return fi.GetValue(obj); + } + + if (memberInfo is PropertyInfo pi) + { + return pi.GetValue(obj); + } + + throw new NotImplementedException($"Unable to get value out of member with type {memberInfo.GetType()}"); + } + + internal static IEnumerable> GetMembersWithAttribute(this Type type) + where TAttribute : Attribute + { + // return from p in GetPropertyOrFieldMembers(type) + // let attr = p.GetCustomAttribute() + // where attr != null + // select new MemberWithAttribute(p, attr); + return MembersWithAttributeCache.CacheEntries.GetOrAdd(type, ComputeMembersWithAttribute); + } + + private static MemberWithAttribute[] ComputeMembersWithAttribute(Type type) + where TAttribute : Attribute + { + var res = from p in GetPropertyOrFieldMembers(type) + let attr = p.GetCustomAttribute() + where attr != null + select new MemberWithAttribute(p, attr); + + return res.ToArray(); + } + + internal static bool TryGetBaseTypeWithKnownTypes(this Type type, out Type result) + { + if (type is null) + { + throw new ArgumentNullException(nameof(type)); + } + + if (type.IsEnum || type.IsPrimitive || type.IsValueType) + { + result = null; + return false; + } + + if (type.IsArray || typeof(IEnumerable).IsAssignableFrom(type)) + { + result = null; + return false; + } + + Type baseType = type.GetTypeInfo().BaseType; + if (baseType is null || baseType.Name.Equals("Object")) + { + result = null; + return false; + } + + bool hasKnownTypes = baseType + .GetCustomAttributes() + .Any(); + + result = hasKnownTypes + ? baseType + : null; + return hasKnownTypes; + } + } +} diff --git a/src/SoapCore/SoapEndpointExtensions.cs b/src/SoapCore/SoapEndpointExtensions.cs index e2b30ca9..47ab82aa 100644 --- a/src/SoapCore/SoapEndpointExtensions.cs +++ b/src/SoapCore/SoapEndpointExtensions.cs @@ -145,7 +145,7 @@ public static IEndpointConventionBuilder UseSoapEndpoint(this IEnd } public static IEndpointConventionBuilder UseSoapEndpoint(this IEndpointRouteBuilder routes, string path, SoapEncoderOptions[] encoders, SoapSerializer serializer = SoapSerializer.DataContractSerializer, bool caseInsensitivePath = false, ISoapModelBounder soapModelBounder = null, WsdlFileOptions wsdlFileOptions = null, bool indentXml = true, bool omitXmlDeclaration = true, string schemeOverride = null) - where T_MESSAGE : CustomMessage, new() + where T_MESSAGE : CustomMessage, new() { return routes.UseSoapEndpoint(opt => {