.NET Core 中上位机开发常用的方法和编程方式的详细说明之三

感谢您的持续关注!以下是继续补充的 .NET Core(现为 .NET,如 .NET 5/6/7/8)在上位机开发中常用的方法和编程方式,延续之前的详细说明,重点针对大数据量、硬件交互和高实时性需求场景。本部分将增加更多方法,涵盖网络通信、数据库操作、日志记录、配置文件管理以及其他现代化特性,确保内容全面且实用。每种方法都会提供详细说明、示例代码、上位机适用场景、注意事项,并与 .NET Framework 对比。


十、现代化开发与架构(续)

  1. Configuration Management (Microsoft.Extensions.Configuration)

    • 功能:提供灵活的配置管理,支持 JSON、XML、环境变量等多种配置源,适合动态加载上位机参数。

    • 上位机场景:加载硬件配置(如串口参数、PLC 地址)或系统设置(如采集频率)。

    • 示例:从 JSON 文件加载串口配置:

      csharp

      using Microsoft.Extensions.Configuration;
      
      public class HardwareConfig
      {
          public string PortName { get; init; }
          public int BaudRate { get; init; }
      }
      
      public class HardwareManager
      {
          private readonly HardwareConfig _config;
      
          public HardwareManager(IConfiguration configuration)
          {
              _config = configuration.GetSection("Hardware").Get<HardwareConfig>();
          }
      
          public void Start()
          {
              using var serialPort = new SerialPort(_config.PortName, _config.BaudRate);
              serialPort.Open();
              Console.WriteLine($"Connected to {_config.PortName} at {_config.BaudRate}");
          }
      }
      
      // appsettings.json
      {
          "Hardware": {
              "PortName": "COM1",
              "BaudRate": 9600
          }
      }
      
      public static IConfiguration BuildConfiguration()
      {
          return new ConfigurationBuilder()
              .SetBasePath(Directory.GetCurrentDirectory())
              .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
              .Build();
      }
    • 注意事项:

      • 使用 reloadOnChange: true 支持运行时配置更新。

      • 确保配置文件的访问权限,特别是在嵌入式设备上。

    • 优势:集中管理配置,支持动态更新,适合工业环境的多设备配置。

    • 对比 .NET Framework:Framework 依赖 System.Configuration,功能较简单,缺乏 JSON 支持和动态加载。

  2. Logging (Microsoft.Extensions.Logging)

    • 功能:提供结构化日志框架,支持多目标输出(如控制台、文件、远程服务)。

    • 上位机场景:记录硬件通信、数据处理错误或性能指标。

    • 示例:记录传感器数据处理日志:

      csharp

      using Microsoft.Extensions.Logging;
      
      public class DataProcessor
      {
          private readonly ILogger<DataProcessor> _logger;
      
          public DataProcessor(ILogger<DataProcessor> logger)
          {
              _logger = logger;
          }
      
          public async Task ProcessDataAsync(byte[] data)
          {
              _logger.LogInformation("Processing data of length {Length}", data.Length);
              try
              {
                  await Task.Delay(10); // 模拟处理
              }
              catch (Exception ex)
              {
                  _logger.LogError(ex, "Failed to process data");
              }
          }
      }
      
      public static ILoggerFactory BuildLoggerFactory()
      {
          return LoggerFactory.Create(builder =>
          {
              builder.AddConsole();
              builder.AddFile("logs/app.log");
          });
      }
    • 注意事项:

      • 使用 ILoggerFactory 配置日志目标(如 Serilog 集成更强大的功能)。

      • 控制日志级别(Information、Error),避免过多日志影响性能。

    • 优势:结构化日志易于分析,适合工业环境中的调试和监控。

    • 对比 .NET Framework:Framework 依赖 Trace 或第三方库(如 log4net),配置复杂且性能稍逊。


