接上一节
/// <summary> /// Perform file deply /// </summary> /// <param name="plug">Plugin file info</param> /// <returns>Assembly</returns> private static Assembly PerformFileDeploy(FileInfo plug) { if (plug.Directory.Parent == null) throw new InvalidOperationException("The plugin directory for the " + plug.Name + " file exists in a folder outside of the allowed nopCommerce folder heirarchy"); FileInfo shadowCopiedPlug; if (CommonHelper.GetTrustLevel() != AspNetHostingPermissionLevel.Unrestricted) { //all plugins will need to be copied to ~/Plugins/bin/ //this is aboslutely required because all of this relies on probingPaths being set statically in the web.config //were running in med trust, so copy to custom bin folder var shadowCopyPlugFolder = Directory.CreateDirectory(_shadowCopyFolder.FullName); shadowCopiedPlug = InitializeMediumTrust(plug, shadowCopyPlugFolder); } else { var directory = AppDomain.CurrentDomain.DynamicDirectory; Debug.WriteLine(plug.FullName + " to " + directory); //were running in full trust so copy to standard dynamic folder shadowCopiedPlug = InitializeFullTrust(plug, new DirectoryInfo(directory)); } //we can now register the plugin definition var shadowCopiedAssembly = Assembly.Load(AssemblyName.GetAssemblyName(shadowCopiedPlug.FullName)); //add the reference to the build manager Debug.WriteLine("Adding to BuildManager: '{0}'", shadowCopiedAssembly.FullName); BuildManager.AddReferencedAssembly(shadowCopiedAssembly); return shadowCopiedAssembly; }
查看CommonHelper.GetTrustLevel方法:
/// <summary> /// Finds the trust level of the running application (http://blogs.msdn.com/dmitryr/archive/2007/01/23/finding-out-the-current-trust-level-in-asp-net.aspx) /// </summary> /// <returns>The current trust level.</returns> public static AspNetHostingPermissionLevel GetTrustLevel() { if (!_trustLevel.HasValue) { //set minimum _trustLevel = AspNetHostingPermissionLevel.None; //determine maximum foreach (AspNetHostingPermissionLevel trustLevel in new[] { AspNetHostingPermissionLevel.Unrestricted, AspNetHostingPermissionLevel.High, AspNetHostingPermissionLevel.Medium, AspNetHostingPermissionLevel.Low, AspNetHostingPermissionLevel.Minimal }) { try { new AspNetHostingPermission(trustLevel).Demand(); _trustLevel = trustLevel; break; //we've set the highest permission we can } catch (System.Security.SecurityException) { continue; } } } return _trustLevel.Value; }
大体意思是:如果新人级别没有值,则先设置为不授予任何权限,然后遍历权限,从最大权限开始,如果授予权限成功 就返回,如果报错继续授予下一个权限,就是授予当前能授予的最大权限。
如果不是最大权限的话,创建BIN目录,并调用方法:
var shadowCopyPlugFolder = Directory.CreateDirectory(_shadowCopyFolder.FullName); shadowCopiedPlug = InitializeMediumTrust(plug, shadowCopyPlugFolder);
InitializeMediumTrust方法如下:
// <summary> /// Used to initialize plugins when running in Medium Trust /// </summary> /// <param name="plug"></param> /// <param name="shadowCopyPlugFolder"></param> /// <returns></returns> private static FileInfo InitializeMediumTrust(FileInfo plug, DirectoryInfo shadowCopyPlugFolder) { var shouldCopy = true; var shadowCopiedPlug = new FileInfo(Path.Combine(shadowCopyPlugFolder.FullName, plug.Name)); //check if a shadow copied file already exists and if it does, check if it's updated, if not don't copy if (shadowCopiedPlug.Exists) { //it's better to use LastWriteTimeUTC, but not all file systems have this property //maybe it is better to compare file hash? var areFilesIdentical = shadowCopiedPlug.CreationTimeUtc.Ticks >= plug.CreationTimeUtc.Ticks; if (areFilesIdentical) { Debug.WriteLine("Not copying; files appear identical: '{0}'", shadowCopiedPlug.Name); shouldCopy = false; } else { //delete an existing file //More info: http://www.nopcommerce.com/boards/t/11511/access-error-nopplugindiscountrulesbillingcountrydll.aspx?p=4#60838 Debug.WriteLine("New plugin found; Deleting the old file: '{0}'", shadowCopiedPlug.Name); File.Delete(shadowCopiedPlug.FullName); } } if (shouldCopy) { try { File.Copy(plug.FullName, shadowCopiedPlug.FullName, true); } catch (IOException) { Debug.WriteLine(shadowCopiedPlug.FullName + " is locked, attempting to rename"); //this occurs when the files are locked, //for some reason devenv locks plugin files some times and for another crazy reason you are allowed to rename them //which releases the lock, so that it what we are doing here, once it's renamed, we can re-shadow copy try { var oldFile = shadowCopiedPlug.FullName + Guid.NewGuid().ToString("N") + ".old"; File.Move(shadowCopiedPlug.FullName, oldFile); } catch (IOException exc) { throw new IOException(shadowCopiedPlug.FullName + " rename failed, cannot initialize plugin", exc); } //ok, we've made it this far, now retry the shadow copy File.Copy(plug.FullName, shadowCopiedPlug.FullName, true); } } return shadowCopiedPlug; }
根据传入值获得 bin目录的 new fileinfo,如果此文件已经存在,则比较创建的UTC时间。
如果是旧文件就删除,如果是新文件 就设置 需要拷贝为false.
如果需要拷贝为true,则进行拷贝到BIN。。。 最后返回BIN的全路径文件名。
最后根据这个文件名加载程序集,并返回这个程序集。
用foreach循环加载剩余的DLL。
最后设置PluginType类型的值 并添加到referencedPlugins。 最后赋值
ReferencedPlugins = referencedPlugins;
IncompatiblePlugins = incompatiblePlugins;
PluginManager类的init方法就是设置ReferencedPlugins 。
EnsurePluginsAreLoaded方法内将它(ReferencedPlugins .tolist)赋值给_plugins。
GetPluginDescriptors 方法:
/// <summary> /// Get plugin descriptors /// </summary> /// <param name="loadMode">Load plugins mode</param> /// <param name="storeId">Load records allowed only in a specified store; pass 0 to load all records</param> /// <param name="group">Filter by plugin group; pass null to load all records</param> /// <returns>Plugin descriptors</returns> public virtual IEnumerable<PluginDescriptor> GetPluginDescriptors(LoadPluginsMode loadMode = LoadPluginsMode.InstalledOnly, int storeId = 0, string group = null) { //ensure plugins are loaded EnsurePluginsAreLoaded(); return _plugins.Where(p => CheckLoadMode(p, loadMode) && AuthenticateStore(p, storeId) && CheckGroup(p, group)); }
最后一句,帅选出 已安装的,并且在storeID内的。group为空也肯定为true 的plugins.