- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在通过将横切关注点(cross-cutting concerns)从主要业务逻辑中分离出来,以提高代码的模块化性、可维护性和复用性.
在传统的面向对象编程中,我们通常通过类和对象来组织和实现功能。然而,某些功能,如日志记录、事务管理、安全性检查等,可能会跨越多个对象和模块,这种跨越称为横切关注点。AOP 的核心思想是将这些横切关注点从业务逻辑中分离出来,通过特定的机制将它们应用到代码中,而不是通过直接修改业务逻辑来实现.
PostSharp(收费) 。
PostSharp是一个功能强大的AOP框架,它通过编译器插件的形式集成到Visual Studio中。PostSharp支持编译时AOP(通过C#特性应用切面),并提供了丰富的切面类型,包括方法拦截、属性访问拦截、异常处理等。它还提供了商业支持和丰富的文档.
Castle DynamicProxy 。
Castle DynamicProxy是Castle项目的一部分,它允许开发者在运行时动态创建代理类,这些代理类可以拦截对目标对象的调用,并在调用前后执行自定义逻辑。虽然它本身不是一个完整的AOP框架,但它经常被用作构建AOP解决方案的基础.
AspectCore Framework 。
AspectCore 是一个开源的 AOP 框架,专为 .NET Core 设计。它提供了基于动态代理的运行时切面和方法拦截机制,支持常见的切面编程需求,如日志、缓存、事务等.
1. 安装Castle.Core NuGet包 。
Install-Package Castle.Core
2. 定义接口和类 。
假设你有一个接口和一个实现了该接口的类,你想要拦截这个类的方法调用.
public interface IMyService
{
void PerformAction();
}
public class MyService : IMyService
{
public void PerformAction()
{
Console.WriteLine("Action performed.");
}
}
3. 创建拦截器 。
接下来,你需要创建一个拦截器类,该类将实现IInterceptor接口。在这个接口的实现中,你可以定义在调用目标方法之前和之后要执行的逻辑.
using Castle.DynamicProxy;
public class MyInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
// 在调用目标方法之前执行的逻辑
Console.WriteLine("Before method: " + invocation.Method.Name);
// 调用目标方法
invocation.Proceed();
// 在调用目标方法之后执行的逻辑
Console.WriteLine("After method: " + invocation.Method.Name);
}
}
4. 创建代理并调用方法 。
最后,你需要使用ProxyGenerator类来创建MyService的代理实例,并指定拦截器。然后,你可以像使用普通对象一样调用代理的方法,但拦截器中的逻辑会在调用发生时执行.
using Castle.DynamicProxy;
public class Program
{
public static void Main(string[] args)
{
var generator = new ProxyGenerator();
var interceptor = new MyInterceptor();
// 创建MyService的代理实例,并指定拦截器
var proxy = generator.CreateInterfaceProxyWithTarget<IMyService>(
new MyService(), interceptor);
// 调用代理的方法,拦截器中的逻辑将被执行
proxy.PerformAction();
}
}
注意,上面的示例使用了接口代理(CreateInterfaceProxyWithTarget),这意味着你的目标类必须实现一个或多个接口。如果你想要代理一个类而不是接口,你可以使用CreateClassProxyWithTarget方法(但这通常用于需要代理非虚方法或字段的场景,且要求目标类是可继承的).
由于IOC容器(如Microsoft的IServiceCollection和IServiceProvider)通常不直接支持AOP,所以用 Autofac 1. 安装必要的 NuGet 包 。
首先,确保你的项目中安装了以下 NuGet 包:
Install-Package Autofac
Install-Package Autofac.Extensions.DependencyInjection
Install-Package Autofac.Extras.DynamicProxy
Install-Package Castle.Core
2. 创建服务接口和实现类 。
public class User
{
public long Id { get; set; }
public string Name { get; set; }
public long CreateUserId { get; set; }
public string CreateUserName { get; set; }
public DateTime CreateTime { get; set; }
public long UpdateUserId { get; set; }
public string UpdateUserName { get; set; }
public DateTime UpdateTime { get; set; }
}
public interface IUserService
{
void Test();
Task<int> TaskTest();
void Add(User user);
void Update(User user);
}
public class UserService : IUserService
{
public void Test()
{
Console.WriteLine("Test");
}
public async Task<int> TaskTest()
{
await Console.Out.WriteLineAsync("TaskTest");
return 1;
}
public void Add(User user)
{
Console.WriteLine(user.CreateUserId);
Console.WriteLine(user.CreateUserName);
}
public void Update(User user)
{
Console.WriteLine(user.UpdateUserId);
Console.WriteLine(user.UpdateUserName);
}
}
[ApiController]
[Route("[controller]")]
public class UserController : ControllerBase
{
readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
[HttpGet]
[Route("/taskTest")]
public async Task<string> TaskTest()
{
await _userService.TaskTest();
return "ok";
}
[HttpGet]
[Route("/test")]
public string Test()
{
_userService.Test();
return "ok";
}
[HttpGet]
[Route("/add")]
public string Add()
{
_userService.Add(new Model.User { Name = "张三" });
return "ok";
}
[HttpGet]
[Route("/update")]
public string Update()
{
_userService.Update(new Model.User { Name = "张三" });
return "ok";
}
}
3. 创建拦截器类 。
创建一个实现 IInterceptor 接口的拦截器类 LoggingInterceptor,用于拦截方法调用并添加日志记录:
public class LoggingInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine($"Before executing: {invocation.Method.Name}");
invocation.Proceed(); // 调用原始方法
Console.WriteLine($"After executing: {invocation.Method.Name}");
}
}
4. 配置 Autofac 容器 。
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()) //使用Autofac
.ConfigureContainer<ContainerBuilder>(autofacBuilder =>
{
autofacBuilder.RegisterType<LoggingInterceptor>();
autofacBuilder.RegisterType<UserService>().As<IUserService> ().SingleInstance().AsImplementedInterfaces()
.EnableInterfaceInterceptors() // 启用接口拦截器
.InterceptedBy(typeof(LoggingInterceptor)); //指定拦截器
});
与Autofac集成时,配置拦截器主要有两种方式 。
使用 InterceptAttribute 特性 。
这种方式通过在接口或类上添加[Intercept(typeof(YourInterceptor))]特性来指定拦截器。然后,在Autofac注册时,启用接口或类的拦截器。(通常不推荐在类上直接添加,因为这会使类与Autofac紧密耦合) 。
[Intercept(typeof(UserAutoFillInterceptor))]
public class UserService : IUserService
{
public void Test()
{
Console.WriteLine("Test");
}
}
autofacBuilder.RegisterType<UserService>().As<IUserService>().EnableInterfaceInterceptors() // 启用接口拦截器
使用 InterceptedBy() 方法 。
这种方式不依赖于[Intercept]特性,而是在注册服务时直接使用InterceptedBy()方法来指定拦截器.
autofacBuilder.RegisterType<UserService>().As<IUserService>()
.EnableInterfaceInterceptors() // 启用接口拦截器
.InterceptedBy(typeof(LoggingInterceptor)); //指定拦截器
拦截器基类 。
/// <summary>
/// 拦截基类
/// </summary>
/// <typeparam name="T"></typeparam>
public abstract class BaseInterceptor<T> : IInterceptor
{
protected readonly ILogger<T> _logger;
public BaseInterceptor(ILogger<T> logger)
{
_logger = logger;
}
/// <summary>
/// 拦截方法
/// </summary>
/// <param name="invocation"></param>
public virtual void Intercept(IInvocation invocation)
{
try
{
Method = invocation.MethodInvocationTarget ?? invocation.Method;
InterceptHandle(invocation);
}
catch (Exception ex)
{
_logger.LogError(ex, ex.Message);
throw ex;
}
}
/// <summary>
/// 拦截处理
/// </summary>
/// <param name="invocation"></param>
public abstract void InterceptHandle(IInvocation invocation);
protected MethodInfo Method{ get; set; }
public static bool IsAsyncMethod(MethodInfo method)
{
return (method.ReturnType == typeof(Task) ||
(method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
);
}
}
事务特性:用来判断是否需要事务管理的 。
/// <summary>
/// 事务特性
/// </summary>
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true)]
public class TransactionalAttribute : Attribute
{
public TransactionalAttribute()
{
Timeout = 60;
}
/// <summary>
///
/// </summary>
public int Timeout { get; set; }
/// <summary>
/// 事务隔离级别
/// </summary>
public IsolationLevel IsolationLevel { get; set; }
/// <summary>
/// 事务传播方式
/// </summary>
public Propagation Propagation { get; set; }
}
/// <summary>
/// 事务传播方式
/// </summary>
public enum Propagation
{
/// <summary>
/// 默认:如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中。
/// </summary>
Required = 0,
/// <summary>
/// 使用当前事务,如果没有当前事务,就抛出异常
/// </summary>
Mandatory = 1,
/// <summary>
/// 以嵌套事务方式执行
/// </summary>
Nested = 2,
}
事务拦截器:处理事务的 。
/// <summary>
/// 事务拦截器
/// </summary>
public class TransactionalInterceptor : BaseInterceptor<TransactionalInterceptor>
{
public TransactionalInterceptor(ILogger<TransactionalInterceptor> logger) : base(logger)
{
}
public override void InterceptHandle(IInvocation invocation)
{
if (Method.GetCustomAttribute<TransactionalAttribute>(true) == null && Method.DeclaringType?.GetCustomAttribute<TransactionalAttribute>(true) == null)
{
invocation.Proceed();
}
else
{
try
{
Console.WriteLine("开启事务");
//执行方法
invocation.Proceed();
// 异步获取异常,先执行
if (IsAsyncMethod(invocation.Method))
{
var result = invocation.ReturnValue;
if (result is Task)
{
Task.WaitAll(result as Task);
}
}
Console.WriteLine("提交事务");
}
catch (Exception ex)
{
Console.WriteLine("回滚事务");
_logger.LogError(ex, ex.Message);
throw ex;
}
}
}
}
接口上加入事务特性 。
//[Transactional]
public class UserService : IUserService
{
[Transactional]
public void Test()
{
Console.WriteLine("Test");
}
}
注入IOC 。
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer<ContainerBuilder>(autofacBuilder =>
{
autofacBuilder.RegisterType<TransactionalInterceptor>();
autofacBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance().AsImplementedInterfaces()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(TransactionalInterceptor));
});
测试 。
上下户用户 。
public interface IHttpContextUser
{
long UserId { get; }
string UserName { get;}
}
public class HttpContextUser : IHttpContextUser
{
private readonly IHttpContextAccessor _accessor;
public HttpContextUser(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public long UserId
{
get
{
return 1; //这里暂时是写死的
if (int.TryParse(_accessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Sid), out var userId))
{
return userId;
}
return default;
}
}
public string UserName
{
get
{
return "admin"; //这里暂时是写死的
return _accessor.HttpContext?.User?.FindFirstValue(ClaimTypes.Name) ?? "";
}
}
}
注入IOC 。
builder.Services.AddHttpContextAccessor();
builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureContainer<ContainerBuilder>(autofacBuilder =>
{
autofacBuilder.RegisterType<HttpContextUser>().As<IHttpContextUser>().SingleInstance().AsImplementedInterfaces();
autofacBuilder.RegisterType<UserAutoFillInterceptor>();
autofacBuilder.RegisterType<UserService>().As<IUserService>().SingleInstance().AsImplementedInterfaces()
.EnableInterfaceInterceptors()
.InterceptedBy(typeof(UserAutoFillInterceptor));
});
用户自动拦截器:处理用户填充的 。
/// <summary>
/// 用户自动填充拦截器
/// </summary>
public class UserAutoFillInterceptor : BaseInterceptor<UserAutoFillInterceptor>
{
private readonly IHttpContextUser _user;
public UserAutoFillInterceptor(ILogger<UserAutoFillInterceptor> logger,IHttpContextUser user) : base(logger)
{
_user = user;
}
public override void InterceptHandle(IInvocation invocation)
{
//对当前方法的特性验证
if (Method.Name?.ToLower() == "add" || Method.Name?.ToLower() == "update")
{
if (invocation.Arguments.Length == 1 && invocation.Arguments[0].GetType().IsClass)
{
dynamic argModel = invocation.Arguments[0];
var getType = argModel.GetType();
if (Method.Name?.ToLower() == "add")
{
if (getType.GetProperty("CreateUserId") != null)
{
argModel.CreateUserId = _user.UserId;
}
if (getType.GetProperty("CreateUserName") != null)
{
argModel.CreateUserName = _user.UserName;
}
if (getType.GetProperty("CreateTime") != null)
{
argModel.CreateTime = DateTime.Now;
}
}
if (getType.GetProperty("UpdateUserId") != null)
{
argModel.UpdateUserId = _user.UserId;
}
if (getType.GetProperty("UpdateUserName") != null)
{
argModel.UpdateUserName = _user.UserName;
}
if (getType.GetProperty("UpdateTime") != null)
{
argModel.UpdateTime = DateTime.Now;
}
}
invocation.Proceed();
}
else
{
invocation.Proceed();
}
}
}
测试 。
最后此篇关于Asp.NetCore系列:基于CastleDynamicProxy+Autofac实践AOP以及实现事务、用户填充功能的文章就讲到这里了,如果你想了解更多关于Asp.NetCore系列:基于CastleDynamicProxy+Autofac实践AOP以及实现事务、用户填充功能的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我在同一类中的方法之间进行方法调用并应用事务建议时遇到问题。 Spring Framework .NET 文档声明它支持基于组合和继承的代理,并且您可以强制 Spring 创建要实例化的基于继承的代理
我理解这些原则,但我很难看到实际应用程序在少数几个之外。请赐教;) 最佳答案 问任何支持人员:日志记录不是 AOP 的一个好的应用程序。他们不在乎应用程序内部调用了什么方法。他们关心应用程序正在执行的
我知道以前有人问过这个问题,但这是一年半前的事了,尽管我认为现在可能是重新提问的时候了。我也认识到它可能被视为主观的,但我想有一些客观的原因支持/反对 AOP。 我会对 感兴趣谁在使用 AOP 在软件
我想这个问题以前有人问过,但我无法立即找到相关的 SO 问题或其他地方的相关文章。 令我震惊的是,AOP 中的某些术语相当奇怪。看来我不是唯一一个-这个article ,例如,指出“不幸的是,AOP
面向切面编程可能的和严重的缺点是什么? 例如:新手的神秘调试(可读性影响) 最佳答案 工具链支持不佳 - 调试器、分析器等可能不了解 AOP,因此可能会在代码上工作,就好像所有方面都已被过程代码替换
这两种AOP框架的优缺点是什么?我使用 Unity 作为我的 aop 框架,但我猜想编译时 aop 框架(例如 postsharp)可能比运行时 aop 框架具有更好的性能?看起来运行时 aop 框架
我现在正在学习 spring aop,我不知道将上下文参数传递给建议。 请注意,我指的是 context 参数,而不是 normal 参数。 传递普通参数很简单,例如: a join point: p
来自类路径资源 [ApplicationContextAOP.xml] 的 XML 文档中的第 13 行无效;嵌套异常是 org.xml.sax.SAXParseException: cvc-comp
我使用 spring boot 2 和 spring security。 使用 aop,我搜索以获取调用该方法的用户。 @Aspect @Component public class LogAspec
我最近一直在一个非常简单的应用程序上尝试 Spring 的 AOP 功能,并且我坚持在适当的时间运行该方法,这意味着该部分中定义的方法应该在 中定义的方法之后运行 在我的代码中,这两个方法都在主方法中
我试图在网上找到如何通过 Ninject 使用 AOP 的例子。有人可以确认 AOP 在 Ninject 2 中是否可用而不使用外部库(即 CaSTLe Windsor?)。 如果可以的话,您能否发布
Aop配置已经在我的项目中完成了。为此添加了以下配置。问题是当下面的代码没有注释时,不会调用 formService 中的方法。因此我得到空指针异常。知道问题出在哪里吗?我附上了下面的代码.. AOP
我是 AOP 的新手。我遇到了这样的问题。 package org.suman.Aspect; import org.aspectj.lang.annotation.Aspect; import or
在我们的企业应用程序中,我们希望将日志记录、度量等横切关注点作为方面。我们已经准备好了 aspectj 建议(来自我们现有的 java 应用程序),但我没有找到将 aspectj 与 Grails 集
我正在向外部系统编写 Web 服务。 我的服务包装类有许多方法可以调用Web服务的所有soap接口(interface)。该调用可能会引发异常,然后该异常会自动触发重新连接到 Web 服务。 为了处理
已结束。此问题不符合 Stack Overflow guidelines .它目前不接受答案。 我们不允许提出有关书籍、工具、软件库等方面的建议的问题。您可以编辑问题,以便用事实和引用来回答它。 关闭
我是 spring 框架的新手,正在尝试一些示例来理解 AOP,这是我到目前为止所做的,但它不起作用。 问题是我一添加 对于 spring.xml,我的构建失败说无法创建具有空指针异常的 bean。但
下面是我要创建的方面。我想将两个切入点表达式合并为一个。我已经看到这可以使用带注释的切入点来完成,但是 xml 中的相同语法失败了。谁能帮帮我? 提前致谢 最佳答案
我对 Spring 事务管理感到困惑。在我的应用程序中,我在服务类中使用 @Transactional 实现了事务管理。我配置的 spring.xml 如下:
我知道围绕 Controller 方法编写 AOP 建议的标准方法,并且如果在 Controller 方法中声明,您可以访问 HttpServletRequest arg。 但我的情况是我有一个翻译服
我是一名优秀的程序员,十分优秀!