我有以下代码:
public class AppDomainArgs : MarshalByRefObject {
public string myString;
}
static AppDomainArgs ada = new AppDomainArgs() { myString = "abc" };
static void Main(string[] args) {
AppDomain domain = AppDomain.CreateDomain("Domain666");
domain.DoCallBack(MyNewAppDomainMethod);
Console.WriteLine(ada.myString);
Console.ReadKey();
AppDomain.Unload(domain);
}
static void MyNewAppDomainMethod() {
ada.myString = "working!";
}
Run Code Online (Sandbox Code Playgroud)
我想这会让我的ada.myString"工作!" 在主appdomain上,但它没有.我认为通过继承MarshalByRefObject,在第二个应用程序域上所做的任何更改也会反映在原始应用程序中(我认为这只是主appdomain上真实对象的代理!)?
谢谢
有关我可以使默认AppDomain使用某些程序集的卷影副本吗?,它描述了一个工作解决方案,用于在特定目录的默认AppDomain中激活卷影复制.
基本上它说使用这些简单的方法:
AppDomain.CurrentDomain.SetShadowCopyPath(aDirectory);
AppDomain.CurrentDomain.SetShadowCopyFiles();
Run Code Online (Sandbox Code Playgroud)
但是因为这里使用的方法被标记为过时,我想知道现在正是什么方法来实现同样的目标.警告消息提示:
请调查AppDomainSetup.ShadowCopyDirectories的使用
AppDomain有一个这种类型的成员SetupInformation,可以带你进入这个简单的实现
AppDomain.CurrentDomain.SetupInformation.ShadowCopyDirectories = aDirectory;
AppDomain.CurrentDomain.SetupInformation.ShadowCopyFiles = "true";
Run Code Online (Sandbox Code Playgroud)
不幸的是,这没有效果.所以问题是,有没有办法改变当前appdomain的AppDomainSetup以激活阴影复制?
我在这里有点头疼,我想知道是否有人知道答案.
设置基本上是这样的:
//in Visual Studio plug-in application
SpinUpProgramWithDebuggerAttached();
//in spun up program
void Start()
{
StaticClass.StaticVariable = "I want to use this.";
XmlSerializer.Deserialize(typeof(MyThingie), "xml");
}
class MyThingie : IXmlSerializable
{
ReadXml()
{
//why the heck is this null?!?
var thingIWantToUse = StaticClass.StaticVariable;
}
}
Run Code Online (Sandbox Code Playgroud)
让我脱头发的问题是,在IXmlSerializable.ReadXml()方法中,StaticClass.StaticVariable为null,即使在设置变量后它被称为RIGHT.
值得注意的是,没有命中断点,并且在问题发生的精确位置忽略Debugger.Launch().
神秘的是,我通过提出异常来确定AppDomain.CurrentDomain.FriendlyName属性对于静态变量填充的位置与null相同!
为什么heck是超出范围的静态变量?!?这是怎么回事?!?我如何分享我的变量?
编辑:
我根据响应中的建议添加了一个静态构造函数,并让它执行Debug.WriteLine.我注意到它被调用了两次,即使所有代码似乎都在同一个AppDomain中运行.这是我在输出窗口中看到的内容,我希望这是一个有用的线索:
静态构造函数调用时间:2015-01-26T13:18:03.2852782-07:00
...加载'C:...\GAC_MSIL\System.Numerics\v4.0_4.0.0.0__b77a5c561934e089\System.Numerics.dll'...
......加载'Microsoft.GeneratedCode'......
...加载'C:...\GAC_MSIL\System.Xml.Linq\v4.0_4.0.0.0__b77a5c561934e089\System.Xml.Linq.dll'....
...加载'C:\ USERS ...\APPDATA\LOCAL\MICROSOFT\VISUALSTUDIO\12.0EXP\EXTENSIONS ... SharePointAdapter.dll'.符号已加载.
...加载'Microsoft.GeneratedCode'.
静态构造函数调用时间:2015-01-26T13:18:03.5196524-07:00
附加细节:
这是实际的代码,因为有几位评论者认为它可能有所帮助:
//this starts a process called "Emulator.exe"
var testDebugInfo = new VsDebugTargetInfo4
{
fSendToOutputWindow = 1,
dlo = …Run Code Online (Sandbox Code Playgroud) 这是核心问题:我有一个在单独的AppDomain中使用COM互操作的.NET应用程序.COM的东西似乎是将程序集加载回默认域,而不是从中调用COM内容的AppDomain.
我想知道的是:这是预期的行为,还是我做错了导致这些COM相关程序集被加载到错误的AppDomain中?请参阅以下情况的更详细说明......
该应用程序由3个程序集组成: - 主EXE,应用程序的入口点. - common.dll,只包含一个接口IController(采用IPlugin风格) - controller.dll,包含一个实现IController和MarshalByRefObject的Controller类.此类完成所有工作并使用COM interop与另一个应用程序进行交互.
主要EXE的相关部分如下所示:
AppDomain controller_domain = AppDomain.CreateDomain("Controller Domain");
IController c = (IController)controller_domain.CreateInstanceFromAndUnwrap("controller.dll", "MyNamespace.Controller");
result = c.Run();
AppDomain.Unload(controller_domain);
Run Code Online (Sandbox Code Playgroud)
common.dll只包含以下两件事:
public enum ControllerRunResult{FatalError, Finished, NonFatalError, NotRun}
public interface IController
{
ControllerRunResult Run();
}
Run Code Online (Sandbox Code Playgroud)
controller.dll包含这个类(也调用COM互操作的东西):
public class Controller: IController, MarshalByRefObject
Run Code Online (Sandbox Code Playgroud)
首次运行应用程序时,Assembly.GetAssemblies()看起来像预期的那样,在两个AppDomain中都加载了common.dll,并且只将controller.dll加载到控制器域中.在调用c.Run()之后,我看到与COM互操作内容相关的程序集已加载到默认的AppDomain中,而不是在发生COM互操作的AppDomain中.
为什么会发生这种情况?
如果你有兴趣,这里有一些背景知识:
最初这是一个AppDomain应用程序.它与之接口的COM东西是一个服务器API,它在长时间使用时不稳定.当COM东西发生COMException(没有关于其原因的有用诊断信息)时,整个应用程序必须重新启动才能再次使用COM连接.只需重新连接到COM应用服务器,就会再次导致COM异常.为了解决这个问题,我试图将COM互操作内容移动到一个单独的AppDomain中,这样当神秘的COMExceptions出现时,我可以卸载发生它的AppDomain,创建一个新的并再次启动,所有这些都无需手动重启应用程序.无论如何,这就是理论......
这是我的问题的基本要点:
问题:在第4步中,当A类从捕获B类事件的事件处理程序方法引发自己的事件时,会引发该事件; 但是,从不调用Window类中的订阅处理程序.
没有例外被抛出.如果我删除辅助AppDomain,事件处理没有问题.
有谁知道为什么这不起作用?有没有其他方法可以在不使用回调的情况下完成这项工作?
我认为,如果有的话,问题将发生在第3步而不是第4步.
这是一个真实的代码示例来说明问题:
Class Window1
Private WithEvents _prog As DangerousProgram
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.Windows.RoutedEventArgs) Handles Button1.Click
_prog = New DangerousProgram()
_prog.Name = "Bad Program"
End Sub
Private Sub MyEventHandler(ByVal sender As Object, ByVal e As NameChangedEventArgs) Handles _prog.NameChanged
TextBox1.Text = "Program's name is now: " & e.Name
End Sub
End Class
<Serializable()> _
Public Class DangerousProgram
Private _appDomain As AppDomain …Run Code Online (Sandbox Code Playgroud) 我无法搞清楚我的AppDomain.Unload(...)电话.我用我之前的问题中的代码详细解释了一下.事实证明,我执行了几个步骤,显然,我不需要.但是,我很确定在创建AppDomain并将其保存在集合中时:
private static Dictionary<string , AppDomain> HostDomains;
void StartNewDomain(string domainName)
{
AppDomain domain = AppDomain.CreateDomain(domainName);
HostDomains[domainName] = domain;
}
Run Code Online (Sandbox Code Playgroud)
......当你完成它之后,你必须卸载它:
if (HostDomains.ContainsKey(domainName))
{
AppDomain.Unload(HostDomains[domainName]);
HostDomains.Remove(domainName);
}
Run Code Online (Sandbox Code Playgroud)
然后从集合中删除域.
但是,当我卸载域时,整个应用程序正在结束.如果我删除卸载,一切都很好......我们只是从集合中删除域.但我担心我的孩子AppDomain 没有真正卸载.它可能最终得到GC我猜,但这并没有给我一个温暖的模糊.
子AppDomain程序集(Windows窗体应用程序)通过我继承的适配器类中引用的接口(IModule)异步启动MarshalByRefObject.我想知道这个对IModule的Start()(插件模块程序集实现的)的引用是不是正确编组(因为我的实现).因此,当调用Shutdown()方法时,整个应用程序都会死掉.我应该使我的IModule成为一个抽象类,所以它应该继承MBR吗?困惑...
看完我的代码后:
// instances the module for access to the module's Start() method
IModule module = (IModule)domain.CreateInstanceAndUnwrap(
ModuleManager.Modules[modName].Name,
ModuleManager.Modules[modName].EntryPoint.FullName);
Run Code Online (Sandbox Code Playgroud)
...我担心,因为IModule是一个接口,即使我在子域中创建一个实例,程序集也会泄漏到我的主AppDomain中.因此,当我尝试卸载子域时,两个域都被卸载.这是正确的吗?什么可能是通过MBR(适配器)对象提供Start()和Stop()方法的最佳解决方案?
更新:请参阅下面的答案进行更改 -
好的,没有泄漏 - 一切都继承了MBR:
我还做错了吗?我尝试了几件事情,但这似乎是错误的或不完整的.当我告诉ModuleAdapter关闭时,它会调用AppDomain.Unload(AppDomain.CurrentDomain)并且Host域也会停止.我仍然在应用程序退出时获得一些第一次机会异常.但是形式(myForm)已被告知.Close().
所以,我仍在寻找正确的方法......
我遇到了一个行为不端的库,它在终结器中抛出异常,这当然会导致应用程序崩溃.
为了避免这种情况,我尝试在自己的AppDomain中加载库,但异常仍然会冒泡到表面并导致应用程序崩溃.
正如在MSDN上记录的AppDomain.UnhandledException那样,注册不会阻止异常冒泡,但我很惊讶没有其他方法可以在"子AppDomain"中捕获这样的异常.
插件主机或使用AppDomains的应用程序如何沙箱化可能有害的代码,如何阻止未处理的异常?它实际上可能吗?
注意:我已经有了另一种解决方法,就是这里描述的解决方法.错误的终结器位于一个长期存在的对象上,似乎只在关闭期间收集,因此足以隐藏用户的这种"虚假"错误.尽管如此,我发现这种解决方法很脆弱,因为它会隐藏其他真正的错误,或者如果先前收集了对象,则可能会炸毁我的应用程序.
我正在开发一个需要将插件加载到单独的子应用程序域中的应用程序.只有一个插件加载到一个子应用程序域中.每个插件都需要不同的Windows标识,并且这些标识与默认(父)应用程序域中使用的Windows标识不同.每个插件都加载一个或多个子插件.
例如,默认应用程序域的身份是Authority\Limited(权限是域名或计算机名称).两个插件加载到两个子应用程序域中.加载的插件的标识是Authority\Privileged1和Authority\Privileged2.Authority\Privileged1和Authority\Privileged2分别具有对数据库Database1和Database2的所有必要访问权限,而Authority\Limited无权访问任何上述数据库.
在创建子应用程序域时,我调用System.AppDomain.SetThreadPrincipal方法传递System.Security.Principal.WindowsPrincipal实例.该实例是从从重复的用户令牌创建的System.Security.Principal.WindowsIdentity实例创建的(请参阅http://support.microsoft.com/kb/306158).我已经省略了对WindowsIdentity.Impersonate方法的调用,因为我在创建WIndowsPrincipal实例时处于默认应用程序域中.
我希望设置app域线程主体足以使加载的插件成功登录到各自的数据库并执行一些T-SQL语句.令我惊讶的是,打开与数据库的连接时使用WindowsIdentity.GetCurrent()方法返回的值.方法返回的值是进程标识或模拟标识.
由于进程标识没有使用数据库所必需的权限,因此不可接受.因此,冒充必须发挥作用.但是,模拟必须仅在子应用程序域中进行.每个插件都公开了用于执行插件加载和卸载的方法.我知道我必须在开始时进行模拟并撤消这些方法结束时的模拟.但是,必须对子应用程序域中生成的所有线程进行模拟.由于每个插件都加载了一个或多个子插件,并且每个插件可能会产生一个或多个线程,因此必须在许多地方执行模拟,这看起来非常混乱.
是否可以仅执行一次模拟,以便影响在子应用程序域中生成的所有线程?
我有两个Web应用程序(预编译站点),一个是第一方,将以完全信任的方式运行.另一个是第三方,应该部分信任(或具有特定权限).
TrustedAssembly.Web.Pages.MyPage应该在完全信任默认的AppDomain中运行.
UntrustedAssembly.Web.Pages.SomePage应该在部分信任AppDomain中运行.
此外,如果TrustedAssembly.Web.Pages.MyPage动态加载UntrustedAssembly.Web.Controls.SomeControl可以在部分信任和/或具有特定权限的情况下运行控件,而页面在完全信任下运行?
反之亦然,例如UntrustedAssembly.Web.Controls.SomePage动态加载TrustedAssembly.Web.Controls.MyControl,当页面在部分信任下运行时,是否可以完全信任地运行控件?
更新/仅供参考:这是.NET 4
我正在调试一个ASP.NET应用程序,它似乎随机丢失了一些静态字段的内容.我做了一些简单的自定义日志记录(因为即使log4net也不稳定),并发现该应用程序正被加载到两个应用程序域中.这是日志中的一个片段:
6/27/2011 9:01:01 PM /LM/W3SVC/1/ROOT/MyApp-1-129537072581658334: log message 1
6/27/2011 9:01:01 PM /LM/W3SVC/1/ROOT/MyApp-1-129537072581658334: log message 2
6/27/2011 9:01:01 PM /LM/W3SVC/1/ROOT/MyApp-1-129537072581658334: log message 3
6/27/2011 9:01:01 PM /LM/W3SVC/1/ROOT/MyApp-1-129537072581658334: log message 4
6/27/2011 9:01:02 PM /LM/W3SVC/1/ROOT/MyApp-4-129537072620628334: log message 5 <-
6/27/2011 9:01:02 PM /LM/W3SVC/1/ROOT/MyApp-4-129537072620628334: log message 6
6/27/2011 9:04:50 PM /LM/W3SVC/1/ROOT/MyApp-1-129537074647228334: log message 7
6/27/2011 9:04:50 PM /LM/W3SVC/1/ROOT/MyApp-1-129537074647228334: log message 8
Run Code Online (Sandbox Code Playgroud)
时间/日期之后的项目是当前的应用程序域名.
该应用程序只是一个常规的ASP.NET(而不是MVC)应用程序,它处理一些AJAX请求并将它们传递给一堆ASP.NET库.唯一不寻常的是,其中一个库使用一些反射来查找某些类,然后实例化它们并在不同的线程上运行它们.但它没有明确地与app域做任何事情.
顺便说一下,日志文件中突出显示的行来自ASP.NET应用程序本身(即不是来自其中一个单独的线程)来自ASPX处理程序.
我正确地解释了日志吗?如果是这样,什么可以导致应用程序从多个应用程序域加载和提供?
编辑:这个问题基本上与这个问题有关:ASP.NET应用程序状态与静态对象.但是,根据我今天看到的情况,似乎不可能依赖静态字段.我可以将所有内容移动到Application对象,但我想同步会有点麻烦.我越来越相信应用程序做了非标准的事情.
编辑2:我做了一些调查,似乎应用程序和应用程序域之间始终存在1-1关系(这是我期望的).所以我认为我所看到的就是回收利用.
编辑3:经过一些实验和探索之后,我启用了IIS运行状况监控(基于http://blogs.msdn.com/b/tess/archive/2006/08/02/asp-net-case-study-lost -session-variables-and-appdomain-recycles.aspx),并发现应用程序快速连续启动两次.这实际上非常令人费解.以下是日志事件:
Event code: 1003
Event message: Application compilation …Run Code Online (Sandbox Code Playgroud)