public BundleData CreateBundleData(string bundleDir) { bundleDir = PathUtility.GetFullPath(bundleDir); string path = Path.Combine(bundleDir, "Manifest.xml"); if (!File.Exists(path)) { return(null); } BundleData data = null; try { data = ManifestParser.CreateBundleData(path); } catch (Exception exception) { FileLogUtility.Error(string.Format(Messages.InstallBundleFailed, bundleDir, exception.Message)); } if (data != null) { if (string.IsNullOrEmpty(data.SymbolicName)) { _framework.EventManager.DispatchFrameworkEvent(this, new FrameworkEventArgs(FrameworkEventType.Error, new Exception(string.Format(Messages.SymbolicNameIsEmpty, bundleDir)))); return(null); } if (_bundleDatas.ContainsKey(data.SymbolicName)) { _framework.EventManager.DispatchFrameworkEvent(this, new FrameworkEventArgs(FrameworkEventType.Error, new Exception(string.Format(Messages.SymbolicNameDuplicated, bundleDir, _bundleDatas[data.SymbolicName].Path)))); return(null); } data.Path = bundleDir; _bundleDatas.Add(data.SymbolicName, data); } return(data); }
protected override void DoStart(BundleStartOptions option) { Stopwatch stopwatch = new Stopwatch(); try { if (((base.State != BundleState.Active) && (base.State != BundleState.Starting)) && (base.State != BundleState.Stopping)) { stopwatch.Start(); base.State = BundleState.Starting; if (base.Context == null) { base.Context = this.CreateBundleContext(); } base.Framework.StartLevelManager.ChangeStartLevel(base.Framework.StartLevelManager.StartLevel); base.State = BundleState.Active; } } finally { stopwatch.Stop(); FileLogUtility.Verbose(string.Format(Messages.StartSystemBundleTimeCounter, stopwatch.ElapsedMilliseconds)); } }
/// <summary> /// 将插件本地程序集添加到ASP.NET页面预编译引用程序集列表。这个方法一般是内部使用。 /// </summary> /// <param name="bundleSymbolicName">插件唯一名称。</param> /// <returns>返回插件所有本地程序集。</returns> public static IList <Assembly> AddReferencedAssemblies(string bundleSymbolicName) { BundleData bundleDataByName = BundleRuntime.Instance.GetFirstOrDefaultService <IBundleInstallerService>().GetBundleDataByName(bundleSymbolicName); if (bundleDataByName == null) { FileLogUtility.Debug(string.Format("Bundle '{0}' does not exist when trying to add its assemblies to referenced assemblies.", bundleSymbolicName)); return(new List <Assembly>()); } IList <Assembly> result; using (ReaderWriterLockHelper.CreateReaderLock(_cacheLock)) { IList <Assembly> list; if (_registeredBunldeCache.TryGetValue(bundleDataByName, out list)) { result = list; } else { IServiceManager serviceContainer = BundleRuntime.Instance.Framework.ServiceContainer; IRuntimeService firstOrDefaultService = serviceContainer.GetFirstOrDefaultService <IRuntimeService>(); List <Assembly> list2 = firstOrDefaultService.LoadBundleAssembly(bundleSymbolicName); FileLogUtility.Debug(string.Format("Add the assemblies of bundle '{0}' to top level referenced assemblies.", bundleSymbolicName)); using (ReaderWriterLockHelper.CreateWriterLock(_cacheLock)) { _registeredBunldeCache[bundleDataByName] = list2; } ResetTopLevelReferencedAssemblies(null); result = list2; } } return(result); }
/// <summary> /// 注册组件 /// </summary> /// <param name="location">位置</param> /// <param name="bd">组件数据</param> /// <returns>IBundle</returns> public IBundle InstallBundle(string location, BundleData bd) { if (!ValidExtention(location)) { location = location + BundleExtention; } string fullLocation = string.Empty; bool isPathRooted = Path.IsPathRooted(location); if (isPathRooted) { fullLocation = location; } if (!File.Exists(fullLocation)) { FileLogUtility.Debug(string.Format("{0}: Bundle {0} not found. {1}", location, DateTime.Now)); FileLogUtility.Debug(string.Format("{0}: file:{0} not found. {1}", fullLocation, DateTime.Now)); } // Create the bundle object BundleData bundleData = bd; bundleData.Id = _bundleRepository.Count; bundleData.Location = fullLocation; Bundle bundle = new Bundle(bundleData, this); if (CheckInstallBundle(bundle)) { InstallBundleInternal(bundle); } return(bundle); }
/// <summary> /// 重启ASP.NET应用域,包括BundleRuntime。当卸载一个模块或者更新一个模块时,需要重新启动应用域,因为旧的程序集会一直保留在BundleRuntime所在应用域直到应用域重启。 /// </summary> public virtual void RestartAppDomain(WriteHtmlContentAfterReboot writeHtmlContent) { FileLogUtility.Debug("Restarting the website by write bin forder or web config."); bool success = TryWriteBinFolder() || TryWriteWebConfig(); if (!success) { throw new BundleException( string.Format("UIShell.OSGi needs to be restarted due to bundle uninstalling or updating, but was unable to do so.\r\n" + "To prevent this issue in the future, a change to the web server configuration is required:\r\n" + "- run the application in a full trust environment, or\r\n" + "- give the application write access to the '{0}' folder, or\r\n" + "- give the application write access to the '{1}' file.", _hostRestartPhysicalPath, _webConfigPhysicalPath)); } // If setting up extensions/modules requires an AppDomain restart, it's very unlikely the // current request can be processed correctly. So, we redirect to the same URL, so that the // new request will come to the newly started AppDomain. HttpContext httpContext = HttpContext.Current; if (httpContext != null) { // Don't redirect posts... if (httpContext.Request.RequestType == "GET") { httpContext.Response.Redirect(httpContext.Request.Url.ToString(), true /*endResponse*/); } else { string refreshHtmlFullPath = _refreshHtmlPhysicalPath; try { // AppStore will create a refresh.html with different content. if (File.Exists(refreshHtmlFullPath)) { File.Delete(refreshHtmlFullPath); } using (StreamWriter sw = File.CreateText(refreshHtmlFullPath)) { if (writeHtmlContent != null) { writeHtmlContent(sw); } } } catch { throw new BundleException( string.Format("UIShell.OSGi needs to be restarted due to bundle uninstalling or updating, but was unable to do so.\r\n" + "To prevent this issue in the future, a change to the web server configuration is required:\r\n" + "- give the application create/write access to the '{0}' file.", refreshHtmlFullPath)); } httpContext.Response.WriteFile(_refreshHtmlPhysicalPath); httpContext.Response.End(); } FileLogUtility.Debug("Restart website successfully."); } }
private void BundleEventListener(object sender, BundleStateChangedEventArgs args) { // This is in another domain, thus the HttpContext.Current is always null. // Just comment it. //if (HttpContext.Current == null) //{ // return; //} //check if this bundle still exist. BundleData bundleData = BundleRuntime.Instance.GetFirstOrDefaultService <IBundleInstallerService>() .GetBundleDataByName(args.Bundle.SymbolicName); if (bundleData == null) { return; } bool needLoad = (args.CurrentState == BundleState.Active); if (needLoad) { //already registered its assemblies using (ReaderWriterLockHelper.CreateReaderLock(CacheLock)) { if (RegisteredBunldeCache.ContainsKey(bundleData)) { return; } //register bundle assemblies to BuildManager. ICollection <Assembly> assemblies = AddReferencedAssemblies(bundleData.SymbolicName); FileLogUtility.Debug( string.Format("Add the assemblies of bundle '{0}' to top level referenced assemblies since the bundle is active.", args.Bundle.SymbolicName)); if (assemblies != null && assemblies.Count > 0) { using (ReaderWriterLockHelper.CreateWriterLock(CacheLock)) { RegisteredBunldeCache[bundleData] = assemblies; } } } } else if (args.CurrentState == BundleState.Stopping) { //unregister when stopping. using (ReaderWriterLockHelper.CreateReaderLock(CacheLock)) { if (RegisteredBunldeCache.ContainsKey(bundleData)) { RemoveReferencedAssemblies(RegisteredBunldeCache[bundleData]); //remove from cache. using (ReaderWriterLockHelper.CreateWriterLock(CacheLock)) { RegisteredBunldeCache.Remove(bundleData); } FileLogUtility.Debug( string.Format("Remove the assemblies of bundle '{0}' from top level referenced assemblies since the bundle is stopping.", args.Bundle.SymbolicName)); } } } }
private void LogUnresolvedNode(Interface2 unresolvedNode, Interface2 dependentNode) { FileLogUtility.Inform(string.Format(Messages.BundleMarkedUnresolved, new object[] { unresolvedNode.SymbolicName, unresolvedNode.Version, dependentNode.SymbolicName, dependentNode.Version })); }
private void LogUnresolvedNode(Interface2 unresolvedNode) { FileLogUtility.Inform(string.Format(Messages.BundleNotResolved, unresolvedNode.SymbolicName, unresolvedNode.Version)); }
public override void OnBegin() { object obj2 = digester.Peek(); string symbolicName = string.Empty; if (obj2 is BundleData) { symbolicName = base.digester.Attributes["SymbolicName"]; } else if (base.digester.Root is BundleData) { symbolicName = (base.digester.Root as BundleData).SymbolicName; } using (IEnumerator enumerator = base.digester.Attributes.Keys.GetEnumerator()) { Label_0071: if (!enumerator.MoveNext()) { return; } string current = (string)enumerator.Current; string str3 = base.digester.Attributes[current]; PropertyInfo property = obj2.GetType().GetProperty(current, BindingFlags.Public | BindingFlags.Instance); if (property == null) { string name = char.ToUpper(current[0]) + current.Substring(1); property = obj2.GetType().GetProperty(name, BindingFlags.Public | BindingFlags.Instance); } if (property == null) { goto Label_0191; } object obj3 = null; if (property.PropertyType.IsEnum) { try { obj3 = Enum.Parse(property.PropertyType, str3, true); } catch (Exception exception) { FileLogUtility.Error(exception); } } else { try { obj3 = TypeConverterUtility.ConvertTo(str3, property.PropertyType); } catch (Exception exception2) { FileLogUtility.Error(exception2); } } goto Label_01B2; Label_013B: if (!string.IsNullOrEmpty(str3)) { FileLogUtility.Warn(string.Format(Messages.ManifestSectionInvalid, new object[] { str3, current, base.digester.ElementName, symbolicName })); goto Label_0071; } Label_0181: property.SetValue(obj2, obj3, null); goto Label_0071; Label_0191: FileLogUtility.Warn(string.Format(Messages.ManifestSectionNotRecognized, current, base.digester.ElementName, symbolicName)); goto Label_0071; Label_01B2: if (obj3 != null) { goto Label_0181; } goto Label_013B; } }
public virtual void Stop(BundleStopOptions option) { FileLogUtility.Debug(string.Format(Messages.BundleStopping, SymbolicName, Version)); DoLifecycleAction(() => DoStop(option), Messages.StopAction); FileLogUtility.Debug(string.Format(Messages.BundleInState, SymbolicName, Version, State)); }
/// <summary> /// 树点击事件。 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void NavigationTreeView_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs <object> e) { var treeViewItem = e.NewValue; if (treeViewItem == null || !(treeViewItem is TreeViewItem)) { return; } HideSidebar(); // 跟踪树形节点选中队列,保持刚选中的项为最后一项 TreeViewItemSelectionQueue.Remove(treeViewItem); TreeViewItemSelectionQueue.Add(treeViewItem); // 如果是换肤节点,则显示换肤控件 if (treeViewItem == SkinTreeViewItem) { ShowContent(SkinUserControl); return; } var node = (treeViewItem as TreeViewItem).Tag as NavigationNode; if (!string.IsNullOrEmpty(node.Value)) { if (OpenedPagesCache.ContainsKey(node.Id)) { ShowContent(OpenedPagesCache[node.Id]); return; } LoadingTextBlock.Visibility = System.Windows.Visibility.Visible; LayoutDockPanel.Visibility = System.Windows.Visibility.Hidden; ThreadPool.QueueUserWorkItem(state => { Action action = () => { bool cached = false; // 缓存中是否存在当前打开的页面,如果有,直接显示 // 获取该树节点的Tag属性,其值为导航节点 // 加载导航节点定义的用户控件的类型,这个类型由插件提供。 // 因此,必须使用插件来加载类型。 if (!cached) { var contentClass = node.Bundle.LoadClass(node.Value); if (contentClass != null) { try { // 创建实例,并转换成用户控件。 var component = System.Activator.CreateInstance(contentClass); var userControl = component as UserControl; if (userControl == null) { FileLogUtility.Error(string.Format("The type '{0}' in the Bundle '{1}' does not inherit from UIElement.", node.Value, node.Bundle.SymbolicName)); return; } if (userControl.DataContext != null && userControl.DataContext is ListViewModelBase) { userControl.InputBindings.AddRange((userControl.DataContext as ListViewModelBase).InputKeyBindings); } // 添加到缓存 OpenedPagesCache[node.Id] = userControl; // 将动态创建控件添加到显示区域 ShowContent(userControl); } catch (Exception ex) { FileLogUtility.Error(string.Format("Failed to create UIElement for the type '{0}' in the Bundle '{1}'.", node.Value, node.Bundle.SymbolicName)); FileLogUtility.Error(ex); } } else { FileLogUtility.Error(string.Format("Failed to load class '{0}' from the Bundle '{1}'.", node.Value, node.Bundle.SymbolicName)); } } LoadingTextBlock.Visibility = System.Windows.Visibility.Hidden; LayoutDockPanel.Visibility = System.Windows.Visibility.Visible; }; DispatcherOperation op = Dispatcher.BeginInvoke( DispatcherPriority.Background, action); DispatcherOperationStatus status = op.Status; while (status != DispatcherOperationStatus.Completed) { status = op.Wait(TimeSpan.FromMilliseconds(1000)); if (status == DispatcherOperationStatus.Aborted) { // Alert Someone } } }); } }
public static void NotInCorrectFormat(string name, string symbolicName, string extensionPoint) { FileLogUtility.Error(string.Format("{0} is not in correct format in bundle {1} for extension point {2} so it's ignored.", name, symbolicName, extensionPoint)); }
private void EventManager_FrameworkStateChanged(object sender, FrameworkEventArgs e) { var target = e.Target as IBundleContext; if (target == null) { var bundle = e.Target as IBundle; if (bundle != null) { target = bundle.Context; } } switch (e.EventType) { case FrameworkEventType.Starting: OnFrameworkStarting(); return; case FrameworkEventType.Started: OnFrameworkStarted(); return; case FrameworkEventType.Error: if (e.Data != null) { if (!(e.Data is Exception)) { break; } FileLogUtility.Error(e.Data as Exception); return; } if (target != null) { FileLogUtility.Error(string.Format(Messages.BundleThrownFrameworkError, target.Bundle.SymbolicName, target.Bundle.Version)); return; } FileLogUtility.Error(string.Format(Messages.ObjectThrownFrameworkError, e.Target)); return; case FrameworkEventType.Warning: if (e.Data != null) { if (e.Data is Exception) { FileLogUtility.Warn(e.Data as Exception); return; } break; } if (target != null) { FileLogUtility.Warn(string.Format(Messages.BundleThrownFrameworkWarning, target.Bundle.SymbolicName, target.Bundle.Version)); return; } FileLogUtility.Warn(string.Format(Messages.ObjectThrownFrameworkWarning, e.Target)); return; case FrameworkEventType.Info: case FrameworkEventType.Stopping: break; case FrameworkEventType.Stopped: OnFrameworkStop(); break; default: return; } }
private void CurrentDomain_AssemblyLoad(object sender, AssemblyLoadEventArgs e) { FileLogUtility.Debug(string.Format(Messages.AssemblyLoadedMessage, e.LoadedAssembly.FullName)); }
/// <summary> /// 将插件的一个ASP.NET页面编译并构建成一个IHttpHandler实例。 /// </summary> /// <param name="context">HttpContext。</param> /// <param name="requestType">请求类型。</param> /// <param name="virtualPath">页面虚拟路径。</param> /// <param name="path">页面物理路径。</param> /// <returns>IHttpHandler实例。</returns> public override IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path) { BundleRuntime instance = BundleRuntime.Instance; if (instance.State != BundleRuntimeState.Started) { try { FileLogUtility.Debug(string.Format("Framework is not in 'Started' state when access page '{0}'.", path)); return(base.GetHandler(context, requestType, FrameworkBusyHandlerPage, "")); } catch (Exception ex) { FileLogUtility.Warn("Failed to redirect framework Busy Handler page when Framework is not in 'Started'."); FileLogUtility.Warn(ex); } return(null); } string value = string.Empty; IBundleRuntimeHttpHost bundleRuntimeHttpHost = (IBundleRuntimeHttpHost)context.ApplicationInstance; BundleData bundleData = bundleRuntimeHttpHost.BundleRuntime.GetFirstOrDefaultService <IBundleInstallerService>() .FindBundleContainPath(Directory.GetParent(path).FullName); if (bundleData != null) { value = bundleData.SymbolicName; } if (string.IsNullOrEmpty(value)) { FileLogUtility.Debug(string.Format( "Failed to get the bundle contains requested page '{0}' and just compile this page into IHttpHandler. Just compile the page directly.", path)); return(SafelyGetHandler(context, requestType, virtualPath, path)); } IBundle bundle = bundleRuntimeHttpHost.BundleRuntime.Framework.GetBundle(bundleData.Path); if (bundle == null) { return(SafelyGetHandler(context, requestType, virtualPath, path)); } FileLogUtility.Debug(string.Format("The bundle state of requested page '{0}' is '{1}'.", path, bundle.State)); switch (bundle.State) { case BundleState.Installed: case BundleState.Resolved: { object syncObject; Monitor.Enter(syncObject = _syncObject); try { bundle.Start(BundleStartOptions.General); bundleRuntimeHttpHost.AddReferencedAssemblies(bundleData.SymbolicName); } finally { Monitor.Exit(syncObject); } return(SafelyGetHandler(context, requestType, virtualPath, path)); } case BundleState.Starting: { object syncObject2; Monitor.Enter(syncObject2 = _syncObject); try { bundleRuntimeHttpHost.AddReferencedAssemblies(bundleData.SymbolicName); } finally { Monitor.Exit(syncObject2); } return(SafelyGetHandler(context, requestType, virtualPath, path)); } case BundleState.Active: return(SafelyGetHandler(context, requestType, virtualPath, path)); case BundleState.Stopping: return(HandleException(context, requestType, new HttpException("Access denied, for the bundle is stopping."))); case BundleState.Uninstalled: return(HandleException(context, requestType, new HttpException("Access denied, for the bundle is uninstalled."))); default: throw new NotSupportedException(); } }
protected override Type GetControllerType(RequestContext requestContext, string controllerName) { const string namespacesKey = "Namespaces"; string bundleSymbolicName = requestContext.GetBundleSymbolicName(); if (bundleSymbolicName == null) { requestContext = HandleNonPluginRequestContext(requestContext, ref controllerName); } object namespaces; if (!requestContext.RouteData.DataTokens.TryGetValue(namespacesKey, out namespaces)) { namespaces = bundleSymbolicName == null ? DefaultConfig.GetHostingNamespaces() : DefaultConfig.GetBundleNamespaces(bundleSymbolicName); requestContext.RouteData.DataTokens[namespacesKey] = namespaces; } string cacheKey = bundleSymbolicName ?? DefaultConfig.HostingName; //从缓存获取控制器类型 Type controllerType = ControllerTypeCache.GetControllerType(cacheKey, controllerName); if (controllerType != null) { FileLogUtility.Inform(string.Format("Loaded controller '{0}' from bundle '{1}' by using cache.", controllerName, bundleSymbolicName)); return(controllerType); } if (bundleSymbolicName != null) { string value = controllerName + "Controller"; IRuntimeService firstOrDefaultService = BundleRuntime.Instance.GetFirstOrDefaultService <IRuntimeService>(); List <Assembly> assemblies = firstOrDefaultService.LoadBundleAssembly(bundleSymbolicName); foreach (Assembly assembly in assemblies) { Type[] types = assembly.GetTypes(); foreach (Type type in types) { if (!type.Name.ToLower().Contains(value.ToLower()) || !typeof(IController).IsAssignableFrom(type) || type.IsAbstract) { continue; } controllerType = type; ControllerTypeCache.AddControllerType(cacheKey, controllerName, controllerType); FileLogUtility.Inform(string.Format("Loaded controller '{0}' from bundle '{1}' and then added to cache.", controllerName, bundleSymbolicName)); return(controllerType); } } FileLogUtility.Error(string.Format("Failed to load controller '{0}' from bundle '{1}'.", controllerName, bundleSymbolicName)); } try { controllerType = base.GetControllerType(requestContext, controllerName); if (controllerType != null) { ControllerTypeCache.AddControllerType(cacheKey, controllerName, controllerType); } return(controllerType); } catch (Exception ex) { FileLogUtility.Error(string.Format("Failed to load controller '{0}'", controllerName)); FileLogUtility.Error(ex); } return(null); }
private void LogUnresolvedNode(IFragmentBundleMetadataNode unresolvedNode) { FileLogUtility.Inform(string.Format(Messages.FragmentDetachedForHostNotResolved, new object[] { unresolvedNode.SymbolicName, unresolvedNode.Version, unresolvedNode.HostNode.SymbolicName, unresolvedNode.HostNode.Version })); }
private static void RunApplication() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); const string PAGE_NAME_LOGIN = "******"; FileLogUtility.SetFileLogEnabled(true); FileLogUtility.SetLogFileName("log.txt"); FileLogUtility.SetLogLevel(LogLevel); FileLogUtility.SetMaxFileSizeByMB(MaxLogFileSize); FileLogUtility.SetCreateNewFileOnMaxSize(CreateNewLogFileOnMaxSize); using (BundleRuntime bundleRuntime = new BundleRuntime()) { bundleRuntime.Start(); // Get the page flow service. IPageFlowService pageFlowService = bundleRuntime.GetFirstOrDefaultService <IPageFlowService>(); if (pageFlowService == null) { throw new Exception(Resources.IPageFlowServiceServiceNotFound); } // Assert the first page node. if (string.IsNullOrEmpty(pageFlowService.FirstPageNodeValue) || string.IsNullOrEmpty(pageFlowService.FirstPageNodeName) || pageFlowService.FirstPageNodeOwner == null) { throw new Exception(Resources.CanNotFindAnAvailablePageNode); } // Load the form type of first page node. Type formType = pageFlowService.FirstPageNodeOwner.LoadClass(pageFlowService.FirstPageNodeValue); if (formType == null) { throw new Exception(string.Format(Resources.CanNotLoadTypeFromBundle, pageFlowService.FirstPageNodeValue, pageFlowService.FirstPageNodeOwner.SymbolicName)); } // Create the form instance of first page node and show it. Form formInstance = System.Activator.CreateInstance(formType) as Form; if (formInstance == null) { throw new Exception(string.Format(Resources.TypeIsNotWindowsFormType, pageFlowService.FirstPageNodeValue, pageFlowService.FirstPageNodeOwner.SymbolicName)); } // If first page node name is 'Login' then, show the dialog and then run application. if (pageFlowService.FirstPageNodeName.Equals(PAGE_NAME_LOGIN)) { DialogResult result = formInstance.ShowDialog(); if (result == DialogResult.OK || result == DialogResult.Yes) { PageNode nextNode = pageFlowService.GetNextPageNode(pageFlowService.FirstPageNodeName); if (nextNode != null) { Type mainPageFormType = nextNode.Bundle.LoadClass(nextNode.Value); if (mainPageFormType == null) { throw new Exception(string.Format(Resources.CanNotLoadTypeFromBundle, nextNode.Value, nextNode.Bundle.SymbolicName)); } Form mainPageForm = System.Activator.CreateInstance(mainPageFormType) as Form; Application.Run(mainPageForm); } } } else // Run the application directly. { Application.Run(formInstance); } } }
/// <summary> /// 将Xml节点转换成导航节点对象。 /// </summary> /// <param name="nav">所属Navigation。</param> /// <param name="node">Xml节点。</param> /// <param name="Parent">父导航节点。</param> /// <param name="children">子导航节点列表。</param> private void ConvertToNode(NavigationNode parent, XmlNode node, IBundle bundle) { // 获取Id、Name、Value、Order、Permisson、Icon和Tooltip属性。 string id = GetAttribute(node, "Id"); string name = GetAttribute(node, "Name"); if (string.IsNullOrEmpty(name)) { FileLogUtility.Warn("The Name attribute can not be empty for UIShell.NavigationService extension."); return; } string value = GetAttribute(node, "Value"); string order = GetAttribute(node, "Order"); float orderFloat = 0; float.TryParse(order, out orderFloat); string permission = GetAttribute(node, "Permission"); string icon = GetAttribute(node, "Icon"); string toolTip = GetAttribute(node, "Tooltip"); string parentId = GetAttribute(node, "ParentId"); // 创建导航节点。 var navNode = new NavigationNode { ParentId = string.IsNullOrEmpty(parentId) ? Guid.NewGuid().ToString() : parentId, Id = string.IsNullOrEmpty(id) ? Guid.NewGuid().ToString() : id, Name = name, Order = orderFloat, Value = value, Permission = permission, Icon = icon, ToolTip = toolTip, Bundle = bundle }; // 设置父节点,并添加到子节点列表。 if (!string.IsNullOrEmpty(parentId)) { PendingAppendedNodes.Add(navNode); } else if (string.IsNullOrEmpty(parentId)) { if (parent != null) { navNode.Parent = parent; parent.Children.Add(navNode); } else { navNode.Parent = null; navNode.ParentId = Guid.NewGuid().ToString(); NavigationNodeList.Add(navNode); } } // 将XML节点其它的属性保存到Attributes字典。 foreach (XmlAttribute attr in node.Attributes) { if (attr.Name.Equals("Id") || attr.Name.Equals("Name") || attr.Name.Equals("Value") || attr.Name.Equals("Order") || attr.Name.Equals("Permission") || attr.Name.Equals("Icon") || attr.Name.Equals("ToolTip")) { continue; } navNode.Attributes[attr.Name] = attr.Value; } // 遍历Xml子节点,并递归转换成导航节点。 foreach (XmlNode childnode in node.ChildNodes) { if (childnode is XmlComment) { continue; } ConvertToNode(navNode, childnode, bundle); } }