示例#1
0
        public static ServerMethodPluginRegistration Create(string pluginAssemblyInstanceId, PluginInfo pluginInfo)
        {
            var reg = new ServerMethodPluginRegistration(pluginInfo.Assembly, pluginInfo.TypeInfo, pluginInfo.Guid, pluginAssemblyInstanceId);

            var classLevelAttrib = pluginInfo.TypeInfo.GetCustomAttribute(typeof(ServerMethodAttribute)) as ServerMethodAttribute;

            // static methods not supported
            var methods = pluginInfo.TypeInfo.GetMethods(BindingFlags.Public /* | BindingFlags.Static*/ | BindingFlags.Instance);

            string classLevelNamespace = classLevelAttrib?.Namespace;

            var serverMethodCollection = (from mi in methods
                                          select new
            {
                MethodInfo = mi,
                ServerMethodAttribute = mi.GetCustomAttribute(typeof(ServerMethodAttribute)) as ServerMethodAttribute
            })
                                         .Where(m => m.ServerMethodAttribute != null);

            if (serverMethodCollection.Count() == 0)
            {
                SessionLog.Warning($"No server method's found in plugin '{pluginInfo.Name}' ({pluginInfo.Guid}) from assembly {pluginInfo.Assembly.FullName}. Add a [ServerMethod] attribute to the methods you want to expose.");
            }
            else
            {
                foreach (var m in serverMethodCollection)
                {
                    string ns = m.ServerMethodAttribute?.Namespace;

                    if (ns == null)
                    {
                        ns = classLevelNamespace;
                    }

                    reg.AddMethod(m.MethodInfo.Name, ns, m.MethodInfo);
                }
            }

            reg.ScriptGenerator = ServerMethodScriptGenerator.Create(reg, pluginInfo);


            return(reg);
        }
示例#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);
        }