⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 assemblyresolver.cs

📁 Agent技术在智能交通中的应用
💻 CS
字号:
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Security;
using System.Security.Permissions;
using System.Security.Policy;
using System.Text;

namespace MobileAgents
{
	/// <summary>
	/// AssemblyManager handles the assembly resolution and base directory CAS configuration.
	/// </summary>
	public class AssemblyResolver
	{
		#region Private Constants for CAS Setup...
		private const string _codeGroupName = "Downloaded Mobile Agents";
		private const string _codeGroupDescription = "Sandboxed environment for execution of downloaded mobile agent assemblies.";
		private const string _permissionSetName = "Mobile Agents";
		#endregion

		/// <summary>
		/// This will store the base directory for assemblies for this agent host system.
		/// </summary>
		private static string _assemblyStoreBaseDir = string.Empty;

		/// <summary>
		/// Static Ctor.  Determines the base assembly cache directory to use and sets CAS policy for it.
		/// This also hooks into the AppDomain's AssemblyResolve event.
		/// </summary>
		static AssemblyResolver() 
		{
			//Create a root directory for agent assemblies to be used/loaded/saved/etc.
			_assemblyStoreBaseDir = Path.Combine
				(
				Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), 
				@"MSDN\MobileAgentsSample\v1.0"
				);

			//Check for the existence of this directory.
			if (!Directory.Exists(_assemblyStoreBaseDir))
				Directory.CreateDirectory(_assemblyStoreBaseDir);

			//Configure CAS for this so that all assemblies downloaded here 
			//have the Internet permission set and NOT FullTrust!
			SetCasPolicyForBaseDir();

			//Also, hook into the AppDomain for notification of assembly resolution failures
			AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
		}

		#region Code Access Security Policy Methods...

		/// <summary>
		/// Begins setting the CAS policy for the base directory.
		/// </summary>
		private static void SetCasPolicyForBaseDir()
		{
			//Get Machine-Level Policy
			PolicyLevel pl = GetMachinePolicy();

			//If our CAG doesn't exist, create it.
			if (!CodeAccessGroupExists(pl))
				CreateCodeAccessGroup(pl);
		}

		/// <summary>
		/// Gets the PolicyLevel object for machine-level policy.
		/// </summary>
		/// <returns>PolicyLevel object for machine-level policy.</returns>
		private static PolicyLevel GetMachinePolicy()
		{
			PolicyLevel machinePolicy = null;

			//Get the machine policy
			IEnumerator ie = SecurityManager.PolicyHierarchy();
			while (ie.MoveNext())
			{
				PolicyLevel pl = ie.Current as PolicyLevel;
				if (pl.Type == PolicyLevelType.Machine)
				{
					machinePolicy = pl;
					break;
				}
			}

			//Make SURE we got it.
			if (machinePolicy == null)
				throw new SecurityException("Unable to obtain machine security policy.");

			return machinePolicy;
		}

		/// <summary>
		/// Checks to see if the CAS CodeGroup that we want already exists.
		/// </summary>
		/// <param name="machinePolicy">The machine-level CAS policy.</param>
		/// <returns>True/false. True if our code group already exists.</returns>
		private static bool CodeAccessGroupExists(PolicyLevel machinePolicy)
		{
			CodeGroup machineAllCode = machinePolicy.RootCodeGroup;
			bool found = false;
			foreach (CodeGroup child in machineAllCode.Children)
			{
				if (child.Name == _codeGroupName)
				{
					found = true;
					break;
				}
			}

			return found;
		}

		/// <summary>
		/// Creates the mobile agent code group as a child of the All_Code group in the machine policy.
		/// </summary>
		/// <param name="machinePolicy">The machine-level policy object.</param>
		private static void CreateCodeAccessGroup(PolicyLevel machinePolicy)
		{
			//Create a Url Membership Condition that points to our assembly store (and sub-dirs)
			string url = string.Format("file://{0}\\*", _assemblyStoreBaseDir);
			UrlMembershipCondition mc = new UrlMembershipCondition(url);

			//Create a policy statement that contains our permission set
			PolicyStatement ps = new PolicyStatement(GetPermissionSet(machinePolicy));

			//Create a union code group based on the permission set defined above.
			UnionCodeGroup ucg = new UnionCodeGroup(mc, ps);
			ucg.Name = _codeGroupName;
			ucg.Description = _codeGroupDescription;
			machinePolicy.RootCodeGroup.AddChild(ucg);

			//Save changes.
			SecurityManager.SavePolicy();
		}

		/// <summary>
		/// Retrieves the permission set with which the uploaded assemblies will run as.
		/// </summary>
		/// <param name="machinePolicy">The machine-level policy object.</param>
		/// <returns>A PermissionSet detailing the permissions of the downloaded assemblies.</returns>
		private static PermissionSet GetPermissionSet(PolicyLevel machinePolicy)
		{
			//Get a copy of the Internet permission set.
			NamedPermissionSet ps = null;
			foreach (NamedPermissionSet nps in machinePolicy.NamedPermissionSets)
			{
				if (nps.Name == "Internet")
				{
					ps = nps.Copy(_permissionSetName);
					break;
				}
			}

			if (ps == null)
				throw new SecurityException("Unable to find machine-level Internet permission set");

			//Customize. Remove unnecessary permissions. TODO: Add any?
			ps.RemovePermission(typeof(FileDialogPermission));
			ps.RemovePermission(typeof(UIPermission));
			ps.RemovePermission(typeof(System.Drawing.Printing.PrintingPermission));

			return ps;
		}
		#endregion

