1

I am loading an assembly using Assembly.LoadFrom(fileName). When fileName is on the local machine, everything works fine. When, however, the identical file (and dependencies) are on a remote network share, I get a System.Security.SecurityException the moment I try to create a new SqlConnection from the remote assembly:

System.Security.SecurityException: Request for the permission of type 'System.Data.SqlClient.SqlClientPermission, System.Data, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089' failed.

What's the cure?

Shaul Behr
  • 36,951
  • 69
  • 249
  • 387

3 Answers3

4

You could load the assembly as bytes and load it with Assembly.Load(bytes), maybe this works.

Or you give the application the requested permission.

Edit:

I made a little test and it worked for me. Here is some code:

static Dictionary<Assembly, String> _Paths = new Dictionary<Assembly, String>();

static void Main(string[] args)
{
    AppDomain current = AppDomain.CurrentDomain;
    current.AssemblyResolve += new ResolveEventHandler(HandleAssemblyResolve);

    // This line loads a assembly and retrieves all types of it. Only when
    // calling "GetTypes" the 'AssemblyResolve'-event occurs and loads the dependency
    Type[] types = LoadAssembly("Assemblies\\MyDLL.dll").GetTypes();
    // The next line is used to test permissions, i tested the IO-Permissions 
    // and the Reflection permissions ( which should be denied when using remote assemblies )
    // Also this test includes the creation of a Form
    Object instance = Activator.CreateInstance(types[0]);
}

private static Assembly LoadAssembly(string file)
{
    // Load the assembly
    Assembly result = Assembly.Load(File.ReadAllBytes(file));
    // Add the path of the assembly to the dictionary
    _Paths.Add(result, Path.GetDirectoryName(file));
    return result;
}

static Assembly HandleAssemblyResolve(object sender, ResolveEventArgs args)
{
    // Extract file name from the full-quallified name
    String name = args.Name;
    name = name.Substring(0, name.IndexOf(','));
    // Load the assembly
    return LoadAssembly(Path.Combine(_Paths[args.RequestingAssembly], name + ".dll"));
}

Something important:

There may be files which do not have a matching name and file name, but you can resolve this by checking all files in folder with AssemblyName.GetAssemblyName(file).

Felix K.
  • 6,201
  • 2
  • 38
  • 71
  • Why do you thinking loading it as bytes would help? And what do you mean by "give the application the requested permission" - how? – Shaul Behr Nov 29 '11 at 09:30
  • Because your application does not know where it has been loaded from, maybe this does not restricts the permissions. – Felix K. Nov 29 '11 at 09:39
  • Nice idea - but it fails as soon as you need to call a dependency. With LoadFrom() we know which folder to look in for required dlls; if we load as bytes we have no idea where to find the other files... – Shaul Behr Nov 29 '11 at 11:23
  • Simple workaround: The dependency's are loaded when loading the assembly, using the `ResolveAssembly` event and a `Stack` solves the issues with loading the assemblies ( Put the path's in the stack while loading ). Edit: If you need the path at runtime, you could use a `Dictionary`. – Felix K. Nov 29 '11 at 14:56
  • Thanks for the suggestion. I'm actually not going to try it, because the solution (workaround, really) I got to is actually a good one, but +1 for the idea, which could well work. If anyone else tries it and it works, please leave a comment here! – Shaul Behr Nov 30 '11 at 09:04
  • Well, well - in that case, you have correctly and effectively answered my question, and answer credit belongs to you! Thanks! – Shaul Behr Nov 30 '11 at 14:33
2

Well, I found a workaround. I could not find any way to circumvent the SecurityException problem - so instead of loading the assembly from the remote folder, I simply copied the remote folder contents at runtime to the local computer and ran from there. Simple, neat and works perfectly. Plus, it's arguably a better way of working, so that the clients are running off their local copy instead of putting load on the server, and it makes it much easier to deploy an updated version of the original, without any file locking.

Caveat to anyone who tries to follow in my footsteps: don't try and copy to a subfolder of your app directory; for some reason this causes errors with dependencies. Rather copy to 'Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)` or some other folder to which you know you have write access.

Shaul Behr
  • 36,951
  • 69
  • 249
  • 387
1

The assembly is being loaded with LocalIntranet permission set. This restricts certain APIs. See:

http://msdn.microsoft.com/en-us/library/03kwzyfc.aspx and http://msdn.microsoft.com/en-us/library/0x4t63kb%28v=vs.80%29.aspx

spender
  • 117,338
  • 33
  • 229
  • 351