📄 assemblyresolver.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 + -