首页 > 其他分享 >.Net的AppDomain

.Net的AppDomain

时间:2025-01-16 17:44:48浏览次数:1  
标签:domain void AppDomain System 应用程序 using Net

 

一、AppDomain的作用

 

AppDomain(应用程序域)是一种在.NET 中提供的隔离机制,用于将应用程序的不同部分隔离开来,以提高安全性、可靠性和可管理性。以下是其主要的功能和用途:

 

    1. 隔离性:
      • 允许在一个进程中运行多个应用程序,同时使它们相互隔离。这样可以避免一个应用程序中的错误影响到其他应用程序,即使它们在同一个进程中运行。例如,在一个服务器进程中,可以运行多个不同的 Web 应用程序,它们可以在各自的 AppDomain 中运行,避免相互干扰。
      • 每个 AppDomain 都有自己的加载程序集、配置和资源,这有助于防止不同应用程序之间的冲突。
    2. 资源管理:
      • 可以对应用程序的资源进行独立的管理,包括内存的分配和使用。当一个 AppDomain 不再需要时,可以将其卸载,从而释放其所占用的资源,包括内存和其他系统资源。
      • 有助于减少内存泄漏的风险,因为可以将不再使用的 AppDomain 及其相关资源清除。
    3. 安全性:
      • 不同的 AppDomain 可以有不同的安全权限。这意味着可以对不同的 AppDomain 进行不同的安全设置,比如允许一个 AppDomain 访问网络资源,而另一个不允许,从而提高系统的整体安全性。
      • 可以为 AppDomain 中的代码设置代码访问安全策略,限制代码的执行权限,确保代码不会执行未经授权的操作。
    4. 程序集加载和卸载:
      • 可以在不同的 AppDomain 中加载和卸载程序集,这提供了一种灵活的方式来管理应用程序的动态行为。
      • 允许在不影响其他 AppDomain 的情况下,更新或替换某个 AppDomain 中的程序集,这在需要动态更新程序的情况下非常有用,比如热更新应用程序的某些部分。
    5. 应用程序配置的独立性:
      • 每个 AppDomain 可以有自己的配置信息,如配置文件(app.config)。这使得不同的应用程序可以根据自己的需要设置不同的配置,即使它们在同一个进程中运行。

 

二、使用AppDomain在一个进程创建两个应用

 

  • 在 Main 函数中:
    • 首先,使用 AppDomain.CreateDomain 创建了两个 AppDomain,分别命名为 "FirstAppDomain" 和 "SecondAppDomain"。
    • 然后,创建了两个 Thread 对象 firstThread 和 secondThread,每个线程都将在其自己的 AppDomain 中运行一个应用程序。
    • 通过 new Thread(() => RunAppInDomain(domain, appType)) 为每个线程指定要执行的操作,即调用 RunAppInDomain 方法并传递相应的 AppDomain 和应用程序类型。
    • 使用 firstThread.Start() 和 secondThread.Start() 启动两个线程,这样它们会同时开始执行。
    • 使用 firstThread.Join() 和 secondThread.Join() 等待两个线程完成。这样可以确保在卸载 AppDomain 之前,线程中的操作已经完成。
    • 最后,使用 AppDomain.Unload 卸载两个 AppDomain。
  • 在 RunAppInDomain 方法中:
    • 使用 domain.CreateInstanceAndUnwrap 在指定的 AppDomain 中创建对象实例。
    • 通过 appType.GetMethod("Run") 找到要调用的 Run 方法。
    • 使用 method.Invoke 调用 Run 方法。
  • 在 FirstApp 和 SecondApp 类中:
    • Run 方法中包含了打印信息和 Thread.Sleep 模拟应用程序的运行时间,你可以添加更复杂的逻辑。

 

这个示例允许两个应用程序在不同的 AppDomain 中同时运行,每个应用程序都有自己的资源和执行环境,并且它们不会相互干扰。通过将每个应用程序的执行放在单独的线程中,实现了并行处理。

 

需要注意的是:

 

    • 当使用多线程时,要注意线程之间的同步和资源共享问题。在这个示例中,由于两个应用程序是隔离的,通常不会出现资源共享问题,但在更复杂的场景中,可能需要考虑线程安全。
    • 卸载 AppDomain 时要确保其中的操作已经完成,否则可能会导致异常。使用 Join 方法可以帮助我们等待线程完成操作。
    • 你可以根据实际需要修改 FirstApp 和 SecondApp 中的 Run 方法,添加更多的功能和逻辑。
