C# 应用程序域
在.NET中,每個應用程序域都是一個獨立的執行環境,有自己的安全邊界和上下文。當使用AppDomain.ExecuteAssembly方法在一個新的應用程序域中執行一個程序集時,這個程序集將會在新的應用程序域中加載和執行,而與原應用程序域隔離開來,兩個應用程序域之間的交互是受到限制的。
默認情況下,新應用程序域中的程序集無法訪問原應用程序域中的對象和資源。如果需要在不同的應用程序域之間進行通信,需要使用.NET提供的跨應用程序域通信(Cross-AppDomain Communication)機制,例如MarshalByRefObject和AppDomain.UnhandledException事件等。
如果需要在新應用程序域中執行某些操作并將結果返回給原應用程序域,可以使用Remoting或WCF等技術。其中,Remoting提供了一種透明的遠程調用機制,可以使得應用程序域之間的調用像本地調用一樣簡單;而WCF則提供了更加通用的跨進程和跨網絡通信機制,可以支持多種協議和格式,具有更高的靈活性和擴展性。
總之,在.NET中,新的應用程序域與原應用程序域之間的交互需要通過特定的機制來實現,具體實現方式取決于具體的場景和需求.
在.NET中,被調用的目標程序集必須是可執行的,這是因為在.NET中,應用程序域的基本單元是可執行程序集(Assembly),而非單個類或對象。應用程序域是.NET提供的一種隔離機制,可以在同一個進程中加載和執行多個不同的可執行程序集,從而實現應用程序的模塊化和隔離。
當在應用程序域中調用一個程序集時,CLR會將其加載到應用程序域中,并在其中創建一個或多個AppDomain對象。這個AppDomain對象將會在應用程序域的邊界內隔離程序集的執行環境,保證程序集的運行不會對應用程序域之外的其他部分產生影響,從而提高應用程序的安全性和可靠性。
因此,為了能夠在應用程序域中加載和執行一個程序集,這個程序集必須是可執行的,即符合.NET可執行程序集的規范,包含符號表、元數據和IL代碼等信息。只有這樣,CLR才能夠正確地解析和執行這個程序集,并將其隔離在應用程序域內部的執行環境中,同時與其他程序集和應用程序域進行交互和通信。
總之,在.NET中,被調用的目標程序集必須是可執行的,才能夠被加載到應用程序域中進行隔離和執行。
在.NET中,AppDomain類提供了一個DoCallBack方法,可以在當前應用程序域中調用指定委托(Delegate)的方法,并將其委托到另一個應用程序域中執行。這個方法通常用于實現應用程序域之間的通信和協作,可以在不同的應用程序域之間傳遞數據和執行代碼,從而實現應用程序的分布式和模塊化。
public void DoCallBack(CrossAppDomainDelegate callBackDelegate);
其中,callBackDelegate參數是一個CrossAppDomainDelegate委托,表示要在另一個應用程序域中執行的方法。該委托的參數和返回值必須是序列化和可傳遞的類型,否則將無法在應用程序域之間進行傳遞。
使用DoCallBack方法在新應用程序域中執行一個委托。這個委托輸出了當前應用程序域的名稱,并通過AppDomain.SetData方法將數據傳遞回主應用程序域。需要注意的是,在使用DoCallBack方法時,委托中的代碼將會在另一個應用程序域中執行,因此需要考慮到數據和代碼的傳遞和隔離問題。同時,由于跨應用程序域調用涉及到數據序列化和傳輸,因此可能會對性能和可靠性產生一定的影響。
AppDomain newDomain = AppDomain.CreateDomain("JohnYang New Domain");
Console.WriteLine(AppDomain.CurrentDomain.FriendlyName+","+AppDomain.CurrentDomain.IsDefaultAppDomain());
newDomain.SetData("Data", "Hello in new Domain");//在新應用程序域中設置槽
newDomain.DoCallBack(() =>
{
//這些代碼在newDomain中執行
Console.WriteLine($"this is in {AppDomain.CurrentDomain.FriendlyName},{AppDomain.CurrentDomain.IsDefaultAppDomain()}");
var data = AppDomain.CurrentDomain.GetData("Data");//newDomain自身設置Data
Console.WriteLine($"new domain get data:{data}");//newDomain自身獲取Data
});
//主程序域獲取不到該項
Console.WriteLine($"{AppDomain.CurrentDomain.FriendlyName}獲取"+AppDomain.CurrentDomain.GetData("Data"));
AppDomain.Unload(newDomain);
Console.ReadLine();
output:
Learn.exe,True
this is in JohnYang New Domain,False
new domain get data:Hello in new Domain
EasyBimBackend.exe獲取
以下代碼證明,獨立應用程序域中,每個應用程序域都有自己的內存空間和運行環境,不同的應用程序域之間相互隔離,無法直接相互訪問。因此,即使是同一個類的靜態成員,也不能在不同的應用程序域之間相互訪問。
class ProgramA
{
public static int count;
static void Main()
{
var domain = AppDomain.CreateDomain("JohnYang new domain");
domain.DoCallBack(() =>
{
ProgramA.count = 100;
});
Console.WriteLine(ProgramA.count);//打印0
Console.ReadLine();
}
}
在 MarshalByRefObject 對象之間進行遠程調用時,數據流通常是單向的,即從客戶端應用程序域到服務器應用程序域。但是,通過將一個 MarshalByRefObject 對象傳遞給另一個 MarshalByRefObject 對象的方法作為參數,可以實現遠程過程調用的逆向。
具體來說,當 FooA 對象的方法接受一個 MarshalByRefObject 參數時,可以將另一個可遠程訪問的對象作為參數傳遞進來。這個參數對象在客戶端應用程序域中創建,但是由于它繼承自 MarshalByRefObject,所以客戶端應用程序域中的代理對象將會在服務器應用程序域中創建一個真實的對象,然后將該對象作為參數傳遞給服務器應用程序域中的方法。
因此,逆向的 Remoting 過程是指在遠程過程調用中,數據流向是從服務器應用程序域到客戶端應用程序域。這使得客戶端應用程序可以向服務器應用程序傳遞對象,從而實現更靈活和動態的交互。
public class FooA : MarshalByRefObject
{
public string SayHello(FooB b) => $"Hello from {AppDomain.CurrentDomain.FriendlyName}. FooB says: {b.SayHello()}";
}
public class FooB : MarshalByRefObject
{
public string SayHello() => $"Hello from {AppDomain.CurrentDomain.FriendlyName}";
}
class ProgramA
{
static void Main()
{
AppDomain newDomainA = AppDomain.CreateDomain("new domain A");
AppDomain newDomainB = AppDomain.CreateDomain("new domain B");
FooA fooA = (FooA)newDomainA.CreateInstanceAndUnwrap(typeof(FooA).Assembly.FullName, typeof(FooA).FullName);
//FooB fooB = (FooB)newDomainB.CreateInstanceAndUnwrap(typeof(FooB).Assembly.FullName, typeof(FooB).FullName);
FooB fooB = new FooB();
Console.WriteLine(fooA.SayHello(fooB)); // 在客戶端應用程序域中調用FooA對象的方法,并將FooB對象作為參數傳遞進去
AppDomain.Unload(newDomainA);
AppDomain.Unload(newDomainB);
Console.ReadLine();
}
}
output:
Hello from new domain A. FooB says: Hello from Learn.exe
public class FooA : MarshalByRefObject
{
public string SayHello(FooB b) => $"Hello from {AppDomain.CurrentDomain.FriendlyName}. FooB says: {b.SayHello()}";
}
public class FooB : MarshalByRefObject
{
public string SayHello() => $"Hello from {AppDomain.CurrentDomain.FriendlyName}";
}
class ProgramA
{
static void Main()
{
AppDomain newDomainA = AppDomain.CreateDomain("new domain A");
AppDomain newDomainB = AppDomain.CreateDomain("new domain B");
FooA fooA = (FooA)newDomainA.CreateInstanceAndUnwrap(typeof(FooA).Assembly.FullName, typeof(FooA).FullName);
FooB fooB = (FooB)newDomainB.CreateInstanceAndUnwrap(typeof(FooB).Assembly.FullName, typeof(FooB).FullName);
//FooB fooB = new FooB();
Console.WriteLine(fooA.SayHello(fooB)); // 在客戶端應用程序域中調用FooA對象的方法,并將FooB對象作為參數傳遞進去
AppDomain.Unload(newDomainA);
AppDomain.Unload(newDomainB);
Console.ReadLine();
}
}
output:
Hello from new domain A. FooB says: Hello from new domain B
總結
- 上一篇: 【HUST】网安|计算机网络实验|实验三
- 下一篇: C# Environment.Curre