十一、数据库与数据存储

  1. Entity Framework Core (EF Core)

    • 功能:轻量级 ORM,支持异步查询和批量操作,优化数据库交互。

    • 上位机场景:存储传感器数据到数据库(如 SQLite、SQL Server)。

    • 示例:异步保存传感器数据:

      csharp

      using Microsoft.EntityFrameworkCore;
      
      public class SensorData
      {
          public int Id { get; set; }
          public double Value { get; set; }
          public DateTime Timestamp { get; set; }
      }
      
      public class AppDbContext : DbContext
      {
          public DbSet<SensorData> SensorData { get; set; }
      
          public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
      }
      
      public async Task SaveSensorDataAsync(SensorData data)
      {
          using var scope = _serviceProvider.CreateScope();
          var dbContext = scope.ServiceProvider.GetService<AppDbContext>();
          dbContext.SensorData.Add(data);
          await dbContext.SaveChangesAsync();
      }
      
      // 配置 SQLite 数据库
      public static IServiceProvider BuildServiceProvider()
      {
          var services = new ServiceCollection();
          services.AddDbContext<AppDbContext>(options =>
              options.UseSqlite("Data Source=sensors.db"));
          return services.BuildServiceProvider();
      }
    • 注意事项:

      • 使用异步方法(如 SaveChangesAsync)避免阻塞。

      • 批量插入优化性能(如 AddRangeAsync)。

    • 优势:异步查询和轻量级设计,适合高吞吐量数据存储(每秒 1000 条+)。

    • 对比 .NET Framework:EF Core 比 EF 6 更轻量,性能更高,支持跨平台。

  2. SqlBulkCopy (System.Data.SqlClient)

    • 功能:高效批量插入数据到 SQL Server,适合大数据量。

    • 上位机场景:存储大量传感器数据(如每秒 10 万条)。

    • 示例:

      csharp

      using System.Data.SqlClient;
      
      public async Task BulkInsertDataAsync(List<SensorData> dataList)
      {
          using var connection = new SqlConnection("Server=localhost;Database=Sensors;Trusted_Connection=True;");
          await connection.OpenAsync();
          using var bulkCopy = new SqlBulkCopy(connection);
          bulkCopy.DestinationTableName = "SensorData";
          var dataTable = new DataTable();
          dataTable.Columns.Add("Id", typeof(int));
          dataTable.Columns.Add("Value", typeof(double));
          dataTable.Columns.Add("Timestamp", typeof(DateTime));
          foreach (var data in dataList)
          {
              dataTable.Rows.Add(data.Id, data.Value, data.Timestamp);
          }
          await bulkCopy.WriteToServerAsync(dataTable);
      }
    • 注意事项:

      • 确保表结构匹配 DataTable。

      • 使用事务提高一致性。

    • 优势:批量插入性能极高,适合大数据量场景。

    • 对比 .NET Framework:功能类似,但 .NET Core 的异步支持更强。


十二、网络通信

  1. HttpClient with HttpClientFactory

    • 功能:优化 HTTP 请求管理,支持连接池和异步操作。

    • 上位机场景:与云端或远程服务器通信(如上传传感器数据到 Azure IoT Hub)。

    • 示例:

      csharp

      using System.Net.Http;
      using Microsoft.Extensions.DependencyInjection;
      
      public class CloudService
      {
          private readonly IHttpClientFactory _clientFactory;
      
          public CloudService(IHttpClientFactory clientFactory)
          {
              _clientFactory = clientFactory;
          }
      
          public async Task SendDataAsync(SensorData data)
          {
              var client = _clientFactory.CreateClient();
              var content = JsonContent.Create(data);
              var response = await client.PostAsync("https://api.example.com/data", content);
              response.EnsureSuccessStatusCode();
          }
      }
      
      public static IServiceProvider BuildServiceProvider()
      {
          var services = new ServiceCollection();
          services.AddHttpClient();
          return services.BuildServiceProvider();
      }
    • 注意事项:

      • 使用 IHttpClientFactory 管理 HttpClient 生命周期,避免端口耗尽。

      • 配置超时和重试策略(结合 Polly)。

    • 优势:高效、可靠的 HTTP 通信,适合云集成。

    • 对比 .NET Framework:Framework 的 HttpClient 易导致资源泄漏,需手动管理。

  2. gRPC

    • 功能:高性能 RPC 框架,适合低延迟、高吞吐量通信。

    • 上位机场景:与远程工业设备或服务器通信(如实时控制指令)。

    • 示例:

      csharp

      // proto 文件
      service DataService {
          rpc SendSensorData (SensorDataRequest) returns (SensorDataResponse);
      }
      
      // C# 客户端
      using Grpc.Net.Client;
      
      public class GrpcClient
      {
          private readonly DataService.DataServiceClient _client;
      
          public GrpcClient()
          {
              var channel = GrpcChannel.ForAddress("https://localhost:5001");
              _client = new DataService.DataServiceClient(channel);
          }
      
          public async Task SendDataAsync(SensorData data)
          {
              var request = new SensorDataRequest { Id = data.Id, Value = data.Value };
              var response = await _client.SendSensorDataAsync(request);
              Console.WriteLine($"Response: {response.Status}");
          }
      }
    • 注意事项:

      • 配置 gRPC 通道(HTTP/2)以优化性能。

      • 确保服务器支持 gRPC。

    • 优势:低延迟(<10ms),高吞吐量,适合实时通信。

    • 对比 .NET Framework:Framework 无内置 gRPC 支持,需使用第三方库。