using System;
using System.Reflection;
using System.Threading;
using System.Windows.Forms;

namespace AppDomainTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 创建第一个 AppDomain
            AppDomain firstDomain = AppDomain.CreateDomain("FirstAppDomain");
            // 创建第二个 AppDomain
            AppDomain secondDomain = AppDomain.CreateDomain("SecondAppDomain");

            // 创建线程来运行第一个应用程序
            Thread firstThread = new Thread(() =>
            {
                RunAppInDomain(firstDomain, typeof(FirstApp));
            });
            // 创建线程来运行第二个应用程序
            Thread secondThread = new Thread(() =>
            {
                RunAppInDomain(secondDomain, typeof(SecondApp));
            });

            // 启动线程
            firstThread.Start();
            secondThread.Start();

            // 等待线程完成
            firstThread.Join();
            secondThread.Join();

            // 卸载 AppDomain
            AppDomain.Unload(firstDomain);
            AppDomain.Unload(secondDomain);

        }

        static void RunAppInDomain(AppDomain domain, Type appType)
        {
            // 在指定的 AppDomain 中创建对象实例
            object instance = domain.CreateInstanceAndUnwrap(
                appType.Assembly.FullName,
                appType.FullName);

            // 调用对象的方法
            MethodInfo method = appType.GetMethod("Run");
            if (method != null)
            {
                method.Invoke(instance, null);
            }
        }



    }

    [Serializable]
    class FirstApp
    {
        public void Run()
        {
            // 创建一个 Windows 窗体应用程序
            Form form = new Form();
            form.Text = "First App";
            form.Size = new System.Drawing.Size(300, 200);
            form.Load += Form_Load;
            Application.Run(form);
        }

        private void Form_Load(object sender, EventArgs e)
        {
            // 窗体加载时的操作
            MessageBox.Show("第一个应用的窗体已加载");
            // 可以添加更多逻辑
        }
    }

    [Serializable]
    class SecondApp
    {
        public void Run()
        {
            // 创建一个 Windows 窗体应用程序
            Form form = new Form();
            form.Text = "Second App";
            form.Size = new System.Drawing.Size(300, 200);
            form.Load += Form_Load;
            Application.Run(form);
        }

        private void Form_Load(object sender, EventArgs e)
        {
            // 窗体加载时的操作
            MessageBox.Show("第二个应用的窗体已加载");
            // 可以添加更多逻辑
        }
    }


}

 

三、AppDomain的其他用法

1、程序集加载和卸载的更多细节

 

  1. 加载特定版本的程序集:
    • 可以在不同的 AppDomain 中加载特定版本的程序集,避免不同版本的程序集冲突。例如:

    收起 csharp  
    using System;
    using System.Reflection;
    
    class Program
    {
        static void Main()
        {
            AppDomain domain = AppDomain.CreateDomain("MyDomain");
            try
            {
                domain.Load("MyAssembly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null");
                // 在这里可以使用在该 AppDomain 中加载的程序集
            }
            finally
            {
                AppDomain.Unload(domain);
            }
        }
    }
    
     
    • 上述代码使用 domain.Load 方法精确指定了要加载的程序集的版本号、区域性和公钥令牌,确保在该 AppDomain 中加载的是所需的特定版本程序集。
  2. 动态加载程序集并执行代码: 收起 csharp  
    using System;
    using System.Reflection;
    
    class Program
    {
        static void Main()
        {
            AppDomain domain = AppDomain.CreateDomain("DynamicDomain");
            try
            {
                domain.AssemblyResolve += Domain_AssemblyResolve;
                object instance = domain.CreateInstanceFromAndUnwrap("MyAssembly.dll", "MyNamespace.MyClass");
                MethodInfo method = instance.GetType().GetMethod("MyMethod");
                if (method!= null)
                {
                    method.Invoke(instance, null);
                }
            }
            finally
            {
                AppDomain.Unload(domain);
            }
        }
    
        private static Assembly Domain_AssemblyResolve(object sender, ResolveEventArgs args)
        {
            // 自定义程序集解析逻辑
            return Assembly.LoadFrom("Path/To/MyAssembly.dll");
        }
    }
    
     
    • 这里使用 domain.AssemblyResolve 事件添加了自定义的程序集解析逻辑,当程序集无法找到时,会调用 Domain_AssemblyResolve 方法,你可以根据需要从自定义位置加载程序集。

 

