Example #1
0
        public void BuildAndCacheServerMethodJsAndTSD()
        {
            try
            {
                var registrations = ServerMethodManager.GetRegistrationsForApp(this);

                if (registrations.Count() > 0)
                {
                    this.GenerateX(registrations);
                }
                else
                {
                    this.ServerMethodJs = this.ServerMethodTSD = this.ServerMethodJsEtag = this.ServerMethodTSDEtag = null;
                }
            }
            catch (Exception ex)
            {
                SessionLog.Error($"Failed to generate ServerMethod output files for {this.Project.Name}/{this.Name}.See exception that follows.");
                SessionLog.Exception(ex);
            }
        }
Example #2
0
        public (plugin.ServerMethodPlugin, ServerMethodRegistrationMethod /*matched Method*/, string /*error*/) GetServerMethodPluginInstance(string nameSpace,
                                                                                                                                              string methodName, Dictionary <string, string> inputParameters)
        {
            // find all registered ServerMethods for this app
            var registrations = ServerMethodManager.GetRegistrationsForApp(this.Application);

            // TODO: To support overloading we need to match name + best fit parameter list
            var methodCandidates = registrations.SelectMany(reg => reg.Methods)
                                   .Where(m => ((nameSpace == null && m.Namespace == null) || (m.Namespace?.Equals(nameSpace, StringComparison.Ordinal) ?? false)) && m.Name.Equals(methodName, StringComparison.Ordinal))
                                   .Select(m => m);

            if (methodCandidates.Count() == 0)
            {
                return(null, null, "Method name not found.");
            }

            var weightedMethodList = new List <(decimal /*weight*/, string /*error*/, ServerMethodRegistrationMethod)>();

            // find the best matching overload (if any)
            foreach (var regMethod in methodCandidates)
            {
                var methodParameters = regMethod.AssemblyMethodInfo.GetParameters();

                if (inputParameters.Count > methodParameters.Length)
                {
                    weightedMethodList.Add((1M, "Too many parameters specified", regMethod));
                    continue;
                }

                var joined = from methodParam in methodParameters
                             join inputParam in inputParameters on methodParam.Name equals inputParam.Key into grp
                             from parm in grp.DefaultIfEmpty()
                             select new { HasMatch = parm.Key != null, Param = methodParam };

                var matched    = joined.Where(e => e.HasMatch);
                var notmatched = joined.Where(e => !e.HasMatch);


                var expectedCnt = methodParameters.Count();
                var matchedCnt  = matched.Count();

                // out/ref/optional parameters are added as extra credit below (but does not contribute to actual weight)
                var outRefSum = (from p in joined
                                 where (p.Param.IsOut || p.Param.IsOptional || p.Param.ParameterType.IsByRef) && !p.HasMatch
                                 select 1.0M).Sum();


                if (matchedCnt == expectedCnt || matchedCnt + outRefSum == expectedCnt)
                {
                    weightedMethodList.Add((matchedCnt, null, regMethod));
                }
                else
                {
                    //weightedMethodList.Add((matchedCnt, $"Following parameters not specified: {string.Join("\r\n", notmatched.Select(nm => nm.Param.Name))}", regMethod));
                    weightedMethodList.Add((matchedCnt, "Parameter mismatch", regMethod));
                }
            }

            var bestMatch = weightedMethodList.OrderByDescending(k => k.Item1).FirstOrDefault();

            if (!string.IsNullOrWhiteSpace(bestMatch.Item2))
            {
                var parms    = bestMatch.Item3.AssemblyMethodInfo.GetParameters();
                var parmDesc = "(no parameters)";
                if (parms.Length > 0)
                {
                    parmDesc = string.Join("\r\n", parms.Select(p => $"{p.Name} ({p.ParameterType.ToString()})")); // TODO: Provide "easy to read" description for type, e.g. nullabe Int32 can be something like 'int?' and 'List<string>' just 'string[]'
                }

                return(null, bestMatch.Item3, $"Failed to find suitable overload.\r\nError: {bestMatch.Item2}\r\nBest match requires parameters:\r\n{parmDesc}");
            }

            var matchedRegMethod = bestMatch.Item3;

            var cacheKey = $"{matchedRegMethod.Registration.PluginAssemblyInstanceId}; {matchedRegMethod.Registration.TypeInfo.FullName}";

            plugin.ServerMethodPlugin pluginInstance = null;

            lock (ServerMethodInstanceCache)
            {
                if (ServerMethodInstanceCache.ContainsKey(cacheKey))
                {
                    pluginInstance = ServerMethodInstanceCache[cacheKey];
                }
                else // instantiate a new instance
                {
                    try
                    {
                        pluginInstance = (plugin.ServerMethodPlugin)matchedRegMethod.Registration.Assembly.CreateInstance(matchedRegMethod.Registration.TypeInfo.FullName);
                        var initMethod = typeof(plugin.ServerMethodPlugin).GetMethod("InitSM", BindingFlags.Instance | BindingFlags.NonPublic);

                        if (initMethod != null)
                        {
                            initMethod.Invoke(pluginInstance, new object[] {
                                new Func <SqlConnection>(() => {
                                    if (this.ExecutionConnection != null)
                                    {
                                        var con = new SqlConnection(this.ExecutionConnection.ConnectionStringDecrypted);

                                        con.Open();

                                        return(con);
                                    }

                                    return(new SqlConnection());
                                })
                            });
                        }
                        else
                        {
                            SessionLog.Warning($"Failed to find InitSM method on plugin {matchedRegMethod.Registration.TypeInfo.FullName} from assembly {matchedRegMethod.Registration.Assembly.FullName}. Make sure the correct version of the jsdal plugin is used and that you derive from the correct base class (should be ServerMethodPlugin).");
                        }

                        var setGetServicesFuncMethod = typeof(plugin.PluginBase).GetMethod("SetGetServicesFunc", BindingFlags.Instance | BindingFlags.NonPublic);

                        if (setGetServicesFuncMethod != null)
                        {
                            setGetServicesFuncMethod.Invoke(pluginInstance, new object[] { new Func <Type, plugin.PluginService>(serviceType =>
                                {
                                    if (serviceType == typeof(plugin.BlobStoreBase))
                                    {
                                        return(BlobStore.Instance);
                                    }

                                    return(null);
                                }) });
                        }

                        ServerMethodManager.RegisterInstanceUse(this, matchedRegMethod);
                        ServerMethodInstanceCache.Add(cacheKey, pluginInstance);
                    }
                    catch (Exception ex)
                    {
                        SessionLog.Error($"Failed to instantiate plugin {matchedRegMethod.Registration.TypeInfo.FullName} from assembly {matchedRegMethod.Registration.Assembly.FullName}. See exception that follows.");
                        SessionLog.Exception(ex);
                    }
                }
            } // lock

            return(pluginInstance, matchedRegMethod, null);
        }