上一篇,我们打造了一个简单的分析器,但是我们实际使用分析器就是为了对项目做分析检测,增加一些非语法的自检的

比如Asp.Net Core 3.0的替换依赖注入检测

设计分析

我们创建一个默认的Asp.Net Core 3.0的项目

打开Startup.cs

大致结构如下

我们要针对Startup分析,第一方法ConfigureServices的返回类型必须是void

这是Asp.Net Core 3.0的改动之一,所以,当Startup.ConfigureServices返回类型不等于void的时候,我们就抛出错误提示

我们编写一个Startup的监视代码

    public class StartupAnalyzerContext : BaseAnalyzContext
{
private static DiagnosticDescriptor NotFindConfigureServices = new DiagnosticDescriptor("Class", "Startup", "未找到方法ConfigureServices", "Error", DiagnosticSeverity.Error, true);
public override DiagnosticDescriptor[] SupportedDiagnostics => new DiagnosticDescriptor[]
{
NotFindConfigureServices
}; public override void Execute(SyntaxNodeAnalysisContext context)
{
if (context.Node.Kind() == SyntaxKind.ClassDeclaration &&
context.Node is ClassDeclarationSyntax classDeclaration &&
classDeclaration.Identifier.Text.Equals("Startup")
)
{
var methods = classDeclaration.Members.OfType<MethodDeclarationSyntax>(); if (!methods.Any(_method => _method.Identifier.Text.Equals("ConfigureServices")))
context.ReportDiagnostic(Diagnostic.Create(NotFindConfigureServices, classDeclaration.GetLocation()));
else
{ }
}
}
}

  

如果没在Startup类里找到ConfigureServices方法则抛出错误

我们注释掉ConfigureServices方法

看看结果

已经可以正常分析方法了

下一步,我们分析ConfigureServices方法的返回值是否是void

                else
{
var voidSymbol = context.Compilation.GetTypeByMetadataName(typeof(void).FullName); var configureServices = methods.FirstOrDefault(_method => _method.Identifier.Text.Equals("ConfigureServices")); var returnType = configureServices.ReturnType;
var typeInfo = context.SemanticModel.GetTypeInfo(returnType); if (!typeInfo.Type.Equals(voidSymbol))
context.ReportDiagnostic(Diagnostic.Create(ConfigureServicesReturnType, configureServices.GetLocation()));
}

  

我们刚才的else部分逻辑,找到了ConfigureServices方法才进入这部分逻辑,我们修改一下ConfigureServices方法返回值,改为Asp.Net Core 3.0一下,常见的IServiceProvider

完善AspectCore的依赖注入替换分析

项目引用AspectCore.Extensions.DependencyInjection

判断Program.CreateHostBuilder是否存在

