.NET Core获取程序运行行环境信息与反射的应用

简介: .NET Core获取程序运行行环境信息与反射的应用

RuntimeInformation、Environment


RuntimeInformation 类提供有关 .NET 运行时安装的信息。主要获取平台以及 版本,API较少。


文档地址 https://docs.microsoft.com/zh-cn/dotnet/api/system.runtime.interopservices.runtimeinformation?view=netcore-3.1

Environment 提供有关当前环境和平台的信息以及操作它们的方法。API比较多。

文档地址 https://docs.microsoft.com/zh-cn/dotnet/api/system.environment?view=netcore-3.1


以上两个类已经提供了文档地址,这里不再赘述。

需要注意的是,Windows、Linux 之间有差异,因此有些 API 是无法跨平台的。另外 .NET Core 相对 .NET Framework ,对获取系统资源信息等的 API 十分少。

.NET Core 是无有 API 获取系统 CPU 情况和 内存使用情况,倒是可以获取当前进程的 CPU 和 内存使用情况。

可以查看 stackoverflow 了解。

https://stackoverflow.com/questions/54215334/how-to-measure-cpu-usage-and-memory-for-a-process-in-net-core-linux


获取信息


下面获取的属于进程使用的内存已经使用 CPU 时间。

CPU 时间不像直接获取到的 使用百分比,可以很直观地看到。

CPU 时间地公式如下。


CPU时间 = 执行程序所需的时钟周期数 * 时钟周期时间

CPU 有多核多线程,因此不能按照运行多长时间去计算。同时进程存在休眠、上下文切换等情况。


程序运行了几小时,有可能CPU时间只有几十分钟。

对 CPU 性能计算方法有兴趣,请参考 https://www.cnblogs.com/whuanle/p/12260224.html

对 Linux CPU 使用率计算有兴趣,请查看 https://www.cnblogs.com/aresxin/p/9152127.html

我们在 C# 中使用地代码如下


[Display(Name = "运行信息")]
    public class ApplicationRunInfo
    {
        private double _UsedMem;
        private double _UsedCPUTime;
        public ApplicationRunInfo()
        {
            var proc = Process.GetCurrentProcess();
            var mem = proc.WorkingSet64;
            var cpu = proc.TotalProcessorTime;
            _UsedMem = mem / 1024.0;
            _UsedCPUTime = cpu.TotalMilliseconds;
        }
        [Display(Name = "进程已使用物理内存(kb)")]
        public double UsedMem { get { return _UsedMem; } }
        [Display(Name = "进程已占耗CPU时间(ms)")]
        public double UsedCPUTime { get { return _UsedCPUTime; } }
    }


这里只有两个属性。

我们使用 Display 特性来标记此属性地的含义,方便反射时获取信息。

另外还有两个获取不同类型信息的类如下


[Display(Name = "系统运行平台")]
    public class SystemPlatformInfo
    {
        [Display(Name = "运行框架")]
        public string FrameworkDescription { get { return RuntimeInformation.FrameworkDescription; } }
        [Display(Name = "操作系统")]
        public string OSDescription { get { return RuntimeInformation.OSDescription; } }
        [Display(Name = "操作系统版本")]
        public string OSVersion { get { return Environment.OSVersion.ToString(); } }
        [Display(Name = "平台架构")]
        public string OSArchitecture { get { return RuntimeInformation.OSArchitecture.ToString(); } }
    }
    [Display(Name = "运行环境")]
    public class SystemRunEvnInfo
    {
        [Display(Name = "机器名称")]
        public string MachineName { get { return Environment.MachineName; } }
        [Display(Name = "用户网络域名")]
        public string UserDomainName { get { return Environment.UserDomainName; } }
        [Display(Name = "分区磁盘")]
        public string GetLogicalDrives { get { return string.Join(", ", Environment.GetLogicalDrives()); } }
        [Display(Name = "系统目录")]
        public string SystemDirectory { get { return Environment.SystemDirectory; } }
        [Display(Name = "系统已运行时间(毫秒)")]
        public int TickCount { get { return Environment.TickCount; } }
        [Display(Name = "是否在交互模式中运行")]
        public bool UserInteractive { get { return Environment.UserInteractive; } }
        [Display(Name = "当前关联用户名")]
        public string UserName { get { return Environment.UserName; } }
        [Display(Name = "Web程序核心框架版本")]
        public string Version { get { return Environment.Version.ToString(); } }
        //对Linux无效
        [Display(Name = "磁盘分区")]
        public string SystemDrive { get { return Environment.ExpandEnvironmentVariables("%SystemDrive%"); } }
        //对Linux无效
        [Display(Name = "系统目录")]
        public string SystemRoot { get { return Environment.ExpandEnvironmentVariables("%SystemRoot%"); } }
    }


可能你会觉得,为什么不写成方法,为啥要写得这么奇怪。不急,慢慢看下去~

反射获取信息


我们来定义一个静态类型,作为获取各种信息的入口。