十三、其他实用方法

  1. System.Text.Json

    • 功能:高性能 JSON 序列化/反序列化,替代 Newtonsoft.Json。

    • 上位机场景:序列化传感器数据以发送到云端或存储。

    • 示例:

      csharp

      using System.Text.Json;
      
      public async Task SerializeDataAsync(SensorData data)
      {
          using var stream = new MemoryStream();
          await JsonSerializer.SerializeAsync(stream, data, new JsonSerializerOptions { WriteIndented = true });
          Console.WriteLine($"Serialized: {Encoding.UTF8.GetString(stream.ToArray())}");
      }
    • 注意事项:

      • 使用 JsonSerializerOptions 配置序列化行为(如忽略 null 值)。

      • 对于复杂对象,可能需自定义转换器。

    • 优势:性能高于 Newtonsoft.Json,内存占用低。

    • 对比 .NET Framework:Framework 依赖 Newtonsoft.Json,性能稍逊。

  2. PeriodicTimer

    • 功能:提供高精度定时器,支持异步定时任务。

    • 上位机场景:周期性采集硬件数据(如每 50ms 读取一次)。

    • 示例:

      csharp

      public async Task RunPeriodicAcquisitionAsync(CancellationToken ct)
      {
          using var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(50));
          while (await timer.WaitForNextTickAsync(ct))
          {
              byte[] data = await ReadFromHardwareAsync();
              Console.WriteLine($"Data collected: {data.Length} bytes");
          }
      }
    • 注意事项:

      • 确保任务执行时间短于定时间隔,防止任务堆积。

      • 使用 CancellationToken 控制停止。

    • 优势:异步友好,高精度,适合实时性要求。

    • 对比 .NET Framework:Framework 依赖 System.Timers.Timer,异步支持较弱。

  3. ValueTuple

    • 功能:轻量级元组类型,支持多值返回,性能优于匿名类型。

    • 上位机场景:从硬件读取多种数据(如 ID 和值)。

    • 示例:

      csharp

      public async ValueTask<(int Id, double Value)> ReadSensorAsync()
      {
          byte[] buffer = new byte[12];
          int bytesRead = await _serialPort.BaseStream.ReadAsync(buffer);
          return (buffer[0], BitConverter.ToDouble(buffer, 4));
      }
    • 注意事项:

      • 使用命名元组提高可读性:

        csharp

        return (Id: buffer[0], Value: BitConverter.ToDouble(buffer, 4));
    • 优势:减少对象分配,适合高频调用。

    • 对比 .NET Framework:Framework 支持 Tuple,但性能较低。


十四、综合示例:完整上位机应用

以下是一个综合示例,整合多种方法,展示实时采集、处理、存储和显示的完整上位机流程:

csharp

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System.IO.Ports;
using System.Text.Json;
using System.Threading.Channels;
using System.Threading.Tasks.Dataflow;

public record SensorData(int Id, double Value, DateTime Timestamp);

public class HardwareManager
{
    private readonly SerialPort _serialPort;
    private readonly ILogger<HardwareManager> _logger;

    public HardwareManager(IConfiguration config, ILogger<HardwareManager> logger)
    {
        var portName = config["Hardware:PortName"];
        var baudRate = int.Parse(config["Hardware:BaudRate"]);
        _serialPort = new SerialPort(portName, baudRate);
        _serialPort.Open();
        _logger = logger;
    }

    public async ValueTask<byte[]> ReadAsync(CancellationToken ct)
    {
        byte[] buffer = ArrayPool<byte>.Shared.Rent(1024);
        try
        {
            int bytesRead = await _serialPort.BaseStream.ReadAsync(buffer, ct);
            _logger.LogInformation("Read {Bytes} bytes from hardware", bytesRead);
            return buffer.AsSpan(0, bytesRead).ToArray();
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Hardware read failed");
            throw;
        }
        finally
        {
            ArrayPool<byte>.Shared.Return(buffer);
        }
    }
}

public class DataProcessor
{
    private readonly Channel<SensorData> _dataChannel = Channel.CreateBounded<SensorData>(10000);
    private readonly HardwareManager _hardware;
    private readonly ILogger<DataProcessor> _logger;
    private readonly TransformBlock<byte[], SensorData> _parseBlock;
    private readonly ActionBlock<SensorData> _storeBlock;