分析CreateHostBuilder的代码体,是否存在一个UseServiceProviderFactory方法,存在则判断是否是泛型AspectCore.Injector.IServiceContainer的类

    public class ProgramAnalyzerContext : BaseAnalyzContext
{
private static DiagnosticDescriptor NotFindCreateHostBuilder = new DiagnosticDescriptor("Class", "Program", "未找到方法CreateHostBuilder", "Error", DiagnosticSeverity.Error, true);
private static DiagnosticDescriptor CreateHostBuilderReturnType = new DiagnosticDescriptor("Class", "Program", "无法分析返回值类型非IHostBuilder的CreateHostBuilder方法", "Error", DiagnosticSeverity.Error, true);
private static DiagnosticDescriptor NotFindUseServiceProviderFactory = new DiagnosticDescriptor("Class", "Program", "未找到UseServiceProviderFactory方法", "Error", DiagnosticSeverity.Error, true);
private static DiagnosticDescriptor AspectCoreServiceProviderFactory = new DiagnosticDescriptor("Class", "Program", "请Nuget安装AspectCore.Extensions.DependencyInjection", "Error", DiagnosticSeverity.Error, true);
private static DiagnosticDescriptor UseServiceProviderFactoryType = new DiagnosticDescriptor("Class", "Program", "UseServiceProviderFactory(new AspectCoreServiceProviderFactory())", "Error", DiagnosticSeverity.Error, true); public override DiagnosticDescriptor[] SupportedDiagnostics => new DiagnosticDescriptor[]
{
NotFindCreateHostBuilder,
CreateHostBuilderReturnType,
NotFindUseServiceProviderFactory,
AspectCoreServiceProviderFactory,
UseServiceProviderFactoryType
}; public override void Execute(SyntaxNodeAnalysisContext context)
{
if (context.Node.Kind() == SyntaxKind.ClassDeclaration &&
context.Node is ClassDeclarationSyntax classDeclaration &&
classDeclaration.Identifier.Text.Equals("Program")
)
{
var methods = classDeclaration.Members.OfType<MethodDeclarationSyntax>(); if (!methods.Any(_method => _method.Identifier.Text.Equals("CreateHostBuilder")))
context.ReportDiagnostic(Diagnostic.Create(NotFindCreateHostBuilder, classDeclaration.GetLocation()));
else
{
var aspectCoreServiceProviderFactorySymbol = context.Compilation.GetTypeByMetadataName("AspectCore.Extensions.DependencyInjection.AspectCoreServiceProviderFactory");
var iServiceContainerSymbol = context.Compilation.GetTypeByMetadataName("AspectCore.Injector.IServiceContainer"); if (aspectCoreServiceProviderFactorySymbol == null)
{
context.ReportDiagnostic(Diagnostic.Create(AspectCoreServiceProviderFactory, classDeclaration.GetLocation())); return;
} var createHostBuilder = methods.FirstOrDefault(_method => _method.Identifier.Text.Equals("CreateHostBuilder")); var expressionBody = createHostBuilder.ExpressionBody as ArrowExpressionClauseSyntax; if (expressionBody != null)
{
var expressions = ConvertArrowExpression(expressionBody); if (!expressions.Any(expression=> ((MemberAccessExpressionSyntax)expression.Expression).Name.Identifier.Text.Equals("UseServiceProviderFactory")))
context.ReportDiagnostic(Diagnostic.Create(NotFindUseServiceProviderFactory, createHostBuilder.GetLocation()));
else
{
var useServiceProviderFactoryExpression = expressions.FirstOrDefault(expression => ((MemberAccessExpressionSyntax)expression.Expression).Name.Identifier.Text.Equals("UseServiceProviderFactory"));
var method = context.SemanticModel.GetSymbolInfo(useServiceProviderFactoryExpression.Expression).Symbol as IMethodSymbol; if (!method.TypeArguments.Any(_param => _param.Equals(iServiceContainerSymbol)))
context.ReportDiagnostic(Diagnostic.Create(UseServiceProviderFactoryType, createHostBuilder.GetLocation()));
}
}
}
}
} private List<InvocationExpressionSyntax> ConvertArrowExpression(ArrowExpressionClauseSyntax expresionBody)
{
var result = new List<InvocationExpressionSyntax>();
var firstExpresson = (InvocationExpressionSyntax) expresionBody.Expression;
var expression = firstExpresson; result.Add(expression); while (IsNext(expression))
{
expression = Next(expression);
result.Add(expression);
} return result;
} private InvocationExpressionSyntax Next(InvocationExpressionSyntax expression)
{
var method = (MemberAccessExpressionSyntax) expression.Expression; Console.WriteLine($"{method.Name}"); return (InvocationExpressionSyntax)method.Expression;
} private bool IsNext(InvocationExpressionSyntax expression)
{
var method = (MemberAccessExpressionSyntax)expression.Expression; return method.Expression.Kind() == SyntaxKind.InvocationExpression;
}
}

