自动化CodeReview系列目录

  1. 自动化CodeReview - ASP.NET Core依赖注入
  2. 自动化CodeReview - ASP.NET Core请求参数验证

我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评。

如果以后有时间的话,我打算写一个系列的【实现BUG自动检测】,本文将是第一篇。

如果你使用过ASP.NET Core那么对依赖注入一定不陌生。
使用流程为:
1. 先注册Service,有3个方法AddTransient、AddScoped、AddSingleton
2. 再使用Service,通常在构造方法里声明

先来说说产生BUG的场景
BUG场景一:
有的时候可能因为疏忽忘记注册Service直接就使用了,使用那个Service时会报异常。这种情况项目都是可以编译通过的,是一个不太容易发现的BUG,如果那个Service在测试时没有覆盖到这个BUG就会被带到生产环境

BUG场景二:
通常有一些Service我们只希望它在请求作用域内被使用,例如:在服务端持有数据库连接的Service通常都是请求作用域级别的,即:在请求内第一次使用数据库时创建数据库连接,请求内会复用连接,请求结束回收连接。
对应ASP.NET Core里的注册方式如下:
services.AddScoped<IDbContext, DbContext>();

在ASP.NET Core中AddScoped注册的Service在请求结束时会销毁。
如果你在控制器中直接引用IDbContext一切正常,现在业务需要我们要封装一个用户管理类UserManager,它是单例的,注册代码:
services.AddScoped<IUserManager, UserManager>();

在写UserManager类的时候要访问数据库,顺手就引用了IDbContext(正常是不应该这么引用的但是忘记了),因为UserManager是单例会造成IDbContext永远不会释放,进而长期占用一个数据库连接。并且在编译时,运行时都不会报错,很隐蔽的一个BUG

好了,场景说完了,本文的主角该登场了,解决方式如下:
在Startup类的ConfigureServices方法最后加入如下代码:

public void ConfigureServices(IServiceCollection services){
//此处省略若干代码... //确保服务依赖的正确性,放到所有注册服务代码后调用
if (_env.IsDevelopment())
services.AssertDependencyValid();
} 

对于“场景一”此方法会抛出异常:
throw new InvalidProgramException($"服务 {svceType.FullName} 的构造方法引用了未注册的服务 {paramType.FullName}");

对于“场景二”此方法会抛出异常:
throw new InvalidProgramException($"Singleton的服务 {svceType.FullName} 的构造方法引用了Scoped的服务 {paramType.FullName}");

您可以根据异常的提示找到具体有问题的类并修改之

完整代码如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection; namespace Microsoft.Extensions.DependencyInjection
{
public static class MondolServiceCollectionExtensions
{
/// <summary>
/// DUMP服务列表
/// </summary>
public static string Dump(this IServiceCollection services)
{
var sevList = new List<Tuple<string, string>>();
foreach (var sev in services)
{
sevList.Add(new Tuple<string, string>(sev.Lifetime.ToString(), sev.ServiceType.FullName));
}
sevList.Sort((x, y) =>
{
var cRs = string.CompareOrdinal(x.Item1, y.Item1);
return cRs != 0 ? cRs : string.CompareOrdinal(x.Item2, y.Item2);
}); return string.Join("\r\n", sevList.Select(p => $"{p.Item2} - {p.Item1}"));
} /// <summary>
/// 确保当前注册服务的依赖关系是正确的
/// </summary>
public static void AssertDependencyValid(this IServiceCollection services)
{
var ignoreTypes = new[]
{
"Microsoft.AspNetCore.Mvc.Internal.MvcRouteHandler",
"Microsoft.AspNetCore.Razor.Runtime.TagHelpers.TagHelperDescriptorResolver"
}; foreach (var svce in services)
{
if (svce.Lifetime == ServiceLifetime.Singleton)
{
//确保Singleton的服务不能依赖Scoped的服务
if (svce.ImplementationType != null)
{
var svceType = svce.ImplementationType;
if (ignoreTypes.Contains(svceType.FullName))
continue; var ctors = svceType.GetConstructors();
foreach (var ctor in ctors)
{
var paramLst = ctor.GetParameters();
foreach (var param in paramLst)
{
var paramType = param.ParameterType;
var paramTypeInfo = paramType.GetTypeInfo();
if (paramTypeInfo.IsGenericType)
{
if (paramType.ToString().StartsWith("System.Collections.Generic.IEnumerable`1"))
{
paramType = paramTypeInfo.GetGenericArguments().First();
paramTypeInfo = paramType.GetTypeInfo();
}
}
if (paramType == typeof(IServiceProvider))
continue; ServiceDescriptor pSvce;
if (paramTypeInfo.IsGenericType)
{
//泛型采用模糊识别,可能有遗漏
var prefix = Regex.Match(paramType.ToString(), @"^[^`]+`\d+\[").Value;
pSvce = services.FirstOrDefault(p => p.ServiceType.ToString().StartsWith(prefix));
}
else
{
pSvce = services.FirstOrDefault(p => p.ServiceType == paramType);
}
if (pSvce == null)
throw new InvalidProgramException($"服务 {svceType.FullName} 的构造方法引用了未注册的服务 {paramType.FullName}");
if (pSvce.Lifetime == ServiceLifetime.Scoped)
throw new InvalidProgramException($"Singleton的服务 {svceType.FullName} 的构造方法引用了Scoped的服务 {paramType.FullName}");
}
}
}
}
}
}
}
}

  