public static class EnvironmentInfo
{
}
}


获取属性值

反射获取属性值的方法,用于获取上述几个类的属性值。


/// <summary>
        /// 获取属性的值
        /// </summary>
        /// <param name="info"></param>
        /// <param name="obj">实例</param>
        /// <returns></returns>
        private static object GetPropertyInfoValue(PropertyInfo info, object obj)
        {
            return info.GetValue(obj);
        }


反射获取特性值

我们使用了特性 [Display(Name = "当前关联用户名")] 来存储别名。

我们要通过反射获取 Dispaly 特性的 Name 属性值。


/// <summary>
        /// 获取 [Display] 特性的属性 Name 的值
        /// </summary>
        /// <param name="attrs"></param>
        /// <returns></returns>
        private static string GetDisplayNameValue(IList<CustomAttributeData> attrs)
        {
            var argument = attrs.FirstOrDefault(x => x.AttributeType.Name == nameof(DisplayAttribute)).NamedArguments;
            return argument.FirstOrDefault(x => x.MemberName == nameof(DisplayAttribute.Name)).TypedValue.Value.ToString();
        }


获取某个属性的值以及别名


我们使用了这样的方式去设置获取一项信息


[Display(Name = "操作系统")]
        public string OSDescription { get { return RuntimeInformation.OSDescription; } }


因此我们要获取到一个类型所有的属性值和属性的特性值。


/// <summary>
        /// 获取某个类型的值以及名称
        /// </summary>
        /// <typeparam name="TInfo"></typeparam>
        /// <param name="info"></param>
        /// <returns></returns>
        private static (string, List<KeyValuePair<string, object>>) GetValues<TInfo>(TInfo info)
        {
            List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>();
            Type type = info.GetType();
            PropertyInfo[] pros = type.GetProperties();
            foreach (var item in pros)
            {
                var name = GetDisplayNameValue(item.GetCustomAttributesData());
                var value = GetPropertyInfoValue(item, info);
                list.Add(new KeyValuePair<string, object>(name, value));
            }
            return
                (GetDisplayNameValue(info.GetType().GetCustomAttributesData()),
                list);
        }


反射获取信息


上面的工具方法定义后,我们来设置不同的方法获取不同的信息。


/// <summary>
        /// 获取程序运行资源信息
        /// </summary>
        /// <returns></returns>
        public static (string, List<KeyValuePair<string, object>>) GetApplicationRunInfo()
        {
            ApplicationRunInfo info = new ApplicationRunInfo();
            return GetValues(info);
        }
        /// <summary>
        /// 获取系统运行平台信息
        /// </summary>
        /// <returns></returns>
        public static (string, List<KeyValuePair<string, object>>) GetSystemPlatformInfo()
        {
            SystemPlatformInfo info = new SystemPlatformInfo();
            return GetValues(info);
        }
        /// <summary>
        /// 获取系统运行环境信息
        /// </summary>
        /// <returns></returns>
        public static (string, List<KeyValuePair<string, object>>) GetSystemRunEvnInfo()
        {
            SystemRunEvnInfo info = new SystemRunEvnInfo();
            return GetValues(info);
        }


还有一个方法获取环境变量的,不需要利用上面的类型-属性来操作,可以直接封装到方法中。


/// <summary>
        /// 获取系统全部环境变量
        /// </summary>
        /// <returns></returns>
        public static (string, List<KeyValuePair<string, object>>) GetEnvironmentVariables()
        {
            List<KeyValuePair<string, object>> list = new List<KeyValuePair<string, object>>();
            IDictionary environmentVariables = Environment.GetEnvironmentVariables();
            foreach (DictionaryEntry de in environmentVariables)
            {
                list.Add(new KeyValuePair<string, object>(de.Key.ToString(), de.Value));
            }
            return ("系统环境变量", list);
        }


使用


我们在 Program 中,这些写就可以输出所有信息了


static void Main(string[] args)
        {
            var a = EnvironmentInfo.GetApplicationRunInfo();
            var b = EnvironmentInfo.GetSystemPlatformInfo();
            var c = EnvironmentInfo.GetSystemRunEvnInfo();
            var d = EnvironmentInfo.GetEnvironmentVariables();
            ConsoleInfo(a.Item1, a.Item2);
            ConsoleInfo(b.Item1, b.Item2);
            ConsoleInfo(c.Item1, c.Item2);
            ConsoleInfo(d.Item1, d.Item2);
            Console.ReadKey();
        }
        public static void ConsoleInfo(string title, List<KeyValuePair<string, object>> list)
        {
            Console.WriteLine("\n***********" + title + "***********");
            foreach (var item in list)
            {
                Console.WriteLine(item.Key + ":" + item.Value);
            }
        }


在 Linux 中显示


微信图片_20220503114225.png


总结


我以上使用了 类-属性 来作为获取功能,这样可以不必写很多方法去调用获取环境信息,属性就是数据。既方便序列化,又方便反射。


同时,如果先拓展信息项,直接添加上去就行,反射直接全部拿到手。

