private DataPortalClient.IDataPortalProxy GetDataPortalProxy(Reflection.ServiceProviderMethodInfo method) { if (method != null) { return(GetDataPortalProxy(method.MethodInfo.RunLocal())); } else { return(GetDataPortalProxy(false)); } }
/// <summary> /// Find a method based on data portal criteria /// and providing any remaining parameters with /// values from an IServiceProvider /// </summary> /// <param name="targetType">Type of domain object</param> /// <param name="criteria">Data portal criteria values</param> /// <param name="throwOnError">Throw exceptions on error</param> public ServiceProviderMethodInfo FindDataPortalMethod <T>(Type targetType, object[] criteria, bool throwOnError = true) where T : DataPortalOperationAttribute { if (targetType == null) { throw new ArgumentNullException(nameof(targetType)); } var typeOfOperation = typeof(T); var cacheKey = GetCacheKeyName(targetType, typeOfOperation, criteria); if (_methodCache.TryGetValue(cacheKey, out ServiceProviderMethodInfo cachedMethod)) { if (!throwOnError || cachedMethod != null) { return(cachedMethod); } } var candidates = new List <ScoredMethodInfo>(); var factoryInfo = Csla.Server.ObjectFactoryAttribute.GetObjectFactoryAttribute(targetType); if (factoryInfo != null) { var factoryType = Csla.Server.FactoryDataPortal.FactoryLoader.GetFactoryType(factoryInfo.FactoryTypeName); var ftList = new List <System.Reflection.MethodInfo>(); var level = 0; while (factoryType != null) { ftList.Clear(); if (typeOfOperation == typeof(CreateAttribute)) { ftList.AddRange(factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == factoryInfo.CreateMethodName)); } else if (typeOfOperation == typeof(FetchAttribute)) { ftList.AddRange(factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == factoryInfo.FetchMethodName)); } else if (typeOfOperation == typeof(DeleteAttribute)) { ftList.AddRange(factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == factoryInfo.DeleteMethodName)); } else if (typeOfOperation == typeof(ExecuteAttribute)) { ftList.AddRange(factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == factoryInfo.ExecuteMethodName)); } else if (typeOfOperation == typeof(CreateChildAttribute)) { ftList.AddRange(factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == "Child_Create")); } else { ftList.AddRange(factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == factoryInfo.UpdateMethodName)); } factoryType = factoryType.BaseType; candidates.AddRange(ftList.Select(r => new ScoredMethodInfo { MethodInfo = r, Score = level })); level--; } if (!candidates.Any() && typeOfOperation == typeof(CreateChildAttribute)) { var ftlist = targetType.GetMethods(_bindingAttr).Where(m => m.Name == "Child_Create"); candidates.AddRange(ftList.Select(r => new ScoredMethodInfo { MethodInfo = r, Score = 0 })); } } else // not using factory types { var tt = targetType; var level = 0; while (tt != null) { var ttList = tt.GetMethods(_bindingAttr).Where(m => m.GetCustomAttributes <T>().Any()); candidates.AddRange(ttList.Select(r => new ScoredMethodInfo { MethodInfo = r, Score = level })); tt = tt.BaseType; level--; } // if no attribute-based methods found, look for legacy methods if (!candidates.Any()) { var attributeName = typeOfOperation.Name.Substring(0, typeOfOperation.Name.IndexOf("Attribute")); var methodName = attributeName.Contains("Child") ? "Child_" + attributeName.Substring(0, attributeName.IndexOf("Child")) : "DataPortal_" + attributeName; tt = targetType; level = 0; while (tt != null) { var ttList = tt.GetMethods(_bindingAttr).Where(m => m.Name == methodName); candidates.AddRange(ttList.Select(r => new ScoredMethodInfo { MethodInfo = r, Score = level })); tt = tt.BaseType; level--; } } } ScoredMethodInfo result = null; if (candidates != null && candidates.Any()) { // scan candidate methods for matching criteria parameters int criteriaLength = 0; if (criteria != null) { if (criteria.GetType().Equals(typeof(object[]))) { criteriaLength = criteria.GetLength(0); } else { criteriaLength = 1; } } var matches = new List <ScoredMethodInfo>(); if (criteriaLength > 0) { foreach (var item in candidates) { int score = 0; var methodParams = GetCriteriaParameters(item.MethodInfo); if (methodParams.Length == criteriaLength) { var index = 0; if (criteria.GetType().Equals(typeof(object[]))) { foreach (var c in criteria) { var currentScore = CalculateParameterScore(methodParams[index], c); if (currentScore == 0) { break; } score += currentScore; index++; } } else { var currentScore = CalculateParameterScore(methodParams[index], criteria); if (currentScore != 0) { score += currentScore; index++; } } if (index == criteriaLength) { matches.Add(new ScoredMethodInfo { MethodInfo = item.MethodInfo, Score = score + item.Score }); } } } if (matches.Count() == 0 && (typeOfOperation == typeof(DeleteSelfAttribute) || typeOfOperation == typeof(DeleteSelfChildAttribute))) { // implement zero parameter fallback if other matches not found foreach (var item in candidates) { if (GetCriteriaParameters(item.MethodInfo).Length == 0) { matches.Add(new ScoredMethodInfo { MethodInfo = item.MethodInfo, Score = item.Score }); } } } } else { foreach (var item in candidates) { if (GetCriteriaParameters(item.MethodInfo).Length == 0) { matches.Add(new ScoredMethodInfo { MethodInfo = item.MethodInfo, Score = item.Score }); } } } if (matches.Count == 0) { // look for params array foreach (var item in candidates) { var lastParam = item.MethodInfo.GetParameters().LastOrDefault(); if (lastParam != null && lastParam.ParameterType.Equals(typeof(object[])) && lastParam.GetCustomAttributes <ParamArrayAttribute>().Any()) { matches.Add(new ScoredMethodInfo { MethodInfo = item.MethodInfo, Score = 1 + item.Score }); } } } if (matches.Count > 0) { result = matches[0]; if (matches.Count > 1) { // disambiguate if necessary, using a greedy algorithm // so more DI parameters are better foreach (var item in matches) { item.Score += GetDIParameters(item.MethodInfo).Length; } var maxScore = int.MinValue; var maxCount = 0; foreach (var item in matches) { if (item.Score > maxScore) { maxScore = item.Score; maxCount = 1; result = item; } else if (item.Score == maxScore) { maxCount++; } } if (maxCount > 1) { if (throwOnError) { throw new AmbiguousMatchException($"{targetType.FullName}.[{typeOfOperation.Name.Replace("Attribute", "")}]{GetCriteriaTypeNames(criteria)}. Matches: {string.Join(", ", matches.Select(m => $"{m.MethodInfo.DeclaringType.FullName}[{m.MethodInfo}]"))}"); } else { _methodCache.TryAdd(cacheKey, null); return(null); } } } } } ServiceProviderMethodInfo resultingMethod = null; if (result != null) { resultingMethod = new ServiceProviderMethodInfo { MethodInfo = result.MethodInfo }; } else { var baseType = targetType.BaseType; if (baseType == null) { if (throwOnError) { throw new TargetParameterCountException(cacheKey); } else { _methodCache.TryAdd(cacheKey, null); return(null); } } try { resultingMethod = FindDataPortalMethod <T>(baseType, criteria, throwOnError); } catch (TargetParameterCountException ex) { throw new TargetParameterCountException(cacheKey, ex); } catch (AmbiguousMatchException ex) { throw new AmbiguousMatchException($"{targetType.FullName}.[{typeOfOperation.Name.Replace("Attribute", "")}]{GetCriteriaTypeNames(criteria)}.", ex); } } _methodCache.TryAdd(cacheKey, resultingMethod); return(resultingMethod); }
private static DataPortalClient.IDataPortalProxy GetDataPortalProxy(Type objectType, Reflection.ServiceProviderMethodInfo method) { if (method != null) { return(GetDataPortalProxy(objectType, method.MethodInfo.RunLocal())); } else { return(GetDataPortalProxy(objectType, false)); } }
/// <summary> /// Invoke a method async if possible, providing /// parameters from the params array and from DI /// </summary> /// <param name="obj">Target object</param> /// <param name="method">Method to invoke</param> /// <param name="parameters">Criteria params array</param> /// <returns></returns> public async Task <object> CallMethodTryAsync(object obj, ServiceProviderMethodInfo method, object[] parameters) { if (method == null) { throw new ArgumentNullException(obj.GetType().FullName + ".<null>() " + Resources.MethodNotImplemented); } var info = method.MethodInfo; method.PrepForInvocation(); object[] plist; if (method.TakesParamArray) { plist = new object[] { parameters }; } else { plist = new object[method.Parameters.Length]; int index = 0; int criteriaIndex = 0; var service = ApplicationContext.CurrentServiceProvider; foreach (var item in method.Parameters) { if (method.IsInjected[index]) { if (service == null) { throw new NullReferenceException(nameof(service)); } plist[index] = service.GetService(item.ParameterType); } else { if (parameters.GetType().Equals(typeof(object[]))) { if (parameters == null || parameters.Length - 1 < criteriaIndex) { plist[index] = null; } else { plist[index] = parameters[criteriaIndex]; } } else { plist[index] = parameters; } criteriaIndex++; } index++; } } try { if (method.IsAsyncTask) { await((Task)method.DynamicMethod(obj, plist)).ConfigureAwait(false); return(null); } else if (method.IsAsyncTaskObject) { return(await((Task <object>)method.DynamicMethod(obj, plist)).ConfigureAwait(false)); } else { var result = method.DynamicMethod(obj, plist); return(result); } } catch (Exception ex) { Exception inner = null; if (ex.InnerException == null) { inner = ex; } else { inner = ex.InnerException; } throw new CallMethodException(obj.GetType().Name + "." + info.Name + " " + Resources.MethodCallFailed, inner); } }
/// <summary> /// Find a method based on data portal criteria /// and providing any remaining parameters with /// values from an IServiceProvider /// </summary> /// <param name="targetType">Type of domain object</param> /// <param name="criteria">Data portal criteria values</param> /// <param name="throwOnError">Throw exceptions on error</param> public static ServiceProviderMethodInfo FindDataPortalMethod <T>(Type targetType, object[] criteria, bool throwOnError = true) where T : DataPortalOperationAttribute { if (targetType == null) { throw new ArgumentNullException(nameof(targetType)); } var typeOfOperation = typeof(T); var cacheKey = GetCacheKeyName(targetType, typeOfOperation, criteria); if (_methodCache.TryGetValue(cacheKey, out ServiceProviderMethodInfo cachedMethod)) { return(cachedMethod); } IEnumerable <System.Reflection.MethodInfo> candidates = null; var factoryInfo = Csla.Server.ObjectFactoryAttribute.GetObjectFactoryAttribute(targetType); if (factoryInfo != null) { var factoryType = Csla.Server.FactoryDataPortal.FactoryLoader.GetFactoryType(factoryInfo.FactoryTypeName); if (factoryType != null) { if (typeOfOperation == typeof(CreateAttribute)) { candidates = factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == factoryInfo.CreateMethodName); } else if (typeOfOperation == typeof(FetchAttribute)) { candidates = factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == factoryInfo.FetchMethodName); } else if (typeOfOperation == typeof(DeleteAttribute)) { candidates = factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == factoryInfo.DeleteMethodName); } else if (typeOfOperation == typeof(ExecuteAttribute)) { candidates = factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == factoryInfo.ExecuteMethodName); } else { candidates = factoryType.GetMethods(_factoryBindingAttr).Where(m => m.Name == factoryInfo.UpdateMethodName); } } } else { candidates = targetType.GetMethods(_bindingAttr). Where(m => m.GetCustomAttributes <T>().Any()); // if no attribute-based methods found, look for legacy methods if (!candidates.Any()) { var attributeName = typeOfOperation.Name.Substring(0, typeOfOperation.Name.IndexOf("Attribute")); var methodName = attributeName.Contains("Child") ? "Child_" + attributeName.Substring(0, attributeName.IndexOf("Child")) : "DataPortal_" + attributeName; candidates = targetType.GetMethods(_bindingAttr).Where( m => m.Name == methodName); } } ScoredMethodInfo result = null; if (candidates != null && candidates.Any()) { // scan candidate methods for matching criteria parameters int criteriaLength = 0; if (criteria != null) { criteriaLength = criteria.GetLength(0); } var matches = new List <ScoredMethodInfo>(); if (criteriaLength > 0) { foreach (var item in candidates) { int score = 0; var methodParams = GetCriteriaParameters(item); if (methodParams.Length == criteriaLength) { var index = 0; foreach (var c in criteria) { if (c == null) { if (methodParams[index].ParameterType.IsPrimitive) { break; } else if (methodParams[index].ParameterType == typeof(object)) { score++; } } else { if (c.GetType() == methodParams[index].ParameterType) { score += 2; } else if (methodParams[index].ParameterType.IsAssignableFrom(c.GetType())) { score++; } else { break; } } index++; } if (index == criteriaLength) { matches.Add(new ScoredMethodInfo { MethodInfo = item, Score = score }); } } } } else { foreach (var item in candidates) { if (GetCriteriaParameters(item).Length == 0) { matches.Add(new ScoredMethodInfo { MethodInfo = item }); } } } if (matches.Count == 0) { // look for params array foreach (var item in candidates) { var lastParam = item.GetParameters().LastOrDefault(); if (lastParam != null && lastParam.ParameterType.Equals(typeof(object[])) && lastParam.GetCustomAttributes <ParamArrayAttribute>().Any()) { matches.Add(new ScoredMethodInfo { MethodInfo = item, Score = 1 }); } } } if (matches.Count > 0) { result = matches[0]; if (matches.Count > 1) { // disambiguate if necessary, using a greedy algorithm // so more DI parameters are better foreach (var item in matches) { item.Score += GetDIParameters(item.MethodInfo).Length; } var maxScore = int.MinValue; var maxCount = 0; foreach (var item in matches) { if (item.Score > maxScore) { maxScore = item.Score; maxCount = 1; result = item; } else if (item.Score == maxScore) { maxCount++; } } if (maxCount > 1) { if (throwOnError) { throw new AmbiguousMatchException($"{targetType.FullName}.[{typeOfOperation.Name.Replace("Attribute", "")}]{GetCriteriaTypeNames(criteria)}. Matches: {string.Join(", ", matches.Select(m => $"{m.MethodInfo.DeclaringType.FullName}[{m.MethodInfo}]"))}"); } else { _methodCache.TryAdd(cacheKey, null); return(null); } } } } } ServiceProviderMethodInfo resultingMethod = null; if (result != null) { resultingMethod = new ServiceProviderMethodInfo { MethodInfo = result.MethodInfo }; } else { var baseType = targetType.BaseType; if (baseType == null) { if (throwOnError) { throw new TargetParameterCountException(cacheKey); } else { _methodCache.TryAdd(cacheKey, null); return(null); } } resultingMethod = FindDataPortalMethod <T>(baseType, criteria, throwOnError); } _methodCache.TryAdd(cacheKey, resultingMethod); return(resultingMethod); }