AppDomainToolkit
所属分类:开发工具
开发工具:C#
文件大小:0KB
下载次数:0
上传日期:2017-05-15 16:44:22
上 传 者:
sh-1993
说明: 用于管理.NET应用程序域编程复杂性的工具包。,
(A toolkit for managing the complexities of .NET application domain programming.,)
文件列表:
AppDomainToolkit.UnitTests/ (0, 2017-05-15)
AppDomainToolkit.UnitTests/AppDomainContextUnitTests.cs (23776, 2017-05-15)
AppDomainToolkit.UnitTests/AppDomainToolkit.UnitTests.csproj (7082, 2017-05-15)
AppDomainToolkit.UnitTests/AssemblyTargetUnitTests.cs (2582, 2017-05-15)
AppDomainToolkit.UnitTests/DisposableAppDomainUnitTests.cs (1879, 2017-05-15)
AppDomainToolkit.UnitTests/Key.snk (596, 2017-05-15)
AppDomainToolkit.UnitTests/Properties/ (0, 2017-05-15)
AppDomainToolkit.UnitTests/Properties/AssemblyInfo.cs (1390, 2017-05-15)
AppDomainToolkit.UnitTests/RemoteActionUnitTests.cs (6496, 2017-05-15)
AppDomainToolkit.UnitTests/RemoteFuncAsyncUnitTests.cs (11207, 2017-05-15)
AppDomainToolkit.UnitTests/RemoteFuncUnitTests.cs (6590, 2017-05-15)
AppDomainToolkit.UnitTests/RemoteUnitTests.cs (3514, 2017-05-15)
AppDomainToolkit.UnitTests/packages.config (673, 2017-05-15)
AppDomainToolkit.UnitTests/test-assembly-files/ (0, 2017-05-15)
AppDomainToolkit.UnitTests/test-assembly-files/TestWithNoReferences.dll (4096, 2017-05-15)
AppDomainToolkit.UnitTests/test-assembly-files/test-with-internal-references/ (0, 2017-05-15)
AppDomainToolkit.UnitTests/test-assembly-files/test-with-internal-references/AssemblyA.dll (4096, 2017-05-15)
AppDomainToolkit.UnitTests/test-assembly-files/test-with-internal-references/AssemblyB.dll (4096, 2017-05-15)
AppDomainToolkit.UnitTests/test-assembly-files/test-with-internal-references/TestWithInternalReferences.dll (4608, 2017-05-15)
AppDomainToolkit.sln (2096, 2017-05-15)
AppDomainToolkit.testsettings (1132, 2017-05-15)
AppDomainToolkit.vsmdi (510, 2017-05-15)
AppDomainToolkit/ (0, 2017-05-15)
AppDomainToolkit/AppDomainContext.cs (15990, 2017-05-15)
AppDomainToolkit/AppDomainToolkit.csproj (3509, 2017-05-15)
AppDomainToolkit/AppDomainToolkit.nupkg (24921, 2017-05-15)
AppDomainToolkit/AssemblyLoader.cs (7392, 2017-05-15)
AppDomainToolkit/AssemblyTarget.cs (4173, 2017-05-15)
AppDomainToolkit/AssemblyTargetLoader.cs (3771, 2017-05-15)
AppDomainToolkit/DisposableAppDomain.cs (2906, 2017-05-15)
AppDomainToolkit/IAppDomainContext.cs (5153, 2017-05-15)
AppDomainToolkit/IAssemblyLoader.cs (3203, 2017-05-15)
AppDomainToolkit/IAssemblyResolver.cs (2471, 2017-05-15)
AppDomainToolkit/IAssemblyTarget.cs (1204, 2017-05-15)
AppDomainToolkit/IAssemblyTargetLoader.cs (3424, 2017-05-15)
AppDomainToolkit/IDisposable.cs (517, 2017-05-15)
AppDomainToolkit/Key.pfx (1764, 2017-05-15)
AppDomainToolkit/MarshalableTaskCompletionSource.cs (774, 2017-05-15)
... ...
AppDomain Toolkit
=================
SUMMARY
-------
Anyone whose ever had to deal with loading Assemblies using standard .NET reflection facilities understands
that it's not straightforward. Which context should I load into? How do I know that my Assembly is imported
into the correct application domain? What if I want to load two versions of the same assembly into an
application domain? How can I tear down an application domain where I've loaded my own assemblies?
I've seen quite a few questions like these all over www.stackoverflow.com, and having dealt with these problems
in my own research projects I decided to build a small library that provided some basic functionality:
1. Ability to set up transient app domains that easily tear themselves down.
2. Ability to execute remote delegates in an arbitrary app domain.
INSTALLING
----------
#### Install via the package manager prompt:
```PM> Install-Package AppDomainToolkit```
You may also search the package gallery for ```AppDomainToolkit``` and it should show up. Click install and you're all
set.
IMPLEMENTATION NOTES
--------------------
There are a couple of things to be aware of when utilizing the library. Most of them are non-issues as long as you
understand the load context concept of application domains, and some of them stem from the backwards idea of executing
code remotely--that is it's not entirely intuitive. I've seen several answers on stackoverflow claiming to solve an
application domain problem when the solution _still_ executes the target code in the current domain. Thinking in a
remoting context requires a deeper analysis of where you think call sites are executing.
### Assembly Loading
The most important of issues to discuss first is how the currently executing assembly is discovered and loaded into the
current and foreign app domains for class resolution. You can't execute any assembly loading into an AppDomainContext
without first loading the AssemblyLoader class into that domain. There's an interface dedicated to handling domain
assembly resolve events and an implementation called [```PathBasedAssemblyResolver```][1]. This class is responsible for loading
missing assemblies into any the current application domain whenever an ```Assembly.Load*``` method is called or whenever
the application domain deduces that it needs to load a specific Assembly. Events that can trigger this include all of
the static Assembly methods, along with pretty much anything that reflects across that assembly. By default, the
```AppDomainContext``` class will load the currently executing assembly's path as a target for the contained
[```IAssemblyResolver```][2] instance, but an overload of ```AppDomainContext.Create()``` allows you to pass your own
```AppDomainSetupInfo``` instance. When doing this, make sure that you set the ```ApplicationBase``` property to be
the base directory where your application, and ideally the AppDomainToolkit assembly lives. Usually this can easily
be done with a simple ```Assembly.GetExecutingAssembly.Location()``` call. Also note that you can access the remote and
local [```IAssemblyResolver```][2] instances on an [```AppDomainContext```][3] through the ```context.AssemblyImporter```
and ```context.RemoteResolver``` properties.
### Executing arbitrary code
The typical remoting scenario requires you to create an instance of a remote class using the ```CreateInstanceAndUnwrap```
method on an application domain and then utilize instance methods on that type--which is effectively _instantiated_ in
the foreign app domain. The .NET runtime also provides a way to execute a block of code in a foreign application domain
via the ```CrossAppDomainDelegate``` class, but it's extremely limited. If you attempt to pass this class a lambda
expression, for example, sometimes you'll get a runtime exception complaining about some mangled class name not being
serializable. This will _always_ happen if your lambda has a closure in it--that is some variable is hoisted in the
class generated by the compiler to be passed back to your code. The root issue here is that the compiler does not mark
the generated class as ```[Serializable]```, something MSFT says they may change in the future. But why wait? Building
out our own Serializable delegates is easy enough. There are two classes equipped for handling this exact problem,
that is the [```RemoteAction```][4] and the [```RemoteFunc```][5]. Please note that both of these classes require _all_
inputs to be serializable, and all output values to be either serializable or extend ```MarshalObjectByRef```. See the
examples below for further clarification.
EXAMPLES
--------
#### Load an assembly into a foreign application domain:
```c#
using(var context = AppDomainContext.Create())
{
context.LoadAssembly(LoadMethod.LoadFile, "C:\path\to\my\test.dll");
}
```
The AppDomain will be set up with a temporary name, and the application base path and private bin paths will be set to
the current executing assembly--which is likely the right thing to do since this assembly will be installed along side
whatever program that is using it.
#### Load an assembly into an app domain with your own setup info:
```c#
var rootDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var setupInfo = new AppDomainSetup()
{
ApplicationName = "My Application",
ApplicationBase = rootDir,
PrivateBinPath = rootDir
};
using(var context = AppDomainContext.Create(setupInfo))
{
context.LoadAssembly(LoadMethod.LoadFrom, "C:\path\to\my\test.dll");
}
```
This overloaded factory method allows you to assign whatever attributes you wish to the domain setup info.
#### Execute an action in a foreign application domain with arguments:
``` c#
using(var context = AppDomainContext.Create())
{
RemoteAction.Invoke(
context.Domain,
"Hello World",
(message) =>
{
var msg = message + " from AppDomain " + AppDomain.CurrentDomain.SetupInformation.ApplicationName
Console.WriteLine(msg);
});
}
```
All arguments passed through the static Invoke method _must_ be serializable or MarshalByRefObject derivatives.
#### Execute a function in a foreign application domain with a return value:
```c#
using(var context = AppDomainContext.Create())
{
var area = RemoteFunc.Invoke(
context.Domain,
3.146,
5,
(pi, r) =>
{
return pi * r * r;
});
}
```
Return values and inputs may be serializable or MarshalByRefObject derivatives. Pay attention to the lifetime cycle of any objects
marshaled by reference. If the time runs out, then the returned value will be GC'd before you're finished with it.
Function arguments passed to Invoke _must_ be serializable.
#### Execute a function with my own custom serializable types:
```c#
Reply reply = null;
using(var context = AppDomainContext.Create())
{
reply = RemoteFunc.Invoke(
context.Domain,
new Request("Hello World"),
(request) =>
{
return !string.IsNullOrEmpty(request.Message) ?
new Reply("Hello yourself!") :
new Reply("You said nothing!");
});
}
// Since the reply is serializable, you can use it after the domain has
// been unloaded! This is super powerful!
Console.WriteLine(reply.Message);
[Serializable]
public class Request
{
public Request(string message)
{
this.Message = message;
}
public string Message { get; private set; }
}
[Serializable]
public class Reply
{
public Request(string message)
{
this.Message = message;
}
public string Message { get; private set; }
}
```
#### Execute remote code and return a proxy
```c#
using(var context = AppDomainContext.Create())
{
var result = RemoteFunc.Invoke(
context.Domain,
"Hello",
(phrase) =>
{
return new Greeter(phrase);
});
// Executes in the remote domain.
result.SayHello("jduv");
}
public class Greeter : MarshalByRefObject
{
private readonly string helloPhrase;
public void RemoteGreeter(string helloPhrase)
{
this.helloPhrase = helloPhrase;
}
public void SayHello(string name)
{
return this.helloPhrase + " " + name + "!";
}
}
```
This code is quite powerful. It will create a remote object and return a handle to it _as long as the remote class
extends ```MarshalByRefObject```_. It's important to understand here, though, that the remote object won't live
outside the ```using``` block. If you wish to persist a remote object longer, check out the next example. Also note that
you can pass constructor arguments to the RemoteFunc.Invoke method. It's a simple ```params``` array after the AppDomain
argument.
#### Create a persistent remote proxy
```c#
var context = AppDomainContext.Create()
// The second arg is ctor arguments.
var remoteGreeter = Remote.CreateProxy(context.Domain, "Hello");
remoteGreeter.SayHello("jduv");
// Eventually, it's a good idea to unload the app domain.
// *Always* use dispose for this. Don't call AppDomain.Unload(context.Domain)
context.Dispose();
```
```c#
var context = AppDomainContext.Create();
// Alternatively, you can place a proxy into a using block for automatic disposal.
using(var remoteGreeter = Remote..CreateProxy(context.Domain, "Hello"))
{
remoteGreeter.SayHello("jduv");
}
```
The Remote class was stolen off the internet and modified slightly to suite my needs. Credit should be placed where
credit is due, so the original version of the Remote class lives [here][6]. Alot of the inspiration for this entire
library was based on that implementation along with some stackoverflow questions I've been lurking.
[1]: https://github.com/jduv/AppDomainToolkit/blob/master/PathBasedAssemblyResolver.cs
[2]: https://github.com/jduv/AppDomainToolkit/blob/master/IAssemblyResolver.cs
[3]: https://github.com/jduv/AppDomainToolkit/blob/master/AppDomainContext.cs
[4]: https://github.com/jduv/AppDomainToolkit/blob/master/RemoteAction.cs
[5]: https://github.com/jduv/AppDomainToolkit/blob/master/RemoteFunc.cs
[6]: http://www.superstarcoders.com/blogs/posts/executing-code-in-a-separate-application-domain-using-c-sharp.aspx
近期下载者:
相关文件:
收藏者: