写C# 一直很羡慕Java的@Autowired 自动装配. 因为C# 必须手动在Ioc里注册
之前用接口实现了自动注册IOC, 总是觉得美中不足, 毕竟没有真正实现用注解/特性实现自动注入, 这次我们来实现一个用特性注入Ioc的扩展方法.
namespace MyCode.BLL.Service.Ioc
{
/// <summary>
/// 类型的生命周期枚举
/// </summary>
public enum Lifetime
{
/// <summary>
/// 单例
/// </summary>
Singleton,
/// <summary>
/// 多例
/// </summary>
Transient,
Scoped
}
/// <summary>
/// 标注类型的生命周期、是否自动初始化
/// </summary>
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class ExposedServiceAttribute : Attribute
{
public Lifetime Lifetime { get; set; }
public bool AutoInitialize { get; set; }
public Type[] Types { get; set; }
public ExposedServiceAttribute(Lifetime lifetime = Lifetime.Transient, params Type[] types)
{
Lifetime = lifetime;
Types = types;
}
}
}
using Microsoft.Extensions.DependencyInjection;
using MyCode.BLL.Service.Ioc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace MyCode.Utils.AttributeIoc
{
public static class DependencyExtension
{
/// <summary>
/// 获取class, 非抽象类, 特性有ExposedServiceAttribute 注解
/// </summary>
/// <param name="services"></param>
/// <returns></returns>
//private static List<Type> GetTypes(Assembly assembly)
//{
// var result = assembly
// .GetTypes()
// .Where(
// t =>
// t != null
// && t.IsClass
// && !t.IsAbstract
// && t.CustomAttributes.Any(
// p => p.AttributeType == typeof(ExposedServiceAttribute)
// )
// )
// .ToList();
// return result;
//}
private static List<Type> MyGetTypes()
{
//获取当前程序集
var entryAssembly = Assembly.GetEntryAssembly();
var types = entryAssembly!
.GetReferencedAssemblies() //获取当前程序集所引用的外部程序集
.Select(Assembly.Load) //装载
.Concat(new List<Assembly>() { entryAssembly }) //与本程序集合并
.SelectMany(x => x.GetTypes()) //获取所有类
.Where(
t =>
t != null
&& t.IsClass
&& !t.IsAbstract
&& t.CustomAttributes.Any(
p => p.AttributeType == typeof(ExposedServiceAttribute)
)
)
.Distinct() //排重
.ToList();
;
return types;
}
//public static void RegisterAssembly(this IServiceCollection services, Assembly assembly)
//{
// var list = GetTypes(assembly);
// foreach (var type in list)
// {
// RegisterAssembly(services, type);
// }
//}
/// <summary>
/// 加this 表示 IServiceCollection 的扩展方法
/// </summary>
/// <param name="services"></param>
public static void RegisterAssembly(this IServiceCollection services)
{
var list = MyGetTypes();
foreach (var type in list)
{
RegisterAssembly(services, type);
}
}
public static void RegisterAssembly(IServiceCollection services, Type type)
{
var list = GetExposedServices(type).ToList();
foreach (var item in list)
{
switch (item.Lifetime)
{
case Lifetime.Singleton:
services.AddSingleton(type);
break;
case Lifetime.Transient:
services.AddTransient(type);
break;
case Lifetime.Scoped:
services.AddScoped(type);
break;
default:
break;
}
foreach (var IType in item.Types)
{
switch (item.Lifetime)
{
case Lifetime.Singleton:
services.AddSingleton(IType, type);
break;
case Lifetime.Transient:
services.AddTransient(IType, type);
break;
case Lifetime.Scoped:
services.AddScoped(IType, type);
break;
default:
break;
}
}
}
}
在Ioc注册:
services.RegisterAssembly();
在View中使用:
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using MyCode.BLL.Models;
using MyCode.BLL.Service.Ioc;
using S7.Net;
using System.Collections.ObjectModel;
using System.Reflection;
namespace MyCode.BLL.Service.PLCService.Impl
{
[ExposedService(Lifetime.Singleton, typeof(IS7ConnService))]
public class S7ConnServiceImpl : IS7ConnService
{
private readonly ILogger<S7ConnServiceImpl> logger;
private ConfigurationBuilder cfgBuilder = new ConfigurationBuilder();
private string myIp;
private CancellationTokenSource cts = new();
private int errorTimes = 0;
private static readonly object lockObj = new object(); // 创建一个对象作为锁
private MyS7Entity s7Entity = new();
public ObservableCollection<PLCModel> PLCModels { get; set; } = new();
public S7ConnServiceImpl(ILogger<S7ConnServiceImpl> logger)
{
this.logger = logger;
cfgBuilder.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
IConfigurationRoot configRoot = cfgBuilder.Build();
myIp = configRoot.GetSection("PlcIp").Value;
PLCModels = new(configRoot.GetSection("PLCModels").Get<List<PLCModel>>());
//IConfigurationSection plcModelsSection = configRoot.GetSection("PLCModels");
//plcModelsSection.Bind(PLCModels);
}
private bool myIsConnected = false;
public bool MyIsConnected
{
get => myIsConnected;
set
{
if (myIsConnected == false && value == true)
{
logger.LogInformation("PLC连接成功!");
}
myIsConnected = value;
}
}
private Plc myS7Master;
public Plc MyS7Master => myS7Master;
public void ConnPlc()
{
Task.Run(
async () =>
{
while (!cts.IsCancellationRequested)
{
if (myS7Master == null || !MyIsConnected)
{
try
{
myS7Master = new Plc(CpuType.S71500, myIp, 0, 0);
myS7Master.Open();
MyIsConnected = myS7Master.IsConnected;
}
catch (Exception ex)
{
myS7Master.Close();
myS7Master = null;
MyIsConnected = false;
logger.LogError(ex.Message);
await Task.Delay(2000);
}
}
else if (MyIsConnected)
{
//注入Client
//var url = "http://localhost:5190/api/private/v1/My/MyGet"; // 目标 Web API 的地址
//var response = clientFactory?.CreateClient().GetAsync(url);
//var response = await httpClient.GetAsync(url);
//if (response.IsSuccessStatusCode)
//{
// var content = await response.Content.ReadAsStringAsync();
// logger.LogError(content);
//}
try
{
MyIsConnected = myS7Master.IsConnected;
await Task.Delay(500);
s7Entity = await myS7Master.ReadClassAsync<MyS7Entity>(1, 0);
lock (lockObj)
{
PropertyInfo[] fields = s7Entity
.GetType()
.GetProperties(
BindingFlags.NonPublic
| BindingFlags.Instance
| BindingFlags.Public
);
//foreach (var item1 in fields)
//{
// foreach (var item2 in PLCModels)
// {
// if (item1.Name == item2.Name)
// {
// item2.PlcValue = item1
// .GetValue(s7Entity)
// .ToString();
// break;
// }
// }
//}
Dictionary<string, string> fieldValues = new();
// 将属性名称和值存储在字典中
foreach (var item in fields)
{
fieldValues[item.Name] = item.GetValue(s7Entity).ToString();
}
// 使用字典查找更新PLC模型的值
foreach (var item2 in PLCModels)
{
if (fieldValues.ContainsKey(item2.Name))
{
item2.PlcValue = fieldValues[item2.Name];
}
}
//myS7Entry.DateTime1 = (DateTime)myS7Master.Read(DataType.DataBlock, 1, 36, VarType.DateTime, 1);
}
}
catch (Exception ex)
{
errorTimes++;
await Task.Delay(1000);
logger.LogError($"读取时发生错误:{ex.Message}");
logger.LogError($"读取时发生错误次数:{errorTimes}");
myS7Master.Close();
MyIsConnected = false;
myS7Master = null;
}
}
}
},
cts.Token
);
}
}
}
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using MyCode.BLL.Models;
using MyCode.BLL.Service.Ioc;
using MyCode.BLL.Service.PLCService;
using System.Collections.ObjectModel;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Windows;
using System.Windows.Media;
namespace MyCode.ViewModels
{
[ExposedService(Lifetime.Singleton)]
public partial class TcpServerViewModel : ObservableObject
{
private readonly ILogger<TcpServerViewModel> logger;
//声明一个Socket对象
private Socket socketSever;
private CancellationTokenSource cts = new();
private ConfigurationBuilder cfgBuilder = new ConfigurationBuilder();
[ObservableProperty]
private string? myIp;
[ObservableProperty]
private string? myPort;
[ObservableProperty]
private ObservableCollection<string> serverList = new();
[ObservableProperty]
private ObservableCollection<TcpMessage> reciveData = new();
[ObservableProperty]
private string? sendTxt;
[ObservableProperty]
private ObservableCollection<PLCModel> myPlcData = new();
[ObservableProperty]
private Brush myBrush;
public TcpServerViewModel(ILogger<TcpServerViewModel> logger, IS7ConnService s7ConnService)
{
myIp = "192.168.2.180";
myPort = "8888";
cfgBuilder.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
IConfigurationRoot configRoot = cfgBuilder.Build();
this.logger = logger;
//MyPort = configRoot.GetSection("PlcIp").Value;
//IConfigurationSection plcModelsSection = configRoot.GetSection("PLCModels");
//List<PLCModel> plcModels = new List<PLCModel>();
//plcModelsSection.Bind(plcModels);
//logger.LogError(JsonSerializer.Serialize(plcModels));
s7ConnService.ConnPlc();
MyPlcData = s7ConnService.PLCModels;
}
[RelayCommand]
public void Conn()
{
socketSever = new Socket(
AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp
);
if (MyIp != null && MyPort != null)
{
IPEndPoint ipe = new IPEndPoint(IPAddress.Parse(MyIp), int.Parse(this.MyPort));
}
else
{
MessageBox.Show("Ip,端口号不能为空!");
}
}
[RelayCommand]
public void DisConn() { }
[RelayCommand]
public void SendMsg() { }
[RelayCommand]
public void MyItemsBtn(PLCModel pLCModel)
{
}
}
}
成功结果: