网站做推广的方式,网站线框图怎样做,郑州企业网站推广,网站建设优化是干嘛ASP.NET Core具有一个以ServiceCollection和ServiceProvider为核心的依赖注入框架#xff0c;虽然这只是一个很轻量级的框架#xff0c;但是在大部分情况下能够满足我们的需要。不过我觉得它最缺乏的是针对AOP的支持#xff0c;虽然这个依赖注入框架提供了扩展点使我们可以很… ASP.NET Core具有一个以ServiceCollection和ServiceProvider为核心的依赖注入框架虽然这只是一个很轻量级的框架但是在大部分情况下能够满足我们的需要。不过我觉得它最缺乏的是针对AOP的支持虽然这个依赖注入框架提供了扩展点使我们可以很容易地实现与第三方框架的集成但是我又不想“节外生枝”为此我们趁这个周末写了一个简单的Interception框架来解决这个问题。通过这个命名为Dora.Interception的框架我们可以采用一种非常简单、直接而优雅地呵呵在这个原生的DI框架上实现针对AOP的编程。目前这只是一个BetaBeta1版本我将它放到了github上https://github.com/jiangjinnan/Dora。我写这篇文章不是为了说明这个Dora.Interception的设计和实现原理而是为了介绍如何利用它在一个ASP.NET Core与原生的DI框架结合实现AOP的编程模式。两个实例可以从这里下载。 一、基本原理 和大部分针AOP/Interception的实现一样我们同样采用“代理”的方式实现对方法调用的拦截和注入。如下图所示我们将需要以AOP方法注入的操作定义成一个个的Interceptor并以某种方式我采用的是最为直接的标注Attribute的形式应用到某个类型或者方法上。在运行的时候我们为目标对象创建一个代理我们针对代理对象的调用将会自动传递到目标对象。不过在目标对象最终被调用的时候注册的Interceptor会按照顺序被先后执行。 二、安装NuGet包 这个框架目前涉及到如下两个框架基础的模型实现在Dora.Interception这个包中Dora.Interception.Castle则利用Castle.DynamicProxy针对代理的创建提供了一个默认实现。 Dora.InterceptionDora.Interception.Castle 这两个NuGet包已经上传到nuget.org所以我们可以直接使用它们。假设我们创建了一个空的ASP.NET Core控制台应用我们可以通过执行如下的命名 三、定义Interceptor 假设我们创建这样一个Interceptor它能够捕获后续执行过程中抛出的异常并将异常消息写入日志我们将这个Interceptor命名为ErrorLogger。如下所示的就是这个ErrorLogger的完整定义。 1: public class ErrorLogger 2: { 3: private InterceptDelegate _next; 4: private ILogger _logger; 5: public ErrorLogger(InterceptDelegate next, ILoggerFactory loggerFactory, string category) 6: { 7: _next next; 8: _logger loggerFactory.CreateLogger(category); 9: } 10: 11: public async Task InvokeAsync(InvocationContext context) 12: { 13: try 14: { 15: await _next(context); 16: } 17: catch (Exception ex) 18: { 19: _logger.LogError(ex.Message); 20: throw; 21: } 22: } 23: } 考虑到依赖注入的使用我们并没有为具体的Interceptor类型定义一个接口用户仅仅需要按照如下的约定来定义这个Interceptor类型就可以了。对ASP.NET Core的管道设计比较熟悉的人应该可以看出这与中间件的设计是一致的。 Interceptor具有一个这样一个公共构造函数它的第一个参数是一个InterceptDelegate 类型的委托我们通过它调用后续的Interceptor或者目标对象。我们并不对后续的参数做任何约束它们可以采用DI的方式进行注入比如上面的loggerFactory参数。如果不能以DI的形式提供的参数比如参数category在后面注册的时候需要显式指定。拦截注入的功能虚线实现在一个名为InvokeAsync的方法中该方法的需要返回一个Task对象并且要求方法中包含一个类型为InvocationContext 的对象该对象表示执行代理方法的执行上下文。如下面的代码片段所示我们不仅仅可以得到与当前方法调用相关的上下文信息还可以直接利用它设置参数的值和最终返回的值。InvokeAsync方法需要自行决定是否继续调用后续的Interceptor和目标对象这可以直接通过在构造函数中指定的这个InterceptDelegate 来完成。 1: namespace Dora.Interception 2: { 3: public abstract class InvocationContext 4: { 5: protected InvocationContext(); 6: 7: public abstract object[] Arguments { get; } 8: public abstract Type[] GenericArguments { get; } 9: public abstract object InvocationTarget { get; } 10: public abstract MethodInfo Method { get; } 11: public abstract MethodInfo MethodInvocationTarget { get; } 12: public abstract object Proxy { get; } 13: public abstract object ReturnValue { get; set; } 14: public abstract Type TargetType { get; } 15: 16: public abstract object GetArgumentValue(int index); 17: public abstract void SetArgumentValue(int index, object value); 18: } 19: } 由于构造函数和InvokeAsync方法都支持依赖注入所以ErrorLogger也可以定义成如下的形式ILoggerFactory 在InvokeAsync方法中注入。 1: public class ErrorLogger 2: { 3: private InterceptDelegate _next; 4: private string _category; 5: public ErrorLogger(InterceptDelegate next, string category) 6: { 7: _next next; 8: _category category; 9: } 10: 11: public async Task InvokeAsync(InvocationContext context, ILoggerFactory loggerFactory) 12: { 13: try 14: { 15: await _next(context); 16: } 17: catch (Exception ex) 18: { 19: loggerFactory.CreateLogger(_category).LogError(ex.Message); 20: throw; 21: } 22: } 23: } 四、定义InterceptorAttribute 由于我们采用标注Attribute的方式我们为这样的Attribute定义了一个名为InterceptorAttribute的基类。针对ErrorLogger的ErrorLoggerAttribute定义如下它的核心在与需要实现抽象方法Use并利用作为参数的IInterceptorChainBuilder 注册对应的ErrorLogger。IInterceptorChainBuilder 中定义了一个泛型的方法使我们很容易地实现针对某个Interceptor类型的注册。该方法的第一个参数是整数它决定注册的Interceptor在整个Interceptor有序列表中的位置。InterceptorAttribute中定义了对应的Order属性。如果注册Interceptor类型的构造还是具有不能通过依赖注入的参数我们需要在调用Use方法的时候显式指定比如category。 1: [AttributeUsage( AttributeTargets.Class| AttributeTargets.Method, AllowMultiple false)] 2: public class ErrorLoggerAttribute : InterceptorAttribute 3: { 4: private string _category; 5: 6: public ErrorLoggerAttribute(string category) 7: { 8: _category category; 9: } 10: public override void Use(IInterceptorChainBuilder builder) 11: { 12: builder.UseErrorLogger(this.Order, _category); 13: } 14: } InterceptorAttribute可以应用在类和方法上我不赞成将它应用到接口上在默认情况下它的AllowMultiple 属性为False。如果我们希望Interceptor链中可以包含多个相同类型的Interceptor我们可以将AllowMultiple 属性设置为True。值得一提的是在AllowMultiple 属性为False的情况下如果类型和方法上都应用了同一个InterceptorAttribute那么只会选择应用在方法上的那一个。在如下的代码中我们将ErrorLoggerAttribute应用到总是会抛出异常的Invoke方法中并且将日志类型设置为“App”。 1: public interface IFoobarService 2: { 3: void Invoke(); 4: } 5: 6: public class FoobarService : IFoobarService 7: { 8: [ErrorLogger(App)] 9: public void Invoke() 10: { 11: throw new InvalidOperationException(Manually thrown exception!); 12: } 13: } 五、以DI的方式注入代理 我们依然会以DI的方式来使用上面定义的服务IFoobarService但是毫无疑问注入的对象必须是目标对象FoobarService的代理我们注册的Interceptor才能生效为了达到这个目的我们需要使用如下这个IInterceptableT接口它的Proxy属性为我们返回需要的代理对象。 1: namespace Dora.Interception 2: { 3: public interface IInterceptableT where T : class 4: { 5: T Proxy { get; } 6: } 7: } 比如我们选在在MVC应用中将IFoobarService注入到Controller中我们可以采用如下的定义方式。 1: public class HomeController 2: { 3: private IFoobarService _service; 4: public HomeController(IInterceptableIFoobarService interceptable) 5: { 6: _service interceptable.Proxy; 7: } 8: [HttpGet(/)] 9: public string Index() 10: { 11: _service.Invoke(); 12: return Hello World; 13: } 14: } 接下来我们来完成这个应用余下的部分。如下面的代码片段所示我们在作为启动类Startup的ConfigureServicves方法中调用IServiceCollection的扩展方法AddInterception注册于Interception相关的服务。为了确定ErrorLogger是否将异常信息写入日志我们在Main方法中添加了针对ConsoleLoggerProvider的注册并选择只写入类型为“App”的日志。 1: public class Program 2: { 3: public static void Main(string[] args) 4: { 5: new WebHostBuilder() 6: .ConfigureLogging(factoryfactory.AddConsole((category, level)category App)) 7: .UseKestrel() 8: .UseStartupStartup() 9: .Build() 10: .Run(); 11: } 12: } 13: 14: public class Startup 15: { 16: public void ConfigureServices(IServiceCollection services) 17: { 18: services 19: .AddInterception() 20: .AddScopedIFoobarService, FoobarService() 21: .AddMvc(); 22: } 23: 24: public void Configure(IApplicationBuilder app) 25: { 26: app.UseDeveloperExceptionPage() 27: .UseMvc(); 28: } 29: } 运行该应用后如果我们利用浏览器访问该应用由于我们注册了DeveloperExceptionPageMiddleware中间件所以会出入如下图所示的错误页面。而服务端的控制台会显示记录下的错误日志。 六、如果你不喜欢IInterceptableT接口 Interception自身的特质决定我们只有注入目标对象的代理才能让注册的Interceptor被执行这个问题我们是利用IInterceptableT接口来实现的可能有人觉得这种方法不是很爽的话我们还有更好的解决方案。我们先将HomeController写成正常的形式。 1: public class HomeController 2: { 3: private IFoobarService _service; 4: public HomeController(IFoobarService service) 5: { 6: _service service; 7: } 8: [HttpGet(/)] 9: public string Index() 10: { 11: _service.Invoke(); 12: return Hello World; 13: } 14: } 接下来我们需要在Startup的ConfigureServices方法调用ServiceCollection的ToInterceptable方法即可。 1: public class Startup 2: { 3: public void ConfigureServices(IServiceCollection services) 4: { 5: services 6: .AddInterception() 7: .AddScopedIFoobarService, FoobarService() 8: .AddMvc(); 9: services.ToInterceptable(); 10: } 11: 12: public void Configure(IApplicationBuilder app) 13: { 14: app.UseDeveloperExceptionPage() 15: .UseMvc(); 16: } 17: } 目前来说如果采用这种方法我们需要让注入的服务实现一个空的IInterceptable接口因为我会利用它来确定某个对象是否需要封装成代理将来我会将这个限制移除。 1: public class FoobarService : IFoobarService, IInterceptable 2: { 3: [ErrorLogger(App)] 4: public void Invoke() 5: { 6: throw new InvalidOperationException(Manually thrown exception!); 7: } 8: } 原文地址http://www.cnblogs.com/artech/p/dora-initerception.html.NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注