2、异常处理和隔离

 

  1. 隔离可能引发异常的代码:
    • 将可能引发异常的代码放在单独的 AppDomain 中运行,避免影响主程序的执行。

    收起 csharp  
    using System;
    
    class Program
    {
        static void Main()
        {
            AppDomain domain = AppDomain.CreateDomain("ExceptionDomain");
            try
            {
                domain.DoCallBack(ExceptionThrowingMethod);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Caught exception from another AppDomain: {ex.Message}");
            }
            finally
            {
                AppDomain.Unload(domain);
            }
        }
    
        static void ExceptionThrowingMethod()
        {
            throw new Exception("This is an exception from another AppDomain");
        }
    }
    
     
    • 在这个例子中,ExceptionThrowingMethod 方法被放在新的 AppDomain 中执行,当它抛出异常时,不会直接导致主程序崩溃,而是可以在主程序中进行异常捕获。

 

3、监控资源使用

 

  1. 监控内存使用:
    • 可以在 AppDomain 中监控内存使用情况,帮助优化性能。

    收起 csharp  
    using System;
    using System.Reflection;
    
    class Program
    {
        static void Main()
        {
            AppDomain domain = AppDomain.CreateDomain("MemoryMonitorDomain");
            try
            {
                domain.MonitoringIsEnabled = true;
                // 执行一些操作
                object instance = domain.CreateInstanceFromAndUnwrap("MyAssembly.dll", "MyClass");
                // 可以调用一些方法等操作
                long memoryUsed = domain.MonitoringSurvivedMemorySize;
                Console.WriteLine($"Memory used in the AppDomain: {memoryUsed} bytes");
            }
            finally
            {
                AppDomain.Unload(domain);
            }
        }
    }
    
     
    • 通过将 domain.MonitoringIsEnabled 设置为 true,可以启用对该 AppDomain 的内存使用监控,使用 domain.MonitoringSurvivedMemorySize 可以获取该 AppDomain 存活对象占用的内存大小。

 

4、跨 AppDomain 通信

 

  1. 使用 MarshalByRefObject 实现跨 AppDomain 通信: 收起 csharp  
    using System;
    
    public class RemoteObject : MarshalByRefObject
    {
        public string GetMessage()
        {
            return "Hello from another AppDomain";
        }
    }
    
    class Program
    {
        static void Main()
        {
            AppDomain domain = AppDomain.CreateDomain("CommunicationDomain");
            try
            {
                RemoteObject remoteObj = (RemoteObject)domain.CreateInstanceAndUnwrap(typeof(RemoteObject).Assembly.FullName, typeof(RemoteObject).FullName);
                string message = remoteObj.GetMessage();
                Console.WriteLine(message);
            }
            finally
            {
                AppDomain.Unload(domain);
            }
        }
    }
    
     
    • RemoteObject 继承自 MarshalByRefObject,这允许它被跨 AppDomain 调用。当在主 AppDomain 中调用 GetMessage 方法时,实际的调用会被代理到另一个 AppDomain 中执行,实现了跨 AppDomain 的通信。

 

5、配置不同的安全策略

 

    1. 设置不同的安全权限: 收起 csharp  
      using System;
      using System.Security;
      using System.Security.Permissions;
      using System.Security.Policy;
      
      class Program
      {
          static void Main()
          {
              Evidence ev = new Evidence();
              ev.AddHostEvidence(new Zone(SecurityZone.Internet));
              PermissionSet internetPermissionSet = SecurityManager.GetStandardSandbox(ev);
              AppDomain domain = AppDomain.CreateDomain("SecureDomain", ev, new AppDomainSetup(), internetPermissionSet);
              try
              {
                  // 在安全受限的 AppDomain 中执行代码
              }
              finally
              {
                  AppDomain.Unload(domain);
              }
          }
      }
      
       
      • 这里使用 Evidence 和 PermissionSet 为新创建的 AppDomain 配置了安全权限,使其只能在特定的安全范围内运行,例如将其权限限制为从 Internet 区域下载的代码的权限。

 

标签:domain,void,AppDomain,System,应用程序,using,Net
From: https://www.cnblogs.com/xietianjiao/p/18675470