自动化CodeReview - ASP.NET Core依赖注入的更多相关文章

  1. 实现BUG自动检测 - ASP.NET Core依赖注入

    我个人比较懒,能自动做的事绝不手动做,最近在用ASP.NET Core写一个项目,过程中会积累一些方便的工具类或框架,分享出来欢迎大家点评. 如果以后有时间的话,我打算写一个系列的[实现BUG自动检测 ...

  2. 自动化CodeReview - ASP.NET Core请求参数验证

    自动化CodeReview系列目录 自动化CodeReview - ASP.NET Core依赖注入 自动化CodeReview - ASP.NET Core请求参数验证 参数验证实现 在做服务端开发 ...

  3. # ASP.NET Core依赖注入解读&使用Autofac替代实现

    标签: 依赖注入 Autofac ASPNETCore ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Aut ...

  4. [译]ASP.NET Core依赖注入深入讨论

    原文链接:ASP.NET Core Dependency Injection Deep Dive - Joonas W's blog 这篇文章我们来深入探讨ASP.NET Core.MVC Core中 ...

  5. asp.net core 依赖注入几种常见情况

    先读一篇注入入门 全面理解 ASP.NET Core 依赖注入, 学习一下基本使用 然后学习一招, 不使用接口规范, 直接写功能类, 一般情况下可以用来做单例. 参考https://www.cnblo ...

  6. ASP.NET Core依赖注入——依赖注入最佳实践

    在这篇文章中,我们将深入研究.NET Core和ASP.NET Core MVC中的依赖注入,将介绍几乎所有可能的选项,依赖注入是ASP.Net Core的核心,我将分享在ASP.Net Core应用 ...

  7. ASP.NET Core 依赖注入最佳实践——提示与技巧

    在这篇文章,我将分享一些在ASP.NET Core程序中使用依赖注入的个人经验和建议.这些原则背后的动机如下: 高效地设计服务和它们的依赖. 预防多线程问题. 预防内存泄漏. 预防潜在的BUG. 这篇 ...

  8. ASP.NET Core依赖注入最佳实践,提示&技巧

    分享翻译一篇Abp框架作者(Halil İbrahim Kalkan)关于ASP.NET Core依赖注入的博文. 在本文中,我将分享我在ASP.NET Core应用程序中使用依赖注入的经验和建议. ...

  9. ASP.NET Core依赖注入解读&使用Autofac替代实现【转载】

    ASP.NET Core依赖注入解读&使用Autofac替代实现 1. 前言 2. ASP.NET Core 中的DI方式 3. Autofac实现和自定义实现扩展方法 3.1 安装Autof ...

随机推荐

  1. 【Java】 剑指offer(1) 找出数组中重复的数字

    本文参考自<剑指offer>一书,代码采用Java语言. 更多:<剑指Offer>Java实现合集 题目 在一个长度为n的数组里的所有数字都在0到n-1的范围内.数组中某些数字 ...

  2. PhotoShop 常用快捷键

    PhotoShop: ctrl+j 复制一块图层ctrl+t 自由变换钢笔画出来的是路径不是选区,将路径转化成选区:ctrl+回车 alt+delete 直排文字蒙版ctrl+d 取消选择中括号可改变 ...

  3. POJ 2250 Compromise【LCS】+输出路径

    题目链接:https://vjudge.net/problem/POJ-2250 题目大意:给出n组case,每组case由两部分组成,分别包含若干个单词,都以“#”当结束标志,要求输出最长子序列. ...

  4. JavaNIO快速入门

    NIO是Jdk中非常重要的一个组成部分,基于它的Netty开源框架可以很方便的开发高性能.高可靠性的网络服务器和客户端程序.本文将就其核心基础类型Channel, Buffer, Selector进行 ...

  5. 谁记录了mysql error log中的超长信息(记pt-stalk一个bug的定位过程)

    [问题] 最近查看MySQL的error log文件时,发现有很多服务器的文件中有大量的如下日志,内容很长(大小在200K左右),从记录的内容看,并没有明显的异常信息. 有一台测试服务器也有类似的问题 ...

  6. AngularJS checkbox/复选框 根据缓存数据实时显示

    想缓存选择按钮时,可以使用这样的方法. index.html <!DOCTYPE html> <html data-ng-app="App"> <he ...

  7. CKEditor 4.4.1 添加代码高亮显示插件功能--使用官方推荐Code Snippet插件

    随着CKEditor4.4.1的发布,以前一直困扰的代码高亮问题终于完美的得到解决,在CKEditor4.4中官方发布了Code Snippet这个代码片段的插件,终于可以完美的内嵌使用代码高亮了,以 ...

  8. luogu P2934 [USACO09JAN]安全出行Safe Travel

    题目链接 luogu P2934 [USACO09JAN]安全出行Safe Travel 题解 对于不在最短路树上的边(x, y) 1 | | t / \ / \ x-----y 考虑这样一种形态的图 ...

  9. wamp memcache 的安装与扩展(Windows 64)

    一.windows操作系统下的memcache安装 1.此处提供32位的安装包链接,如果需要64位的应该可惜查得到.将下载的压缩包解压到自己确定的安装目录,我的参考如下: 2.为了安装顺利,所以需要以 ...

  10. 用type动态创建Form

    type时所有元类的父亲object是type(object的类型是type),type也是object(type继承自object) >>> isinstance(object, ...