c# - Visual Studio 编译时 SQL 验证

标签 c# sql validation roslyn

如果我有一个像这样的 Dapper.NET 查询:

conn.Execute("insert into My_Table values ('blah', 'blah, 'blah', 'blah')");

我如何强制 visual studio 针对某个数据库模式对该查询进行编译时验证?我知道有些库可以进行查询验证(提供字符串和连接),但是这里的正确工具是什么?

扩展 Roslyn 以检查我标记为查询字符串的字符串(语法类似于熟悉的 @"Unescaped string")?自定义预处理?

还是我问错了问题?将所有查询逻辑包装在我的数据库项目中的存储过程中会更安全吗(这让我验证了查询本身)?既然我写下来了,我想我实际上会采用该解决方案,但我仍然对上述内容感到好奇。我希望能够写:

 conn.Execute(#"insert into My_Table values ('blah',
 'blah, 'blah', 'blah')"); //Hashtag to mark as query

并让编译器根据给定的数据库模式验证字符串。

最佳答案

一种选择是编写 Roslyn 分析器。分析器要做的是找到所有对 Execute() 等函数的调用,如果它们的参数是常量字符串,则使用您提到的库进行验证。

在实现分析器时,您会遇到的一个问题是如何指定要验证的数据库模式。除非您想以某种方式在分析器中对其进行硬编码,否则似乎这样做的方法是使用 "additional files" (其中currently requires hand-editing the csproj of any project where you want to use the analyzer)。

分析器可能如下所示(请注意,您可能需要修改代码以使其更健壮):

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
    => ImmutableArray.Create(BadSqlRule, MissingOptionsFileRule);

public override void Initialize(AnalysisContext context)
{
    context.RegisterCompilationStartAction(AnalyzeCompilationStart);
    context.RegisterCompilationAction(AnalyzeCompilation);
    context.RegisterSyntaxNodeAction(AnalyzeNode, SyntaxKind.InvocationExpression);
}

private Config config = null;

private void AnalyzeCompilationStart(CompilationStartAnalysisContext context)
{
    var configFile = context.Options.AdditionalFiles
        .SingleOrDefault(f => Path.GetFileName(f.Path) == "myconfig.json");

    config = configFile == null
        ? null
        : new Config(configFile.GetText(context.CancellationToken).ToString());
}

private void AnalyzeCompilation(CompilationAnalysisContext context)
{
    if (config == null)
        context.ReportDiagnostic(Diagnostic.Create(MissingOptionsFileRule, Location.None));
}

private void AnalyzeNode(SyntaxNodeAnalysisContext context)
{
    if (config == null)
        return;

    var node = (InvocationExpressionSyntax) context.Node;

    var symbol = (IMethodSymbol) context.SemanticModel.GetSymbolInfo(
        node, context.CancellationToken).Symbol;

    // TODO: properly check it's one of the methods we analyze
    if (symbol.ToDisplayString().Contains(".Execute(string"))
    {
        var arguments = node.ArgumentList.Arguments;
        if (arguments.Count == 0)
            return;

        var firstArgument = arguments.First().Expression;

        if (!firstArgument.IsKind(SyntaxKind.StringLiteralExpression))
            return;

        var sqlString = (string)((LiteralExpressionSyntax) firstArgument).Token.Value;

        if (Verify(config, sqlString))
            return;

        context.ReportDiagnostic(
            Diagnostic.Create(BadSqlRule, firstArgument.GetLocation(), sqlString));
    }
}

关于c# - Visual Studio 编译时 SQL 验证,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36938911/

相关文章:

c# - ASP.NET MVC 模块

java - MariaDB 功能索引

sql - 为什么图遍历比联接更快?有关SQL中标准化数据的任何类(class)?

javascript - 通过 AJAX 调用问题 knockout 自定义验证

forms - 如何在服务器端响应不同的验证错误?

c# - 结构图 ObjectFactory.GetAllInstances<IHandle<TEvent>>()

c# - 类到数据集/数据集到类

mysql - SQL "group by"仅返回第一行 - 之二

javascript - 用于检查文本的 jquery 验证不包含 html

c# - 如何获取 Windows Phone Mango 上所有可用键盘的列表(在 C# 代码中)?