相关文章

  • Asp .Net Core 实现微服务:集成 Ocelot+Consul+Swagger+Cors实现网关、服务注册、服务
    什么是Ocelot?Ocelot是一个开源的ASP.NETCore微服务网关,它提供了API网关所需的所有功能,如路由、认证、限流、监控等。Ocelot是一个简单、灵活且功能强大的API网关,它可以与现有的服务集成,并帮助您保护、监控和扩展您的微服务。以下是Ocelot的一些主要功能:路由管理:Ocelot允......
  • Asp .Net Core 实现微服务:集成 Ocelot+Nacos+Swagger+Cors实现网关、服务注册、服务发
    什么是Ocelot?Ocelot是一个开源的ASP.NETCore微服务网关,它提供了API网关所需的所有功能,如路由、认证、限流、监控等。Ocelot是一个简单、灵活且功能强大的API网关,它可以与现有的服务集成,并帮助您保护、监控和扩展您的微服务。以下是Ocelot的一些主要功能:路由管理:Ocelot......
  • Asp .Net Core实现微服务:集成 Consul 实现 服务注册与健康检查
    什么是Consul?官网:ConsulbyHashiCorpConsul是一款开源的服务发现和配置管理工具,它能够监控应用程序和服务之间的通信,并提供了一组API和WebUI,用于管理服务和配置。Consul是分布式的、高可用的、可横向扩展的,具备以下特性:服务发现:Consul通过DNS或者HTTP接口使......
  • Kubernetes (K8s) 入门指南
    Kubernetes(K8s)入门指南什么是Kubernetes?Kubernetes,通常简称为K8s(因为从“K”到“s”之间有八个字符),是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。它最初由谷歌设计,并在2014年捐赠给了云原生计算基金会(CNCF)。Kubernetes建立在谷歌多年来......
  • OxyPlot:一个功能强大、漂亮.Net跨平台开源绘图库
    推荐一个支持多平台、多框架的.Net绘图库。01项目简介OxyPlot是一个基于.NET开发的、跨平台的绘图库,可用于多种平台和框架,如WPF、Windows8、WindowsPhone、WindowsPhoneSilverlight、WindowsForms、Silverlight、GTK#、Xwt、Xamarin.iOS、Xamarin.Android、Xamarin.Forms......
  • rinetd-端口转发工具
    工具介绍Rinetd是为在一个Unix和Linux操作系统中为重定向传输控制协议(TCP)连接的一个工具。Rinetd是单一过程的服务器,它处理任何数量的连接到在配置文件etc/rinetd中指定的地址/端口对。尽管rinetd使用非闭锁I/O运行作为一个单一过程,它可能重定向很多连接而不对这台机器增加额外......
  • (翻译) 关于游戏网络,每个游戏程序需知 What Every Programmer Needs To Know About
    原文链接 https://gafferongames.com/post/what_every_programmer_needs_to_know_about_game_networking/ Haveyoueverwonderedhowmultiplayergameswork?Fromtheoutsideitseemsmagical:twoormoreplayerssharingaconsistentexperience(一致的体验)across......
  • MSGNet:多尺度序列间相关性学习的多变量时间序列预测
    MSGNet——多尺度序列间相关性学习的多变量时间序列预测[2401.00423v1]MSGNet:LearningMulti-ScaleInter-SeriesCorrelationsforMultivariateTimeSeriesForecasting——来自CCF-A(AAAI,AAAlConferenceonArtificialIntelligence)GitHub代码:YoZhibo/MSGNet:MS......
  • 深入理解Kubernetes Pod生命周期
    目录前言:1.Pod概述2.Pod生命周期的各个阶段2.1Pending(待定)2.2Running(运行中)2.3Succeeded(成功)2.4Failed(失败)2.5Unknown(未知)3.Pod状态的转变4.Pod的重启策略5.Pod的终止过程6.容器的管理与生命周期6.1容器的生命周期6.2健康检查与容器管理6.3......
  • Kubernetes 知识梳理及集群搭建
    Kubernetes介绍应用部署方式演变在部署应用程序的方式上,主要经历了三个时代:传统部署:互联网早期,会直接将应用程序部署在物理机上优点:简单,不需要其它技术的参与缺点:不能为应用程序定义资源使用边界,很难合理地分配计算资源,而且程序之间容易产生影响虚拟化部署:可以在一台......