.Net中使用Castle进行IOC+AOP(动态注入+代理)
一、nuget安装Castle
Install-Package Castle.Windsor
二、定义空接口作为标识:所有实现改接口的,说明需要依赖注入或代理(AOP代理必须在IOC基础之上)
public interface ILingbugService
{
}
三、定义特性:作用于服务类/接口上,说明要使用哪个Interceptor进行AOP代理(具体作用于服务类还是接口,看个人喜好)
public class LingbugInterceptorAttribute : Attribute
{
public LingbugInterceptorAttribute(params Type[] interceptorTypes)
{
//初始化拦截器集合
this.InterceptorTypes = new List<Type>();
//将拦截器添加到集合中
if (interceptorTypes != null && interceptorTypes.Length > 0) this.InterceptorTypes.AddRange(interceptorTypes);
}
public List<Type> InterceptorTypes { get; set; }
}
四、定义注册类,实现注册接口(在该类中,编写核心逻辑将IOC和AOP注入到容器中)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Castle.Core;
using Castle.DynamicProxy;
using Castle.MicroKernel;
using Castle.MicroKernel.Registration;
namespace TestCastle
{
public class CastleRegister : IRegistration
{
public void Register(IKernelInternal kernel)
{
//需要注入的集合
var registerComponentList = new List<IRegistration>();
//当前程序集所有类
var typeList = Assembly.GetExecutingAssembly().GetTypes().ToList();
//所有拦截器
var interceptorTypes = typeList.FindAll(r => typeof(IInterceptor).IsAssignableFrom(r));
//将拦截器添加到集合
registerComponentList.AddRange(interceptorTypes.Select(r => Component.For(r).ImplementedBy(r)));
//所有服务类
var serviceTypes = typeList.FindAll(r => typeof(ILingbugService).IsAssignableFrom(r) && !r.IsInterface);
serviceTypes.ForEach(s =>
{
//要注入的接口类
Type interfaceItemType = null;
//该类实现的所有接口
var interfaceItemTypes = s.GetInterfaces().Where(r => r.Name != typeof(ILingbugService).Name).ToArray();
if (interfaceItemTypes.Length > 0)
{
if (interfaceItemTypes.Length > 1)
{
//接口名
string interfaceItemTypeName = $"I{s.Name}";
//根据名称找接口
interfaceItemType = interfaceItemTypes.FirstOrDefault(r => r.Name == interfaceItemTypeName);
if (interfaceItemType == null)
{
//根据名称没找到,提示
Console.WriteLine($"服务类【{s.FullName}】未找到任何接口类【接口名:{interfaceItemTypeName}】");
}
}
else
{
//只实现了一个接口
interfaceItemType = interfaceItemTypes[0];
}
}
else
{
//没有实现任何接口,提示
Console.WriteLine($"服务类【{s.FullName}】没有实现任何接口");
}
if (interfaceItemType != null)
{
//依赖注入
var ioc = Component.For(interfaceItemType).ImplementedBy(s).LifestyleSingleton();
//获取到拦截器特性
var attrInterceptor = s.GetCustomAttribute<LingbugInterceptorAttribute>();
if (attrInterceptor != null && attrInterceptor.InterceptorTypes != null && attrInterceptor.InterceptorTypes.Count > 0)
{
//拦截器集合
var interceptors = attrInterceptor.InterceptorTypes.Select(r => InterceptorReference.ForType(r)).ToArray();
//添加拦截器
ioc = ioc.Interceptors(interceptors).Anywhere;
}
//添加到注入集合中
registerComponentList.Add(ioc);
}
});
//注入
kernel.Register(registerComponentList.ToArray());
}
}
}
五、定义启动类,在该类中进行容器初始化,在Web开发中,一般在Global.cs中调用
public class DependencyResolver
{
private static IWindsorContainer _container;
public static void Init()
{
//初始化容器
_container = new WindsorContainer();
//动态注入到容器中
_container.Register(new CastleRegister());
}
public static T Resolve<T>()
{
//从容器中解析对象
return _container.Resolve<T>();
}
}
六、编写测试代码
6.1、根据需求定义拦截对象(实现接口IInterceptor)
using System;
using Castle.DynamicProxy;
namespace TestCastle
{
/// <summary>
/// 拦截器一
/// </summary>
public class EatInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
//标识名
string name = nameof(EatInterceptor);
try
{
//参数
string paraStr = string.Join(",", invocation.Arguments);
//执行前
Console.WriteLine($"【{name}】开始执行方法:{invocation.Method.Name},参数:{paraStr}");
//获取到第一个参数
string food = invocation.Arguments[0].ToString();
if (food == "香蕉")
{
//价格
var money = Convert.ToDecimal(invocation.Arguments[1]);
//打折后的价格
var newMoney = money * Convert.ToDecimal(0.8);
//打印
Console.WriteLine($"今天{food}打折,原价【{money}】,折后价【{newMoney}】");
//修改参数
invocation.SetArgumentValue(1, newMoney);
}
//执行代理的方法逻辑
invocation.Proceed();
//执行后
Console.WriteLine($"【{name}】方法【{invocation.Method.Name}】执行完毕,参数:{paraStr},返回值:{invocation.ReturnValue}");
}
catch (Exception ex)
{
//异常
Console.WriteLine($"【{name}】执行方法【{invocation.Method.Name}】发生异常:{ex.Message}");
}
}
}
}
using System;
using Castle.DynamicProxy;
namespace TestCastle
{
/// <summary>
/// 拦截器二
/// </summary>
public class PersonInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
//标识名
string name = nameof(PersonInterceptor);
try
{
//参数
string paraStr = string.Join(",", invocation.Arguments);
//执行前
Console.WriteLine($"【{name}】开始执行方法:{invocation.Method.Name},参数:{paraStr}");
//执行代理的方法逻辑
invocation.Proceed();
//执行后
Console.WriteLine($"【{name}】方法【{invocation.Method.Name}】执行完毕,参数:{paraStr},返回值:{invocation.ReturnValue}");
}
catch (Exception ex)
{
//异常
Console.WriteLine($"【{name}】执行方法【{invocation.Method.Name}】发生异常:{ex.Message}");
}
}
}
}
6.2、编写服务接口和服务实现类
/// <summary>
/// 服务接口
/// </summary>
public interface IPerson : ILingbugService
{
string Eat(string food, decimal money);
}
/// <summary>
/// 服务实现类
/// </summary>
[LingbugInterceptor(typeof(EatInterceptor), typeof(PersonInterceptor))]
public class Person : IPerson
{
public string Name { get; set; }
public int? Age { get; set; }
public string Sex { get; set; }
public string Eat(string food, decimal money)
{
//准备吃
Console.WriteLine($"{this.Name}花了【{money}】元买了【{food}】,准备吃饭");
//正在吃
for (int i = 0; i < 3; i++)
{
//打印消息
Console.WriteLine($"【{i + 1}】{this.Name}正在吃{food}...");
//等待
Thread.Sleep(1000);
}
//吃完了
Console.WriteLine($"{this.Name}吃完了{food}");
//返回
return $"姓名:{this.Name},年龄:{this.Age},性别:{this.Sex}";
}
}
6.3、测试代码
class Program
{
static void Main(string[] args)
{
Console.WriteLine("程序启动...");
//初始化容器
DependencyResolver.Init();
//初始化服务类
var person = DependencyResolver.Resolve<IPerson>();
try
{
//调用方法
var eatResult = person.Eat("香蕉", Convert.ToDecimal(9.5));
//打印运行结果
Console.WriteLine("运行结果:" + eatResult);
}
catch (Exception ex)
{
//异常
Console.WriteLine("Error:" + ex.Message);
}
Console.WriteLine("运行结束...");
Console.ReadKey();
}
}
6.4、运行测试
程序启动...
【EatInterceptor】开始执行方法:Eat,参数:香蕉,9.5
今天香蕉打折,原价【9.5】,折后价【7.60】
【PersonInterceptor】开始执行方法:Eat,参数:香蕉,7.60
花了【7.60】元买了【香蕉】,准备吃饭
【1】正在吃香蕉...
【2】正在吃香蕉...
【3】正在吃香蕉...
吃完了香蕉
【PersonInterceptor】方法【Eat】执行完毕,参数:香蕉,7.60,返回值:姓名:,年龄:,性别:
【EatInterceptor】方法【Eat】执行完毕,参数:香蕉,9.5,返回值:姓名:,年龄:,性别:
运行结果:姓名:,年龄:,性别:
运行结束...
补充:
说明:依赖注入的三种生命周期
- Singleton:单例
- Scoped:线程内单例(一次请求内单例)
- Transient:相当于New

本文详细介绍如何在.Net中利用Castle Windsor实现IOC容器管理和AOP动态代理,包括Nuget安装、定义接口、特性、注册类及启动类,通过具体实例展示依赖注入与切面编程的应用。
&spm=1001.2101.3001.5002&articleId=108263462&d=1&t=3&u=ca82023bfa174ef48c06e9341f9e43c9)
1671

被折叠的 条评论
为什么被折叠?