    public DataProcessor(HardwareManager hardware, ILogger<DataProcessor> logger)
    {
        _hardware = hardware;
        _logger = logger;
        _parseBlock = new TransformBlock<byte[], SensorData>(
            data => new SensorData(data[0], BitConverter.ToDouble(data, 1), DateTime.Now),
            new ExecutioncouponDataflowBlockOptions { MaxDegreeOfParallelism = 2 });
        _storeBlock = new ActionBlock<SensorData>(
            async data => await StoreAsync(data),
            new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 1 });
        _parseBlock.LinkTo(_storeBlock, new DataflowLinkOptions { PropagateCompletion = true });
    }

    public async Task StartAcquisitionAsync(CancellationToken ct)
    {
        using var timer = new PeriodicTimer(TimeSpan.FromMilliseconds(50));
        while (await timer.WaitForNextTickAsync(ct))
        {
            byte[] rawData = await _hardware.ReadAsync(ct);
            await _parseBlock.SendAsync(rawData, ct);
        }
    }

    public async Task ProcessDataAsync(CancellationToken ct)
    {
        await _storeBlock.Completion;
    }

    private async Task StoreAsync(SensorData data)
    {
        // 模拟存储到数据库或云端
        await Task.Delay(10);
        _logger.LogInformation("Stored: {Data}", JsonSerializer.Serialize(data));
    }
}

public class Program
{
    public static async Task Main()
    {
        var services = new ServiceCollection();
        services.AddLogging(builder => builder.AddConsole());
        services.AddSingleton<IConfiguration>(BuildConfiguration());
        services.AddSingleton<HardwareManager>();
        services.AddSingleton<DataProcessor>();
        var provider = services.BuildServiceProvider();

        var processor = provider.GetService<DataProcessor>();
        using var cts = new CancellationTokenSource();

        var acquisitionTask = processor.StartAcquisitionAsync(cts.Token);
        var processingTask = processor.ProcessDataAsync(cts.Token);

        Console.ReadLine();
        cts.Cancel();
        await Task.WhenAll(acquisitionTask, processingTask);
    }

    private static IConfiguration BuildConfiguration()
    {
        return new ConfigurationBuilder()
            .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
            .Build();
    }
}

// appsettings.json
{
    "Hardware": {
        "PortName": "COM1",
        "BaudRate": 9600
    }
}

示例说明:

  • 硬件交互:HardwareManager 使用 SerialPort 和 ValueTask 异步读取数据,结合 ArrayPool 优化内存。

  • 数据处理:DataProcessor 使用 Channel 和 Dataflow 构建采集-解析-存储管道,支持高并发。

  • 配置管理:通过 IConfiguration 加载 JSON 配置。

  • 日志记录:使用 ILogger 记录操作和错误。

  • 定时采集:PeriodicTimer 每 50ms 采集一次数据,满足高实时性。

  • 现代化特性:record 定义数据模型,DI 管理服务。


十五、总结

常用方法汇总(补充后):

  • 异步与并发:Task.Run, Task.WhenAll, Parallel.ForEachAsync, Channels, ValueTask, Dataflow, IAsyncEnumerable, PeriodicTimer.

  • 内存优化:Span<T>, Memory<T>, ArrayPool<T>, RecyclableMemoryStream, Pipelines.

  • 硬件交互:System.IO.Ports(异步增强)、OPC UA Client, Modbus.Net.

  • 数据库:EF Core, SqlBulkCopy.

  • 网络通信:HttpClientFactory, gRPC.

  • UI 管理:.NET MAUI, Dispatcher.

  • 并发安全:Concurrent Collections, Interlocked, ReaderWriterLockSlim.

  • 容错:Polly, CancellationToken.

  • 诊断:System.Diagnostics.Metrics, EventSource.

  • 现代化开发:Records, Init-only Properties, Pattern Matching, Dependency Injection, Configuration, Logging, System.Text.Json, ValueTuple.

上位机优势:

  • 大数据量:Span<T>, Pipelines, IAsyncEnumerable, SqlBulkCopy 处理每秒 100MB+ 数据,内存效率高。

  • 硬件交互:异步 API(ReadAsync, OPC UA, Modbus)降低延迟(<50ms),支持现代协议。

  • 高实时性:ValueTask, PeriodicTimer, Parallel.ForEachAsync 满足 <10ms 延迟需求。

  • 现代化开发:MAUI, DI, Configuration, Logging 提高可维护性和跨平台能力。

对比 .NET Framework:

  • .NET Core 提供更高性能(延迟低 20%-50%)、跨平台支持、现代化特性。

  • Framework 缺乏 Span<T>, IAsyncEnumerable, Pipelines, gRPC 等,异步和内存优化较弱。

若需更具体的实现(如特定硬件协议、数据库类型、UI 框架)或性能优化建议,请提供更多细节,我可进一步定制代码!

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhxup606

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值