/// <summary> /// 启动 XNCF 模块引擎,包括初始化扫描和注册等过程 /// </summary> /// <returns></returns> public static string StartEngine(this IServiceCollection services, IConfiguration configuration) { StringBuilder sb = new StringBuilder(); sb.AppendLine($"[{SystemTime.Now}] 开始初始化扫描 XncfModules"); var scanTypesCount = 0; var hideTypeCount = 0; ConcurrentDictionary <Type, ScanTypeKind> types = new ConcurrentDictionary <Type, ScanTypeKind>(); //所有 XNCF 模块,包括被忽略的。 //var cache = CacheStrategyFactory.GetObjectCacheStrategyInstance(); //using (cache.BeginCacheLock("Senparc.Ncf.XncfBase.Register", "Scan")) //在注册阶段还未完成缓存配置 { try { //遍历所有程序集 foreach (var a in AppDomain.CurrentDomain.GetAssemblies()) { scanTypesCount++; var aTypes = a.GetTypes(); foreach (var t in aTypes) { if (t.IsAbstract) { continue; } if (t.GetInterfaces().Contains(typeof(IXncfRegister))) { types[t] = ScanTypeKind.IXncfRegister; } else if (t.GetInterfaces().Contains(typeof(IXncfFunction))) { types[t] = ScanTypeKind.IXncfFunction; /* 暂时不收录处理 */ } else if (t.GetCustomAttributes(true).FirstOrDefault(z => z is XncfAutoConfigurationMappingAttribute) != null /*&& t.GetInterfaces().Contains(typeof(IEntityTypeConfiguration<>))*/) { types[t] = ScanTypeKind.XncfAutoConfigurationMappingAttribute; } } } } catch (Exception ex) { Console.WriteLine($"扫描程集异常退出,可能无法获得完整程序集信息:{ex.Message}"); } sb.AppendLine($"[{SystemTime.Now}] 满足条件对象:{types.Count()}"); //先注册 XncfRegister { //筛选 var allTypes = types.Where(z => z.Value == ScanTypeKind.IXncfRegister /* && z.Key.GetInterfaces().Contains(typeof(IXncfRegister))*/) .Select(z => z.Key); //按照优先级进行排序 var orderedTypes = allTypes.OrderByDescending(z => { var orderAttribute = z.GetCustomAttributes(true).FirstOrDefault(attr => attr is XncfOrderAttribute) as XncfOrderAttribute; if (orderAttribute != null) { return(orderAttribute.Order); } return(0); }); foreach (var type in orderedTypes) { sb.AppendLine($"[{SystemTime.Now}] 扫描到 IXncfRegister:{type.FullName}"); var register = type.Assembly.CreateInstance(type.FullName) as IXncfRegister; if (!RegisterList.Contains(register)) { if (RegisterList.Exists(z => z.Uid.Equals(register.Uid, StringComparison.OrdinalIgnoreCase))) { throw new XncfFunctionException("已经存在相同 Uid 的模块:" + register.Uid); } if (register.IgnoreInstall) { hideTypeCount++; } RegisterList.Add(register); //只有允许安装的才进行注册,否则执行完即结束 services.AddScoped(type); //DI 中注册 foreach (var functionType in register.Functions) { services.AddScoped(functionType);//DI 中注册 } } } #region 暂时不收录 IXncfFunction /* 暂时不收录 */ ////再扫描具体方法 //foreach (var type in types.Where(z => z != null && z.GetInterfaces().Contains(typeof(IXncfFunction)))) //{ // sb.AppendLine($"[{SystemTime.Now}] 扫描到 IXncfFunction:{type.FullName}"); // if (!ModuleFunctionCollection.ContainsKey(type)) // { // throw new NCFExceptionBase($"{type.FullName} 未能提供正确的注册方法!"); // } // var function = type as IXncfFunction; // ModuleFunctionCollection[type].Add(function); //} #endregion } //处理 XncfAutoConfigurationMappingAttribute { var allTypes = types.Where(z => z.Value == ScanTypeKind.XncfAutoConfigurationMappingAttribute).Select(z => z.Key); foreach (var type in allTypes) { var obj = type.Assembly.CreateInstance(type.FullName); XncfAutoConfigurationMappingList.Add(obj /*as IEntityTypeConfiguration<EntityBase>*/); } } } var scanResult = "初始化扫描结束,共扫描 {scanTypesCount} 个程序集"; if (hideTypeCount > 0) { scanResult += $"。其中 {hideTypeCount} 个程序集为非安装程序集,不会被缓存"; } sb.AppendLine($"[{SystemTime.Now}] {scanResult}"); //Repository & Service services.AddScoped(typeof(Senparc.Ncf.Repository.IRepositoryBase <>), typeof(Senparc.Ncf.Repository.RepositoryBase <>)); services.AddScoped(typeof(ServiceBase <>)); services.AddScoped(typeof(IServiceBase <>), typeof(ServiceBase <>)); //ConfigurationMapping services.AddScoped(typeof(ConfigurationMappingBase <>)); services.AddScoped(typeof(ConfigurationMappingWithIdBase <,>)); //微模块进行 Service 注册 foreach (var xncfRegister in RegisterList) { xncfRegister.AddXncfModule(services, configuration); } sb.AppendLine($"[{SystemTime.Now}] 完成模块 services.AddXncfModule():共扫描 {scanTypesCount} 个程序集"); //支持 AutoMapper //引入当前系统 services.AddAutoMapper(z => z.AddProfile <Core.AutoMapper.SystemProfile>()); //引入所有模块 services.AddAutoMapper(z => z.AddProfile <AutoMapper.XncfModuleProfile>()); return(sb.ToString()); }
/// <summary> /// 启动 XSCF 模块引擎,包括初始化扫描和注册等过程,通常在 Startup.cs 中的 ConfigureServices() 方法中执行 /// </summary> /// <returns></returns> public static string StartEngine(this IServiceCollection services, IConfiguration configuration) { StringBuilder sb = new StringBuilder(); sb.AppendLine($"[{SystemTime.Now}] 开始初始化扫描 XscfModules"); var scanTypesCount = 0; var hideTypeCount = 0; IEnumerable <Type> types = null; //所有 XSCF 模块,包括被忽略的。 //var cache = CacheStrategyFactory.GetObjectCacheStrategyInstance(); //using (cache.BeginCacheLock("Senparc.Scf.XscfBase.Register", "Scan")) //在注册阶段还未完成缓存配置 { try { types = AppDomain.CurrentDomain.GetAssemblies() .SelectMany(a => { try { scanTypesCount++; var aTypes = a.GetTypes(); return(aTypes.Where(t => !t.IsAbstract && (t.GetInterfaces().Contains(typeof(IXscfRegister)) || t.GetInterfaces().Contains(typeof(IXscfFunction) /* 暂时不收录 */) ))); } catch (Exception ex) { sb.AppendLine($"[{SystemTime.Now}] 自动扫描程序集异常:" + a.FullName); SenparcTrace.SendCustomLog("XscfRegister() 自动扫描程序集异常:" + a.FullName, ex.ToString()); return(new List <Type>()); //不能 return null } }); } catch (Exception ex) { Console.WriteLine($"扫描程集异常退出,可能无法获得完整程序集信息:{ex.Message}"); } if (types != null) { sb.AppendLine($"[{SystemTime.Now}] 满足条件对象:{types.Count()}"); //先注册 XscfRegister //筛选 var allTypes = types.Where(z => z != null && z.GetInterfaces().Contains(typeof(IXscfRegister))); //按照优先级进行排序 var orderedTypes = allTypes.OrderByDescending(z => { var orderAttribute = z.GetCustomAttributes(true).FirstOrDefault(z => z is XscfOrderAttribute) as XscfOrderAttribute; if (orderAttribute != null) { return(orderAttribute.Order); } return(0); }); foreach (var type in orderedTypes) { sb.AppendLine($"[{SystemTime.Now}] 扫描到 IXscfRegister:{type.FullName}"); var register = type.Assembly.CreateInstance(type.FullName) as IXscfRegister; if (!RegisterList.Contains(register)) { if (RegisterList.Exists(z => z.Uid.Equals(register.Uid, StringComparison.OrdinalIgnoreCase))) { throw new XscfFunctionException("已经存在相同 Uid 的模块:" + register.Uid); } if (register.IgnoreInstall) { hideTypeCount++; } RegisterList.Add(register); //只有允许安装的才进行注册,否则执行完即结束 services.AddScoped(type); //DI 中注册 foreach (var functionType in register.Functions) { services.AddScoped(functionType);//DI 中注册 } } } /* 暂时不收录 */ ////再扫描具体方法 //foreach (var type in types.Where(z => z != null && z.GetInterfaces().Contains(typeof(IXscfFunction)))) //{ // sb.AppendLine($"[{SystemTime.Now}] 扫描到 IXscfFunction:{type.FullName}"); // if (!ModuleFunctionCollection.ContainsKey(type)) // { // throw new SCFExceptionBase($"{type.FullName} 未能提供正确的注册方法!"); // } // var function = type as IXscfFunction; // ModuleFunctionCollection[type].Add(function); //} } } var scanResult = "初始化扫描结束,共扫描 {scanTypesCount} 个程序集"; if (hideTypeCount > 0) { scanResult += $"。其中 {hideTypeCount} 个程序集为非安装程序集,不会被缓存"; } sb.AppendLine($"[{SystemTime.Now}] {scanResult}"); //微模块进行 Service 注册 foreach (var xscfRegister in RegisterList) { xscfRegister.AddXscfModule(services, configuration); } sb.AppendLine($"[{SystemTime.Now}] 完成模块 services.AddXscfModule():共扫描 {scanTypesCount} 个程序集"); //支持 AutoMapper //引入当前系统 services.AddAutoMapper(z => z.AddProfile <Core.AutoMapper.SystemProfile>()); //引入所有模块 services.AddAutoMapper(z => z.AddProfile <AutoMapper.XscfModuleProfile>()); return(sb.ToString()); }
private string TokenMatchHandler(Match m) { string TOKEN_PROC = Util.GetLocalizedString("ProcessToken"); string TOKEN_SKIN = Util.GetLocalizedString("SkinToken"); string TOKEN_PANE = Util.GetLocalizedString("PaneToken"); string TOKEN_FOUND = Util.GetLocalizedString("TokenFound"); string TOKEN_FORMAT = Util.GetLocalizedString("TokenFormat"); string TOKEN_NOTFOUND_INFILE = Util.GetLocalizedString("TokenNotFoundInFile"); string CONTROL_FORMAT = Util.GetLocalizedString("ControlFormat"); string TOKEN_NOTFOUND = Util.GetLocalizedString("TokenNotFound"); string Token = m.Groups["token"].Value.ToUpper(); string ControlName = Token + m.Groups["instance"].Value; string AttributeNode = Token + (String.IsNullOrEmpty(m.Groups["instance"].Value) ? "" : ":" + m.Groups["instance"].Value); this.Messages += SkinController.FormatMessage(TOKEN_PROC, "[" + AttributeNode + "]", 2, false); if (this.ControlList.ContainsKey(Token) == true || Token.IndexOf("CONTENTPANE") != -1) { string SkinControl = ""; if (this.ControlList.ContainsKey(Token)) { this.Messages += SkinController.FormatMessage(TOKEN_SKIN, (string)this.ControlList[Token], 2, false); } else { this.Messages += SkinController.FormatMessage(TOKEN_PANE, Token, 2, false); } if (this.Attributes.DocumentElement != null) { XmlNode xmlSkinAttributeRoot = this.Attributes.DocumentElement.SelectSingleNode("descendant::Object[Token='[" + AttributeNode + "]']"); if (xmlSkinAttributeRoot != null) { this.Messages += SkinController.FormatMessage(TOKEN_FOUND, "[" + AttributeNode + "]", 2, false); foreach (XmlNode xmlSkinAttribute in xmlSkinAttributeRoot.SelectNodes(".//Settings/Setting")) { if (!String.IsNullOrEmpty(xmlSkinAttribute.SelectSingleNode("Value").InnerText)) { this.Messages += SkinController.FormatMessage(TOKEN_FORMAT, xmlSkinAttribute.SelectSingleNode("Name").InnerText + "=\"" + xmlSkinAttribute.SelectSingleNode("Value").InnerText + "\"", 2, false); SkinControl += " " + xmlSkinAttribute.SelectSingleNode("Name").InnerText + "=\"" + xmlSkinAttribute.SelectSingleNode("Value").InnerText.Replace("\"", """) + "\""; } } } else { this.Messages += SkinController.FormatMessage(TOKEN_NOTFOUND_INFILE, "[" + AttributeNode + "]", 2, false); } } if (this.ControlList.ContainsKey(Token)) { SkinControl = "dnn:" + Token + " runat=\"server\" id=\"dnn" + ControlName + "\"" + SkinControl; string ControlRegistration = "<%@ Register TagPrefix=\"dnn\" TagName=\"" + Token + "\" Src=\"~/" + (string)this.ControlList[Token] + "\" %>" + Environment.NewLine; if (RegisterList.Contains(ControlRegistration) == false) { RegisterList.Add(ControlRegistration); } this.Messages += SkinController.FormatMessage(CONTROL_FORMAT, "<" + SkinControl + " />", 2, false); SkinControl = "<" + SkinControl + " />"; } else { if (SkinControl.ToLower().IndexOf("id=") == -1) { SkinControl = " id=\"ContentPane\""; } SkinControl = "div runat=\"server\"" + SkinControl + "></div"; this.Messages += SkinController.FormatMessage(CONTROL_FORMAT, "<" + SkinControl + ">", 2, false); SkinControl = "<" + SkinControl + ">"; } return(SkinControl); } else { this.Messages += SkinController.FormatMessage(TOKEN_NOTFOUND, "[" + m.Groups["token"].Value + "]", 2, false); return("[" + m.Groups["token"].Value + "]"); } }
private string ObjectMatchHandler(Match m) { string OBJECT_PROC = Util.GetLocalizedString("ProcessObject"); string OBJECT_SKIN = Util.GetLocalizedString("SkinObject"); string OBJECT_PANE = Util.GetLocalizedString("PaneObject"); string OBJECT_FOUND = Util.GetLocalizedString("ObjectFound"); string CONTROL_FORMAT = Util.GetLocalizedString("ControlFormat"); string OBJECT_NOTFOUND = Util.GetLocalizedString("ObjectNotFound"); string EmbeddedObjectAttributes = m.Groups["token"].Value.Substring(0, m.Groups["token"].Value.IndexOf(">")); string[] Attributes = EmbeddedObjectAttributes.Split(' '); string AttributeNode = ""; string Token = ""; string ControlName = ""; string[] Attribute; string AttributeName; string AttributeValue; foreach (string strAttribute in Attributes) { if (strAttribute != string.Empty) { Attribute = strAttribute.Split('='); AttributeName = Attribute[0].Trim(); AttributeValue = Attribute[1].Trim().Replace("\"", ""); switch (AttributeName.ToLower()) { case "id": ControlName = AttributeValue; break; case "codetype": AttributeNode = AttributeValue; break; case "codebase": Token = AttributeValue.ToUpper(); break; } } } if (AttributeNode.ToLower() == "dotnetnuke/server") { this.Messages += SkinController.FormatMessage(OBJECT_PROC, Token, 2, false); if (this.ControlList.ContainsKey(Token) == true || Token == "CONTENTPANE") { string SkinControl = ""; if (this.ControlList.ContainsKey(Token)) { this.Messages += SkinController.FormatMessage(OBJECT_SKIN, (string)this.ControlList[Token], 2, false); } else { this.Messages += SkinController.FormatMessage(OBJECT_PANE, Token, 2, false); } string Parameters = m.Groups["token"].Value.Substring(m.Groups["token"].Value.IndexOf(">") + 1); Parameters = Parameters.Replace("<param name=\"", ""); Parameters = Parameters.Replace("\" value", ""); Parameters = Parameters.Replace("/>", ""); Parameters = Regex.Replace(Parameters, "\\s+", " "); if (this.ControlList.ContainsKey(Token)) { SkinControl = "dnn:" + Token + " runat=\"server\" "; if (!String.IsNullOrEmpty(ControlName)) { SkinControl += "id=\"" + ControlName + "\" "; } SkinControl += Parameters; string ControlRegistration = "<%@ Register TagPrefix=\"dnn\" TagName=\"" + Token + "\" Src=\"~/" + (string)this.ControlList[Token] + "\" %>" + Environment.NewLine; if (RegisterList.Contains(ControlRegistration) == false) { RegisterList.Add(ControlRegistration); } this.Messages += SkinController.FormatMessage(CONTROL_FORMAT, "<" + SkinControl + " />", 2, false); SkinControl = "<" + SkinControl + "/>"; } else { SkinControl = "div runat=\"server\" "; if (!String.IsNullOrEmpty(ControlName)) { SkinControl += "id=\"" + ControlName + "\" "; } else { SkinControl += "id=\"ContentPane\" "; } SkinControl += Parameters + "></div"; this.Messages += SkinController.FormatMessage(CONTROL_FORMAT, "<" + SkinControl + ">", 2, false); SkinControl = "<" + SkinControl + ">"; } return(SkinControl); } else { this.Messages += SkinController.FormatMessage(OBJECT_NOTFOUND, Token, 2, false); return("<object" + m.Groups["token"].Value + "</object>"); } } else { return("<object" + m.Groups["token"].Value + "</object>"); } }
/// <summary> /// Process regular expression matches. /// </summary> /// <param name="m">Regular expression match for token which requires processing.</param> /// <returns>Properly formatted token.</returns> /// <remarks> /// The handler is invoked by the Regex.Replace method once for each match that /// it encounters. The returned value of the handler is substituted for the /// original match. So the handler properly formats the replacement for the /// token and returns it instead. If an unknown token is encountered, the token /// is unmodified. This can happen if a token is used for a skin object which /// has not yet been installed. /// </remarks> private string TokenMatchHandler(Match m) { string TOKEN_PROC = Localization.GetString("ProcessToken", Globals.GetPortalSettings()); string TOKEN_SKIN = Localization.GetString("SkinToken", Globals.GetPortalSettings()); string TOKEN_PANE = Localization.GetString("PaneToken", Globals.GetPortalSettings()); string TOKEN_FOUND = Localization.GetString("TokenFound", Globals.GetPortalSettings()); string TOKEN_FORMAT = Localization.GetString("TokenFormat", Globals.GetPortalSettings()); string TOKEN_NOTFOUND_INFILE = Localization.GetString("TokenNotFoundInFile", Globals.GetPortalSettings()); string CONTROL_FORMAT = Localization.GetString("ControlFormat", Globals.GetPortalSettings()); string TOKEN_NOTFOUND = Localization.GetString("TokenNotFound", Globals.GetPortalSettings()); string Token = m.Groups["token"].Value.ToUpper(); string ControlName = Token + m.Groups["instance"].Value; // if the token has an instance name, use it to look for the corresponding attributes string AttributeNode = Token + Convert.ToString((m.Groups["instance"].Value == "") ? "" : (":" + m.Groups["instance"].Value)); this.Messages += SkinController.FormatMessage(TOKEN_PROC, "[" + AttributeNode + "]", 2, false); // if the token is a recognized skin control if (this.ControlList.ContainsKey(Token) == true || Token.IndexOf("CONTENTPANE") != -1) { string SkinControl = ""; if (this.ControlList.ContainsKey(Token)) { this.Messages += SkinController.FormatMessage(TOKEN_SKIN, ((string)this.ControlList[Token]), 2, false); } else { this.Messages += SkinController.FormatMessage(TOKEN_PANE, Token, 2, false); } // if there is an attribute file if (this.Attributes.DocumentElement != null) { // look for the the node of this instance of the token XmlNode xmlSkinAttributeRoot = this.Attributes.DocumentElement.SelectSingleNode("descendant::Object[Token='[" + AttributeNode + "]']"); // if the token is found if (xmlSkinAttributeRoot != null) { this.Messages += SkinController.FormatMessage(TOKEN_FOUND, "[" + AttributeNode + "]", 2, false); // process each token attribute XmlNode xmlSkinAttribute; foreach (XmlNode tempLoopVar_xmlSkinAttribute in xmlSkinAttributeRoot.SelectNodes(".//Settings/Setting")) { xmlSkinAttribute = tempLoopVar_xmlSkinAttribute; if (xmlSkinAttribute.SelectSingleNode("Value").InnerText != "") { // append the formatted attribute to the inner contents of the control statement this.Messages += SkinController.FormatMessage(TOKEN_FORMAT, xmlSkinAttribute.SelectSingleNode("Name").InnerText + "=\"" + xmlSkinAttribute.SelectSingleNode("Value").InnerText + "\"", 2, false); SkinControl += " " + xmlSkinAttribute.SelectSingleNode("Name").InnerText + "=\"" + xmlSkinAttribute.SelectSingleNode("Value").InnerText.Replace("\"", """) + "\""; } } } else { this.Messages += SkinController.FormatMessage(TOKEN_NOTFOUND_INFILE, "[" + AttributeNode + "]", 2, false); } } if (this.ControlList.ContainsKey(Token)) { // create the skin object user control tag SkinControl = "dnn:" + ControlName + " runat=\"server\" id=\"dnn" + ControlName + "\"" + SkinControl; // Save control registration statement RegisterList.Add("<%@ Register TagPrefix=\"dnn\" TagName=\"" + ControlName + "\" Src=\"~/" + ((string)this.ControlList[Token]) + "\" %>" + "\r\n"); // return the control statement this.Messages += SkinController.FormatMessage(CONTROL_FORMAT, "<" + SkinControl + " />", 2, false); SkinControl = "<" + SkinControl + " />"; } else // CONTENTPANE { if (SkinControl.ToLower().IndexOf("id=") == -1) { SkinControl = " id=\"ContentPane\""; } SkinControl = "div runat=\"server\"" + SkinControl + "></div"; // return the control statement this.Messages += SkinController.FormatMessage(CONTROL_FORMAT, "<" + SkinControl + ">", 2, false); SkinControl = "<" + SkinControl + ">"; } return(SkinControl); } else { // return the unmodified token // note that this is currently protecting array syntax in embedded javascript // should be fixed in the regular expressions but is not, currently. this.Messages += SkinController.FormatMessage(TOKEN_NOTFOUND, "[" + m.Groups["token"].Value + "]", 2, false); return("[" + m.Groups["token"].Value + "]"); } }