打造静态分析器(二)基于Asp.Net Core 3.0的AspectCore组件检测的更多相关文章

  1. 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(1)

    最近使用vscode比较多. 学习了一下如何在mac上使用vscode开发asp.netcore项目. 这里是我写的关于vscode的一篇文章: https://www.cnblogs.com/cgz ...

  2. [译]基于ASP.NET Core 3.0的ABP v0.21已发布

    基于ASP.NET Core 3.0的ABP v0.21已发布 在微软发布仅仅一个小时后, 基于ASP.NET Core 3.0的ABP v0.21也紧跟着发布了. v0.21没有新功能.它只是升级到 ...

  3. 基于ASP.NET Core 3.0快速搭建Razor Pages Web应用

    前言 虽然说学习新的开发框架是一项巨大的投资,但是作为一个开发人员,不断学习新的技术并快速上手是我们应该掌握的技能,甚至是一个.NET Framework开发人员,学习.NET Core 新框架可以更 ...

  4. 基于Asp.Net Core 5.0依赖Quartz.Net框架编写的任务调度web管理平台

    源码地址: https://github.com/246850/Calamus.TaskScheduler 演示地址:http://47.101.47.193:1063/ 1.Quartz.NET框架 ...

  5. 基于ASP.NET Core 6.0的整洁架构

    大家好,我是张飞洪,感谢您的阅读,我会不定期和你分享学习心得,希望我的文章能成为你成长路上的垫脚石,让我们一起精进. 本节将介绍基于ASP.NET Core的整洁架构的设计理念,同时基于理论落地的代码 ...

  6. 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(2)

    第一部分: http://www.cnblogs.com/cgzl/p/8478993.html 为Domain Model添加约束 前一部分, 我们已经把数据库创建出来了. 那么我们先看看这个数据库 ...

  7. 基于ASP.NET Core 5.0使用RabbitMQ消息队列实现事件总线(EventBus)

    文章阅读请前先参考看一下 https://www.cnblogs.com/hudean/p/13858285.html 安装RabbitMQ消息队列软件与了解C#中如何使用RabbitMQ 和 htt ...

  8. 用VSCode开发一个基于asp.net core 2.0/sql server linux(docker)/ng5/bs4的项目(3)

    第一部分: http://www.cnblogs.com/cgzl/p/8478993.html 第二部分: http://www.cnblogs.com/cgzl/p/8481825.html 由于 ...

  9. 如何基于asp.net core的Identity框架在mysql上作身份验证处理

    首先了解这个概念,我一开始也是理解和掌握基本的概念,再去做程序的开发.Identity框架是微软自己提供,基于.net core平台,可拓展.轻量 级.面向多个数据库的身份验证框架.IdentityS ...

随机推荐

  1. Kail系统更新指令

    0x00源更新 国内更新源 leafpad /etc/apt/sources.list 然后复制粘贴下面的源 #kali官方源 deb http://http.kali.org/kali kali-r ...

  2. 线下---复习day02

    目录 1 后续课程安排 2 作业讲解 3 python中的魔法方法 setattr,getattr,setitem,getitem演示 with 上下文管理器 eq 4 cookie,session, ...

  3. git clone下载速度很慢的解决方法

    一直用git clone从github上下载源码学习,但是有时候git clone速度好慢,只有几Kb的速度,按这个速度下载安卓源码的话估计要下一年. 然后我再网上找各种教程,试过通过vps下载git ...

  4. element-ui(vue版)使用switch时change回调函数中的形参传值问题

    需求说明 有多个switch组件 需要知道switch的状态 表格中当前行(scope.row)的数据 问题描述 官方文档中对switch中change的描述: 目前能得到switch的状态值,但是无 ...

  5. python 迭代器(一):迭代器基础(一) 语言内部使用 iter(...) 内置函数处理可迭代对象的方式

    简介 在 Python 中,所有集合都可以迭代.在 Python 语言内部,迭代器用于支持: 1.for 循环2.构建和扩展集合类型3.逐行遍历文本文件4.列表推导.字典推导和集合推导5.元组拆包6. ...

  6. CSS定位布局

    CSS定位布局 基础知识 在CSS布局中,定位布局也是一种非常常见的技术手段,我们以京东为例: 上面是非常好的例子,对于定位布局来说它可以将一个元素放在页面上的任意一个位置. 但是定位布局也不能滥用, ...

  7. 理解Spring(一):Spring 与 IoC

    目录 什么是 Spring Spring 的整体架构 什么是 IoC Bean 的概念 Spring 的基本使用 Spring 的两种 IoC 容器 Spring 容器的基本工作原理 Spring B ...

  8. 一口气说出 4 种分布式一致性 Session 实现方式,面试杠杠的~

    前言 公司有一个 Web 管理系统,使用 Tomcat 进行部署.由于是后台管理系统,所有的网页都需要登录授权之后才能进行相应的操作. 起初这个系统的用的人也不多,为了节省资源,这个系统仅仅只是单机部 ...

  9. 【Python学习笔记六】获取百度搜索结果以及百度返回“百度安全验证”问题解决

    1.获取百度搜索结果页面主要是修改百度搜索url中的参数实现,例如查询的关键字为wd: 举例:https://www.baidu.com/s?wd=python",这样就可以查询到‘pyth ...

  10. 【思维+大数(高精度)】number 计蒜客 - 45276

    题目: 求 1 到 10^n 的数字中有 3 的数字的数量. 输入格式 1 个整数 n. 输出格式 共一行,1 个整数,表示答案. 数据范围 对于 10% 的数据,n≤8 对于 30% 的数据,n≤1 ...