另外有个 Display 特性,专业用来显示信息项的。这样设置,可以为属性灵活设置别名,便于显示信息以及说明。


笔者会继续带来更多反射的使用实例,融入到日常需求中。

相关文章
|
11月前
|
开发框架 .NET C#
ASP.NET Core Blazor 路由配置和导航
大家好,我是码农刚子。本文系统介绍Blazor单页应用的路由机制,涵盖基础配置、路由参数、编程式导航及高级功能。通过@page指令定义路由,支持参数约束、可选参数与通配符捕获,结合NavigationManager实现页面跳转与参数传递,并演示用户管理、产品展示等典型场景,全面掌握Blazor路由从入门到实战的完整方案。
752 6
|
开发框架 .NET 开发者
简化 ASP.NET Core 依赖注入(DI)注册-Scrutor
Scrutor 是一个简化 ASP.NET Core 应用程序中依赖注入(DI)注册过程的开源库,支持自动扫描和注册服务。通过简单的配置,开发者可以轻松地从指定程序集中筛选、注册服务,并设置其生命周期,同时支持服务装饰等高级功能。适用于大型项目,提高代码的可维护性和简洁性。仓库地址:&lt;https://github.com/khellang/Scrutor&gt;
875 5
|
开发框架 .NET C#
在 ASP.NET Core 中创建 gRPC 客户端和服务器
本文介绍了如何使用 gRPC 框架搭建一个简单的“Hello World”示例。首先创建了一个名为 GrpcDemo 的解决方案,其中包含一个 gRPC 服务端项目 GrpcServer 和一个客户端项目 GrpcClient。服务端通过定义 `greeter.proto` 文件中的服务和消息类型,实现了一个简单的问候服务 `GreeterService`。客户端则通过 gRPC 客户端库连接到服务端并调用其 `SayHello` 方法,展示了 gRPC 在 C# 中的基本使用方法。
593 5
在 ASP.NET Core 中创建 gRPC 客户端和服务器
|
算法 Java 测试技术
Benchmark.NET:让 C# 测试程序性能变得既酷又简单
Benchmark.NET是一款专为 .NET 平台设计的性能基准测试框架,它可以帮助你测量代码的执行时间、内存使用情况等性能指标。它就像是你代码的 "健身教练",帮助你找到瓶颈,优化性能,让你的应用跑得更快、更稳!希望这个小教程能让你在追求高性能的路上越走越远,享受编程带来的无限乐趣!
1170 13
|
开发框架 算法 中间件
ASP.NET Core 中的速率限制中间件
在ASP.NET Core中,速率限制中间件用于控制客户端请求速率,防止服务器过载并提高安全性。通过`AddRateLimiter`注册服务,并配置不同策略如固定窗口、滑动窗口、令牌桶和并发限制。这些策略可在全局、控制器或动作级别应用,支持自定义响应处理。使用中间件`UseRateLimiter`启用限流功能,并可通过属性禁用特定控制器或动作的限流。这有助于有效保护API免受滥用和过载。 欢迎关注我的公众号:Net分享 (239字符)
534 1
|
弹性计算 开发框架 安全
基于云效 Windows 构建环境和 Nuget 制品仓库进行 .Net 应用开发
本文将基于云效 Flow 流水线 Windows 构建环境和云效 Packages Nuget 制品仓库手把手教你如何开发并部署一个 .NET 应用,从环境搭建到实战应用发布的详细教程,帮助你掌握 .NET 开发的核心技能。
|
开发框架 缓存 .NET
GraphQL 与 ASP.NET Core 集成:从入门到精通
本文详细介绍了如何在ASP.NET Core中集成GraphQL,包括安装必要的NuGet包、创建GraphQL Schema、配置GraphQL服务等步骤。同时,文章还探讨了常见问题及其解决方法,如处理复杂查询、错误处理、性能优化和实现认证授权等,旨在帮助开发者构建灵活且高效的API。
578 3
|
安全 算法 编译器
.NET 9 AOT的突破 - 支持老旧Win7与XP环境
【10月更文挑战第30天】在.NET 9 中,AOT(Ahead-of-Time)编译技术在支持老旧的 Windows 7 和 XP 系统方面取得了显著进展。主要突破包括:性能提升(启动速度加快、执行效率提高)、部署优化(无需安装.NET 运行时、减小应用程序体积)、兼容性保障(编译策略优化、依赖项管理改进)以及安全性增强(代码保护机制)。这些改进使得应用程序在老旧系统上运行更加流畅、高效和安全。
782 2
|
XML 安全 API
.NET 9 AOT的突破 - 支持老旧Win7与XP环境
.NET 9开始,AOT支持Win7和XP,不仅仅只支持SP1版本
.NET 9 AOT的突破 - 支持老旧Win7与XP环境
|
开发框架 JavaScript 前端开发
一个适用于 ASP.NET Core 的轻量级插件框架
一个适用于 ASP.NET Core 的轻量级插件框架
505 0