C# , .netWebApi, WPF 用特性实现类似Java 的Ioc 自动装配@Component

写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)
        {

        }
    }
}

成功结果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

潘诺西亚的火山

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

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

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

打赏作者

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

抵扣说明:

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

余额充值