		/// <summary>
		/// Delegate method for AssemblyResolve event.
		/// </summary>
		/// <param name="sender">AppDomain that had the failure.</param>
		/// <param name="args">The arguments for the event.</param>
		/// <returns>The loaded Assembly.</returns>
		private static System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
		{
			Assembly a = null;

			//Retrieve the directory and the file to load
			string fileName, dirPath;
			GetDirectoryAndFileForAssembly(args.Name, out dirPath, out fileName);

			//Load the assembly given its path. Return it.
			string fullPath = Path.Combine(dirPath, fileName);
			if (File.Exists(fullPath))
				a = Assembly.LoadFrom(fullPath);

			return a;
		}

		/// <summary>
		/// Given the identity of the assembly and the base directory, it will output the directory and file name.
		/// </summary>
		/// <param name="assemblyFullName">The full name of the assembly</param>
		/// <param name="directoryName">Output. The directory the assembly will be found at.</param>
		/// <param name="fileName">The name of the file.</param>
		private static void GetDirectoryAndFileForAssembly(string assemblyFullName, out string directoryName, out string fileName)
		{
			//Init
			fileName = string.Empty;
			directoryName = string.Empty;

			//Parse the assembly name
			string name, version, culture, publicKeyToken;
			ParseAssemblyFullName(assemblyFullName, out name, out version, out culture, out publicKeyToken);

			//Set our output param.  Always end with .dll.
			fileName = name + ".dll";

			//Create a relative path from those items
			string relPath = string.Format(@"{0}\{1}\{2}\{3}", name, culture, version, publicKeyToken);

			//Append the relative path to the base path and return it!
			directoryName = Path.Combine(_assemblyStoreBaseDir, relPath);
		}

		/// <summary>
		/// Retrieves the name,version,culture,and public key token for the given assembly name.
		/// </summary>
		/// <param name="assemblyFullName">The assembly name to parse.</param>
		/// <param name="name">The simple name of the assembly.</param>
		/// <param name="version">The assembly version.</param>
		/// <param name="culture">The assembly culture.</param>
		/// <param name="publicKeyToken">The assembly public key token.</param>
		private static void ParseAssemblyFullName(string assemblyFullName, out string name, out string version, out string culture, out string publicKeyToken)
		{
			//Init vars.
			name = version = culture = publicKeyToken = string.Empty;

			AssemblyName an = new AssemblyName(assemblyFullName);
			name = an.Name;
			version = an.Version.ToString();
			culture = an.CultureInfo.NativeName;
			publicKeyToken = ConvertBytesToHexString(an.GetPublicKeyToken());
		}

		/// <summary>
		/// Helper function to convert a byte[] into a hex-formatted string.
		/// </summary>
		/// <param name="bits">The bits to convert.</param>
		/// <returns>A hex-encoded string.</returns>
		private static string ConvertBytesToHexString(byte[] bits)
		{
			StringBuilder sb = new StringBuilder();
			foreach (byte b in bits)
				sb.AppendFormat("{0:x}", b);

			return sb.ToString();
		}

		/// <summary>
		/// Saves the given bits to the appropriate place on the file system. Called internally by AgentHost.
		/// </summary>
		/// <param name="assemblyFullName">The full name of the assembly.</param>
		/// <param name="assemblyBits">The assembly bits.</param>
		internal static void SaveAssemblyBits(string assemblyFullName, byte[] assemblyBits)
		{
			//Get the directory this assembly should go in.
			string fileName, dirPath;
			GetDirectoryAndFileForAssembly(assemblyFullName, out dirPath, out fileName);

			//Create the assembly's directory if we need to
			if (!Directory.Exists(dirPath)) {Directory.CreateDirectory(dirPath);}

			//Create the assembly file if it doesn't already exist.
			string filePath = Path.Combine(dirPath, fileName);
			if (!File.Exists(filePath))
			{
				FileStream fs = File.OpenWrite(filePath);
				fs.Write(assemblyBits, 0, assemblyBits.Length);
				fs.Close();
			}
		}

		/// <summary>
		/// Determines whether or not the assembly is installed.
		/// </summary>
		/// <param name="assemblyFullName">The full name of the assembly to check for.</param>
		/// <returns>True/false.  True if this assembly is installed.</returns>
		internal static bool IsAssemblyInstalled(string assemblyFullName)
		{
			bool found = false;
			try
			{				
				AssemblyName an = new AssemblyName(assemblyFullName);
				Assembly asm = Assembly.Load(an);
				if (asm != null)
					found = true;
			}
			catch(FileNotFoundException){}
			return found;
		}

		internal static void Initialize()
		{
			//A dummy method that will load this type into an AppDomain,
			//thus hooking into the AppDomain's events.
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -