Partilhar via


Criar regras de análise de código personalizado

Aplica-se a:SQL ServerAzure SQL DatabaseAzure SQL Managed InstanceBase de dados SQL no Microsoft Fabric

Este passo a passo demonstra as etapas usadas para criar uma regra de análise de código do SQL Server. A regra criada neste passo a passo é usada para evitar instruções WAITFOR DELAY em procedimentos armazenados, gatilhos e funções.

Nesta explicação passo a passo, você cria uma regra personalizada para Transact-SQL análise de código estático usando as seguintes etapas:

  1. Crie um projeto de biblioteca de classes, habilite a assinatura para esse projeto e adicione as referências necessárias.
  2. Crie duas classes C# auxiliares.
  3. Crie uma classe de regra personalizada em C#.
  4. Construa o projeto de biblioteca de classes.
  5. Instale e teste a nova regra de análise de código.

Exceto para as instruções do Visual Studio (SQL Server Data Tools), o guia se concentra em projetos SQL no estilo SDK.

Prerequisites

Você precisa dos seguintes componentes para concluir este passo a passo:

  • Uma versão do Visual Studio instalada, que inclui o SQL Server Data Tools e oferece suporte ao desenvolvimento em C# .NET Framework.
  • Um projeto do SQL Server que contém objetos do SQL Server.
  • Uma instância do SQL Server na qual você pode implantar um projeto de banco de dados.

Este passo a passo destina-se a usuários que já estão familiarizados com os recursos do SQL Server do SQL Server Data Tools. Você deve estar familiarizado com os conceitos do Visual Studio, como criar uma biblioteca de classes, adicionar pacotes NuGet e como usar o editor de código para adicionar código a uma classe.

Note

Devido às limitações de visualização do SQL Server Data Tools no estilo SDK, várias instalações do Visual Studio são necessárias para concluir este passo a passo. A primeira instalação é necessária para criar o projeto de biblioteca de classes, a segunda instalação é necessária para criar o projeto de banco de dados SQL no estilo SDK.

Este passo a passo destina-se a usuários que já estão familiarizados com os recursos do SQL Server do SQL Server Data Tools. Você deve estar familiarizado com os conceitos do Visual Studio, como criar uma biblioteca de classes, adicionar pacotes NuGet e como usar o editor de código para adicionar código a uma classe.

  • Uma versão do Visual Studio Code instalada, que inclui a extensão Projetos do Banco de Dados SQL.
  • Um projeto de banco de dados SQL que contém objetos SQL.
  • SDK do .NET 8
  • Recomendado: extensão C# Dev Kit para VS Code

Este passo a passo destina-se a usuários que já estão familiarizados com a extensão Projetos do Banco de Dados SQL no Visual Studio Code. Você deve estar familiarizado com conceitos de desenvolvimento, como criar uma biblioteca de classes, adicionar pacotes e como usar o editor de código para editar código.

  • Um editor de texto, como o editor de arquivos no Visual Studio Code.
  • Um projeto de banco de dados SQL que contém objetos SQL.
  • SDK do .NET 8

Este passo a passo destina-se a usuários que já estão familiarizados com projetos SQL. Você deve estar familiarizado com conceitos de desenvolvimento, como criar uma biblioteca de classes, adicionar pacotes e como usar o editor de código para editar código.

Etapa 1: Criar um projeto de biblioteca de classes

Primeiro, crie uma biblioteca de classes. Para criar um projeto de biblioteca de classes:

  1. Crie um projeto de biblioteca de classes C# (.NET Framework) chamado SampleRules.

  2. Renomeie o arquivo Class1.cs para AvoidWaitForDelayRule.cs.

  3. No Explorador de Soluções, clique com o botão direito do rato no nó do projeto e, em seguida, selecione Adicionar depois Referência.

  4. Selecione System.ComponentModel.Composition na guia Assemblies\Frameworks.

  5. No Gerenciador de Soluções, clique com o botão direito do mouse no nó do projeto e selecione Gerenciar Pacotes NuGet. Localize e instale o pacote NuGet Microsoft.SqlServer.DacFx. A versão selecionada deve ser 162.x.x (por exemplo, 162.2.111) com o Visual Studio 2022.

Em seguida, adicione classes de suporte que serão usadas pela regra.

Primeiro, crie uma biblioteca de classes. Para criar um projeto de biblioteca de classes:

  1. Crie um projeto de biblioteca de classes C# (.NET Framework) chamado SampleRules.

  2. Renomeie o arquivo Class1.cs para AvoidWaitForDelayRule.cs.

  3. No Explorador de Soluções, clique com o botão direito do rato no nó do projeto e, em seguida, selecione Adicionar depois Referência.

  4. Selecione System.ComponentModel.Composition na guia Assemblies\Frameworks.

  5. No Gerenciador de Soluções, clique com o botão direito do mouse no nó do projeto e selecione Gerenciar Pacotes NuGet. Localize e instale o pacote NuGet Microsoft.SqlServer.DacFx. A versão selecionada deve ser 162.x.x (por exemplo, 162.2.111) com o Visual Studio 2022.

Em seguida, adicione classes de suporte que serão usadas pela regra.

  1. Inicie o Visual Studio Code e abra a pasta onde você deseja criar o projeto.

  2. Abra uma janela Terminal no Visual Studio Code selecionando o menu Exibir e, em seguida, Terminal.

  3. No Terminal, insira os seguintes comandos para criar uma nova solução e projeto:

    dotnet new sln
    dotnet new classlib -n SampleRules -o SampleRules
    dotnet sln add SampleRules/SampleRules.csproj
    
  4. Mude para o diretório SampleRules:

    cd SampleRules
    
  5. Adicione o pacote NuGet necessário:

    dotnet add package Microsoft.SqlServer.DacFx
    

Em seguida, adicione classes de suporte que serão usadas pela regra.

  1. Abra um prompt de comando ou janela de terminal e navegue até a pasta onde você deseja criar o projeto.

  2. No Terminal, insira os seguintes comandos para criar uma nova solução e projeto:

    dotnet new sln
    dotnet new classlib -n SampleRules -o SampleRules
    dotnet sln add SampleRules/SampleRules.csproj
    
  3. Mude para o diretório SampleRules:

    cd SampleRules
    
  4. Adicione o pacote NuGet necessário:

    dotnet add package Microsoft.SqlServer.DacFx
    

Etapa 2: Criar classes auxiliares de regras personalizadas

Antes de criar a classe para a regra em si, adicione uma classe de visitante e uma classe de atributo ao projeto. Essas classes podem ser úteis para criar mais regras personalizadas.

Etapa 2.1: Definir a classe WaitForDelayVisitor

A primeira classe que você deve definir é a classe WaitForDelayVisitor, derivada de TSqlConcreteFragmentVisitor. Esta classe fornece acesso às instruções WAITFOR DELAY no modelo. As classes de visitantes utilizam as APIs ScriptDom fornecidas pelo SQL Server. Nesta API, o código Transact-SQL é representado como uma árvore de sintaxe abstrata (AST) e as classes visitantes podem ser úteis quando se pretende encontrar objetos de sintaxe específicos, como instruções WAITFOR DELAY. Essas instruções podem ser difíceis de encontrar usando o modelo de objeto, pois não estão associadas a uma propriedade ou relação de objeto específica, mas você pode encontrá-las usando o padrão de visitante e a API ScriptDom .

  1. No Gerenciador de Soluções , selecione o projeto SampleRules.

  2. No menu Project, selecione Adicionar Classe. A caixa de diálogo Adicionar Novo Item é exibida. Na caixa de texto Nome , digite WaitForDelayVisitor.cs e selecione o botão Adicionar. O arquivo WaitForDelayVisitor.cs é adicionado ao projeto no Gerenciador de Soluções .

  1. No Gerenciador de Soluções , selecione o projeto SampleRules.

  2. No menu Project, selecione Adicionar Classe. A caixa de diálogo Adicionar Novo Item é exibida. Na caixa de texto Nome , digite WaitForDelayVisitor.cs e selecione o botão Adicionar. O arquivo WaitForDelayVisitor.cs é adicionado ao projeto no Gerenciador de Soluções .

  1. Abra a vista Explorer no Visual Studio Code.

  2. Crie um novo arquivo chamado WaitForDelayVisitor.cs na pasta SampleRules.

  1. Navegue até o diretório SampleRules.
  2. Crie um novo arquivo chamado WaitForDelayVisitor.cs.
  1. Abra o arquivo WaitForDelayVisitor.cs e atualize o conteúdo para corresponder ao seguinte código:

    using System.Collections.Generic;
    using Microsoft.SqlServer.TransactSql.ScriptDom;
    namespace SampleRules {
        class WaitForDelayVisitor {}
    }
    
  2. Na declaração de classe, altere o modificador de acesso para interno e derive a classe de TSqlConcreteFragmentVisitor:

    internal class WaitForDelayVisitor : TSqlConcreteFragmentVisitor {}
    
  3. Adicione o seguinte código para definir a variável de membro List:

    public IList<WaitForStatement> WaitForDelayStatements { get; private set; }
    
  4. Defina o construtor de classe adicionando o seguinte código:

    public WaitForDelayVisitor() {
       WaitForDelayStatements = new List<WaitForStatement>();
    }
    
  5. Substitua o método ExplicitVisit adicionando o seguinte código:

    public override void ExplicitVisit(WaitForStatement node) {
       // We are only interested in WAITFOR DELAY occurrences
       if (node.WaitForOption == WaitForOption.Delay)
          WaitForDelayStatements.Add(node);
    }
    

    Esse método visita as instruções WAITFOR no modelo e adiciona instruções que têm a opção DELAY especificada à lista de instruções WAITFOR DELAY. A classe chave referenciada é WaitForStatement.

  6. No menu Arquivo, selecione Guardar.

Etapa 2.2: Adicionar um arquivo de recurso e três cadeias de caracteres de recurso

Em seguida, adicione um arquivo de recurso que defina o nome da regra, a descrição da regra e a categoria na qual a regra aparecerá na interface de configuração da regra.

  1. No Gerenciador de Soluções , selecione o projeto SampleRules. No menu Projeto, selecione Adicionar e depois Novo Item. A caixa de diálogo Adicionar Novo Item é exibida.

  2. Na lista de Modelos Instalados, selecione Geral. No painel de detalhes, selecione Arquivo de Recursos.

  3. Em Nome, digite RuleResources.resx. O editor de recursos é exibido, sem recursos definidos.

  4. Defina quatro cadeias de caracteres de recursos da seguinte maneira:

    Name Value
    AvoidWaitForDelay_ProblemDescription WAITFOR DELAY statement was found in {0}.
    AvoidWaitForDelay_RuleName Avoid using WaitFor Delay statements in stored procedures, functions and triggers.
    CategorySamples SamplesCategory
    CannotCreateResourceManager Can't create ResourceManager for {0} from {1}.
  5. No menu Arquivo, selecione Salvar RuleResources.resx.

  1. No Gerenciador de Soluções , selecione o projeto SampleRules. No menu Projeto, selecione Adicionar e depois Novo Item. A caixa de diálogo Adicionar Novo Item é exibida.

  2. Na lista de Modelos Instalados, selecione Geral. No painel de detalhes, selecione Arquivo de Recursos.

  3. Em Nome, digite RuleResources.resx. O editor de recursos é exibido, sem recursos definidos.

  4. Defina quatro cadeias de caracteres de recursos da seguinte maneira:

    Name Value
    AvoidWaitForDelay_ProblemDescription WAITFOR DELAY statement was found in {0}.
    AvoidWaitForDelay_RuleName Avoid using WaitFor Delay statements in stored procedures, functions and triggers.
    CategorySamples SamplesCategory
    CannotCreateResourceManager Can't create ResourceManager for {0} from {1}.
  5. No menu Arquivo, selecione Salvar RuleResources.resx.

  1. No diretório SampleRules, crie um novo arquivo chamado RuleResources.resx.

  2. Abra o arquivo RuleResources.resx e adicione o seguinte código:

    <?xml version="1.0" encoding="utf-8"?>
    <root>
      <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
        <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
        <xsd:element name="root" msdata:IsDataSet="true">
          <xsd:complexType>
            <xsd:choice maxOccurs="unbounded">
              <xsd:element name="metadata">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="value" type="xsd:string" minOccurs="0" />
                  </xsd:sequence>
                  <xsd:attribute name="name" use="required" type="xsd:string" />
                  <xsd:attribute name="type" type="xsd:string" />
                  <xsd:attribute name="mimetype" type="xsd:string" />
                  <xsd:attribute ref="xml:space" />
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="assembly">
                <xsd:complexType>
                  <xsd:attribute name="alias" type="xsd:string" />
                  <xsd:attribute name="name" type="xsd:string" />
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="data">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                    <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
                  </xsd:sequence>
                  <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
                  <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
                  <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
                  <xsd:attribute ref="xml:space" />
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="resheader">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                  </xsd:sequence>
                  <xsd:attribute name="name" type="xsd:string" use="required" />
                </xsd:complexType>
              </xsd:element>
            </xsd:choice>
          </xsd:complexType>
        </xsd:element>
      </xsd:schema>
      <resheader name="resmimetype">
        <value>text/microsoft-resx</value>
      </resheader>
      <resheader name="version">
        <value>2.0</value>
      </resheader>
      <resheader name="reader">
        <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
      </resheader>
      <resheader name="writer">
        <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
      </resheader>
      <data name="AvoidWaitForDelay_ProblemDescription" xml:space="preserve">
        <value>WAITFOR DELAY statement was found in {0}</value>
      </data>
      <data name="AvoidWaitFormDelay_RuleName" xml:space="preserve">
        <value>Avoid using WaitFor Delay statements in stored procedures, functions and triggers.</value>
      </data>
      <data name="CategorySamples" xml:space="preserve">
        <value>SamplesCategory</value>
      </data>
      <data name="CannotCreateResourceManager" xml:space="preserve">
        <value>Can't create ResourceManager for {0} from {1}</value>
      </data>
    </root>
    
  3. Salve o arquivo RuleResources.resx.

  4. Abra o arquivo SampleRules.csproj e adicione o seguinte código para atualizar e incluir o conteúdo do recurso no projeto:

    <ItemGroup>
      <Compile Update="RuleResources.Designer.cs">
        <DesignTime>True</DesignTime>
        <AutoGen>True</AutoGen>
        <DependentUpon>RuleResources.resx</DependentUpon>
      </Compile>
    </ItemGroup>
    <ItemGroup>
      <EmbeddedResource Include="RuleResources.resx">
        <Generator>PublicResXFileCodeGenerator</Generator>
        <LastGenOutput>RuleResources.Designer.cs</LastGenOutput>
      </EmbeddedResource>
    </ItemGroup>
    
  5. Salve o arquivo SampleRules.csproj.

  1. No diretório SampleRules, crie um novo arquivo chamado RuleResources.resx.

  2. Abra o arquivo RuleResources.resx e adicione o seguinte código:

    <?xml version="1.0" encoding="utf-8"?>
    <root>
      <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
        <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
        <xsd:element name="root" msdata:IsDataSet="true">
          <xsd:complexType>
            <xsd:choice maxOccurs="unbounded">
              <xsd:element name="metadata">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="value" type="xsd:string" minOccurs="0" />
                  </xsd:sequence>
                  <xsd:attribute name="name" use="required" type="xsd:string" />
                  <xsd:attribute name="type" type="xsd:string" />
                  <xsd:attribute name="mimetype" type="xsd:string" />
                  <xsd:attribute ref="xml:space" />
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="assembly">
                <xsd:complexType>
                  <xsd:attribute name="alias" type="xsd:string" />
                  <xsd:attribute name="name" type="xsd:string" />
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="data">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                    <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
                  </xsd:sequence>
                  <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
                  <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
                  <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
                  <xsd:attribute ref="xml:space" />
                </xsd:complexType>
              </xsd:element>
              <xsd:element name="resheader">
                <xsd:complexType>
                  <xsd:sequence>
                    <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
                  </xsd:sequence>
                  <xsd:attribute name="name" type="xsd:string" use="required" />
                </xsd:complexType>
              </xsd:element>
            </xsd:choice>
          </xsd:complexType>
        </xsd:element>
      </xsd:schema>
      <resheader name="resmimetype">
        <value>text/microsoft-resx</value>
      </resheader>
      <resheader name="version">
        <value>2.0</value>
      </resheader>
      <resheader name="reader">
        <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
      </resheader>
      <resheader name="writer">
        <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
      </resheader>
      <data name="AvoidWaitForDelay_ProblemDescription" xml:space="preserve">
        <value>WAITFOR DELAY statement was found in {0}</value>
      </data>
      <data name="AvoidWaitFormDelay_RuleName" xml:space="preserve">
        <value>Avoid using WaitFor Delay statements in stored procedures, functions and triggers.</value>
      </data>
      <data name="CategorySamples" xml:space="preserve">
        <value>SamplesCategory</value>
      </data>
      <data name="CannotCreateResourceManager" xml:space="preserve">
        <value>Can't create ResourceManager for {0} from {1}</value>
      </data>
    </root>
    
  3. Salve o arquivo RuleResources.resx.

  4. Abra o arquivo SampleRules.csproj e adicione o seguinte código para atualizar e incluir o conteúdo do recurso no projeto:

    <ItemGroup>
      <Compile Update="RuleResources.Designer.cs">
        <DesignTime>True</DesignTime>
        <AutoGen>True</AutoGen>
        <DependentUpon>RuleResources.resx</DependentUpon>
      </Compile>
    </ItemGroup>
    <ItemGroup>
      <EmbeddedResource Include="RuleResources.resx">
        <Generator>PublicResXFileCodeGenerator</Generator>
        <LastGenOutput>RuleResources.Designer.cs</LastGenOutput>
      </EmbeddedResource>
    </ItemGroup>
    
  5. Salve o arquivo SampleRules.csproj.

Etapa 2.3: Definir a classe LocalizedExportCodeAnalysisRuleAttribute

A segunda classe é LocalizedExportCodeAnalysisRuleAttribute.cs. Esta é uma extensão do Microsoft.SqlServer.Dac.CodeAnalysis.ExportCodeAnalysisRuleAttribute integrado no framework e suporta a leitura dos DisplayName e Description usados pela sua regra a partir de um ficheiro de recursos. Esta é uma classe útil se você pretende ter suas regras usadas em vários idiomas.

  1. No Gerenciador de Soluções , selecione o projeto SampleRules.

  2. No menu Project, selecione Adicionar Classe. A caixa de diálogo Adicionar Novo Item é exibida. Na caixa de texto Nome , digite LocalizedExportCodeAnalysisRuleAttribute.cs e selecione o botão Adicionar. O arquivo é adicionado ao projeto no Gerenciador de Soluções .

  1. No Gerenciador de Soluções , selecione o projeto SampleRules.

  2. No menu Project, selecione Adicionar Classe. A caixa de diálogo Adicionar Novo Item é exibida. Na caixa de texto Nome , digite LocalizedExportCodeAnalysisRuleAttribute.cs e selecione o botão Adicionar. O arquivo é adicionado ao projeto no Gerenciador de Soluções .

  1. Navegue até o diretório SampleRules no modo de exibição Explorer no Visual Studio Code.
  2. Crie um novo arquivo chamado LocalizedExportCodeAnalysisRuleAttribute.cs.
  1. Navegue até o diretório SampleRules.
  2. Crie um novo arquivo chamado LocalizedExportCodeAnalysisRuleAttribute.cs.
  1. Abra o arquivo e atualize o conteúdo para corresponder ao seguinte código:

    using Microsoft.SqlServer.Dac.CodeAnalysis;
    using System;
    using System.Globalization;
    using System.Reflection;
    using System.Resources;
    
    namespace SampleRules
    {
    
        internal class LocalizedExportCodeAnalysisRuleAttribute : ExportCodeAnalysisRuleAttribute
        {
            private readonly string _resourceBaseName;
            private readonly string _displayNameResourceId;
            private readonly string _descriptionResourceId;
    
            private ResourceManager _resourceManager;
            private string _displayName;
            private string _descriptionValue;
    
            /// <summary>
            /// Creates the attribute, with the specified rule ID, the fully qualified
            /// name of the resource file that will be used for looking up display name
            /// and description, and the Ids of those resources inside the resource file.
            /// </summary>
            public LocalizedExportCodeAnalysisRuleAttribute(
                string id,
                string resourceBaseName,
                string displayNameResourceId,
                string descriptionResourceId)
                : base(id, null)
            {
                _resourceBaseName = resourceBaseName;
                _displayNameResourceId = displayNameResourceId;
                _descriptionResourceId = descriptionResourceId;
            }
    
            /// <summary>
            /// Rules in a different assembly would need to overwrite this
            /// </summary>
            /// <returns></returns>
            protected virtual Assembly GetAssembly()
            {
                return GetType().Assembly;
            }
    
            private void EnsureResourceManagerInitialized()
            {
                var resourceAssembly = GetAssembly();
    
                try
                {
                    _resourceManager = new ResourceManager(_resourceBaseName, resourceAssembly);
                }
                catch (Exception ex)
                {
                    var msg = String.Format(CultureInfo.CurrentCulture, RuleResources.CannotCreateResourceManager, _resourceBaseName, resourceAssembly);
                    throw new RuleException(msg, ex);
                }
            }
    
            private string GetResourceString(string resourceId)
            {
                EnsureResourceManagerInitialized();
                return _resourceManager.GetString(resourceId, CultureInfo.CurrentUICulture);
            }
    
            /// <summary>
            /// Overrides the standard DisplayName and looks up its value inside a resources file
            /// </summary>
            public override string DisplayName
            {
                get
                {
                    if (_displayName == null)
                    {
                        _displayName = GetResourceString(_displayNameResourceId);
                    }
                    return _displayName;
                }
            }
    
            /// <summary>
            /// Overrides the standard Description and looks up its value inside a resources file
            /// </summary>
            public override string Description
            {
                get
                {
                    if (_descriptionValue == null)
                    {
                        _descriptionValue = GetResourceString(_descriptionResourceId);
                    }
                    return _descriptionValue;
                }
            }
        }
    }
    

Etapa 2.4: Definir a classe SampleConstants

Em seguida, defina uma classe que faça referência aos recursos no arquivo de recurso que são usados pelo Visual Studio para exibir informações sobre sua regra na interface do usuário.

  1. No Gerenciador de Soluções , selecione o projeto SampleRules.

  2. No menu Projeto, selecione Adicionar depois Classe. A caixa de diálogo Adicionar Novo Item é exibida. Na caixa de texto Nome , digite SampleRuleConstants.cs e selecione o botão Adicionar. O arquivo SampleRuleConstants.cs é adicionado ao projeto no Gerenciador de Soluções .

  1. No Gerenciador de Soluções , selecione o projeto SampleRules.

  2. No menu Projeto, selecione Adicionar depois Classe. A caixa de diálogo Adicionar Novo Item é exibida. Na caixa de texto Nome , digite SampleRuleConstants.cs e selecione o botão Adicionar. O arquivo SampleRuleConstants.cs é adicionado ao projeto no Gerenciador de Soluções .

  1. Navegue até o diretório SampleRules no modo de exibição Explorer no Visual Studio Code.
  2. Crie um novo arquivo chamado SampleRuleConstants.cs.
  1. Navegue até o diretório SampleRules.
  2. Crie um novo arquivo chamado SampleRuleConstants.cs.
  1. Abra o ficheiro SampleRuleConstants.cs e adicione as seguintes instruções using ao ficheiro:

    namespace SampleRules
    {
        internal static class RuleConstants
        {
            /// <summary>
            /// The name of the resources file to use when looking up rule resources
            /// </summary>
            public const string ResourceBaseName = "SampleRules.RuleResources";
    
            /// <summary>
            /// Lookup name inside the resources file for the select asterisk rule name
            /// </summary>
            public const string AvoidWaitForDelay_RuleName = "AvoidWaitForDelay_RuleName";
            /// <summary>
            /// Lookup ID inside the resources file for the select asterisk description
            /// </summary>
            public const string AvoidWaitForDelay_ProblemDescription = "AvoidWaitForDelay_ProblemDescription";
    
            /// <summary>
            /// The design category (should not be localized)
            /// </summary>
            public const string CategoryDesign = "Design";
    
            /// <summary>
            /// The performance category (should not be localized)
            /// </summary>
            public const string CategoryPerformance = "Design";
        }
    }
    
  2. No menu Arquivo, selecione Guardar.

Etapa 3: Criar uma classe de regra personalizada

Depois de adicionar as classes auxiliares que a regra de análise de código personalizado usará, crie uma classe de regra personalizada e nomeie-a AvoidWaitForDelayRule. A regra personalizada AvoidWaitForDelayRule será usada para ajudar os desenvolvedores de banco de dados a evitar instruções WAITFOR DELAY em procedimentos armazenados, gatilhos e funções.

Etapa 3.1: Criar a classe AvoidWaitForDelayRule

  1. No Gerenciador de Soluções , selecione o projeto SampleRules.

  2. No menu Projeto, selecione Adicionar depois Classe. A caixa de diálogo Adicionar Novo Item é exibida. Na caixa de texto Nome , digite AvoidWaitForDelayRule.cs e selecione Adicionar . O arquivo AvoidWaitForDelayRule.cs é adicionado ao projeto no Gerenciador de Soluções .

  1. No Gerenciador de Soluções , selecione o projeto SampleRules.

  2. No menu Projeto, selecione Adicionar depois Classe. A caixa de diálogo Adicionar Novo Item é exibida. Na caixa de texto Nome , digite AvoidWaitForDelayRule.cs e selecione Adicionar . O arquivo AvoidWaitForDelayRule.cs é adicionado ao projeto no Gerenciador de Soluções .

  1. Navegue até o diretório SampleRules no modo de exibição Explorer no Visual Studio Code.
  2. Crie um novo arquivo chamado AvoidWaitForDelayRule.cs.
  1. Navegue até o diretório SampleRules.
  2. Crie um novo arquivo chamado AvoidWaitForDelayRule.cs.
  1. Abra o ficheiro AvoidWaitForDelayRule.cs e adicione as seguintes instruções using ao ficheiro:

    using Microsoft.SqlServer.Dac.CodeAnalysis;
    using Microsoft.SqlServer.Dac.Model;
    using Microsoft.SqlServer.TransactSql.ScriptDom;
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    namespace SampleRules {
        class AvoidWaitForDelayRule {}
    }
    
  2. Na declaração de classe AvoidWaitForDelayRule, altere o modificador de acesso para público:

    /// <summary>
    /// This is a rule that returns a warning message
    /// whenever there is a WAITFOR DELAY statement appears inside a subroutine body.
    /// This rule only applies to stored procedures, functions and triggers.
    /// </summary>
    public sealed class AvoidWaitForDelayRule
    
  3. Derive a classe AvoidWaitForDelayRule da classe base Microsoft.SqlServer.Dac.CodeAnalysis.SqlCodeAnalysisRule:

    public sealed class AvoidWaitForDelayRule : SqlCodeAnalysisRule
    
  4. Adicione o LocalizedExportCodeAnalysisRuleAttribute à sua turma.

    LocalizedExportCodeAnalysisRuleAttribute permite que o serviço de análise de código descubra regras de análise de código personalizadas. Somente classes marcadas com um ExportCodeAnalysisRuleAttribute (ou um atributo que herda disso) podem ser usadas na análise de código.

    LocalizedExportCodeAnalysisRuleAttribute fornece alguns metadados necessários usados pelo serviço. Isso inclui uma ID exclusiva para essa regra, um nome para exibição mostrado na interface do usuário do Visual Studio e um Description que pode ser usado pela regra ao identificar problemas.

    [LocalizedExportCodeAnalysisRule(AvoidWaitForDelayRule.RuleId,
        RuleConstants.ResourceBaseName,
        RuleConstants.AvoidWaitForDelay_RuleName,
        RuleConstants.AvoidWaitForDelay_ProblemDescription
        Category = RuleConstants.CategoryPerformance,
        RuleScope = SqlRuleScope.Element)]
    public sealed class AvoidWaitForDelayRule : SqlCodeAnalysisRule
    {
       /// <summary>
       /// The Rule ID should resemble a fully-qualified class name. In the Visual Studio UI
       /// rules are grouped by "Namespace + Category", and each rule is shown using "Short ID: DisplayName".
       /// For this rule, that means the grouping will be "Public.Dac.Samples.Performance", with the rule
       /// shown as "SR1004: Avoid using WaitFor Delay statements in stored procedures, functions and triggers."
       /// </summary>
       public const string RuleId = "RuleSamples.SR1004";
    }
    

    A propriedade RuleScope deve ser Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleScope.Element pois esta regra analisa elementos específicos. A regra é chamada uma vez para cada elemento correspondente no modelo. Se você deseja analisar um modelo inteiro, então Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleScope.Model pode ser usado em vez disso.

  5. Adicione um construtor que configure o Microsoft.SqlServer.Dac.CodeAnalysis.SqlAnalysisRule.SupportedElementTypes. Isso é necessário para regras com escopo de elemento. Define os tipos de elementos aos quais esta regra se aplica. Nesse caso, a regra é aplicada a procedimentos armazenados, gatilhos e funções. A classe Microsoft.SqlServer.Dac.Model.ModelSchema lista todos os tipos de elementos disponíveis que podem ser analisados.

    public AvoidWaitForDelayRule()
    {
       // This rule supports Procedures, Functions and Triggers. Only those objects will be passed to the Analyze method
       SupportedElementTypes = new[]
       {
          // Note: can use the ModelSchema definitions, or access the TypeClass for any of these types
          ModelSchema.ExtendedProcedure,
          ModelSchema.Procedure,
          ModelSchema.TableValuedFunction,
          ModelSchema.ScalarFunction,
    
          ModelSchema.DatabaseDdlTrigger,
          ModelSchema.DmlTrigger,
          ModelSchema.ServerDdlTrigger
       };
    }
    
  6. Adicione uma substituição para o método Microsoft.SqlServer.Dac.CodeAnalysis.SqlAnalysisRule.Analyze(Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleExecutionContext), que usa Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleExecutionContext como parâmetros de entrada. Esse método retorna uma lista de problemas potenciais.

    O método obtém o Microsoft.SqlServer.Dac.Model.TSqlModel, Microsoft.SqlServer.Dac.Model.TSqlObjecte TSqlFragment do parâmetro context. A classe WaitForDelayVisitor é então usada para obter uma lista de todas as instruções WAITFOR DELAY no modelo.

    Para cada WaitForStatement nessa lista, é criado um Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleProblem.

    /// <summary>
    /// For element-scoped rules the Analyze method is executed once for every matching
    /// object in the model.
    /// </summary>
    /// <param name="ruleExecutionContext">The context object contains the TSqlObject being
    /// analyzed, a TSqlFragment
    /// that's the AST representation of the object, the current rule's descriptor, and a
    /// reference to the model being
    /// analyzed.
    /// </param>
    /// <returns>A list of problems should be returned. These will be displayed in the Visual
    /// Studio error list</returns>
    public override IList<SqlRuleProblem> Analyze(
        SqlRuleExecutionContext ruleExecutionContext)
    {
         IList<SqlRuleProblem> problems = new List<SqlRuleProblem>();
    
         TSqlObject modelElement = ruleExecutionContext.ModelElement;
    
         // this rule does not apply to inline table-valued function
         // we simply do not return any problem in that case.
         if (IsInlineTableValuedFunction(modelElement))
         {
             return problems;
         }
    
         string elementName = GetElementName(ruleExecutionContext, modelElement);
    
         // The rule execution context has all the objects we'll need, including the
         // fragment representing the object,
         // and a descriptor that lets us access rule metadata
         TSqlFragment fragment = ruleExecutionContext.ScriptFragment;
         RuleDescriptor ruleDescriptor = ruleExecutionContext.RuleDescriptor;
    
         // To process the fragment and identify WAITFOR DELAY statements we will use a
         // visitor
         WaitForDelayVisitor visitor = new WaitForDelayVisitor();
         fragment.Accept(visitor);
         IList<WaitForStatement> waitforDelayStatements = visitor.WaitForDelayStatements;
    
         // Create problems for each WAITFOR DELAY statement found
         // When creating a rule problem, always include the TSqlObject being analyzed. This
         // is used to determine
         // the name of the source this problem was found in and a best guess as to the
         // line/column the problem was found at.
         //
         // In addition if you have a specific TSqlFragment that is related to the problem
         //also include this
         // since the most accurate source position information (start line and column) will
         // be read from the fragment
         foreach (WaitForStatement waitForStatement in waitforDelayStatements)
         {
            SqlRuleProblem problem = new SqlRuleProblem(
                String.Format(CultureInfo.CurrentCulture,
                    ruleDescriptor.DisplayDescription, elementName),
                modelElement,
                waitForStatement);
            problems.Add(problem);
        }
        return problems;
    }
    
    private static string GetElementName(
        SqlRuleExecutionContext ruleExecutionContext,
        TSqlObject modelElement)
    {
        // Get the element name using the built in DisplayServices. This provides a number of
        // useful formatting options to
        // make a name user-readable
        var displayServices = ruleExecutionContext.SchemaModel.DisplayServices;
        string elementName = displayServices.GetElementName(
            modelElement, ElementNameStyle.EscapedFullyQualifiedName);
        return elementName;
    }
    
    private static bool IsInlineTableValuedFunction(TSqlObject modelElement)
    {
        return TableValuedFunction.TypeClass.Equals(modelElement.ObjectType)
                       && FunctionType.InlineTableValuedFunction ==
            modelElement.GetMetadata<FunctionType>(TableValuedFunction.FunctionType);
    }
    
  7. No menu Arquivo, selecione Salvar.

Etapa 4: Criar a biblioteca de classes

  1. No menu Projeto, selecione Propriedades do SampleRules.
  2. Selecione a guia de assinatura.
  3. Selecione Assinar a montagem.
  4. No Escolha um arquivo de chave de nome forte, selecione <Novo>.
  5. Na caixa de diálogo Criar Chave de Nome Forte, em Nome do arquivo de chave, digite MyRefKey.
  6. (facultativo) Você pode especificar uma senha para seu arquivo de chave de nome forte.
  7. Selecione OK.
  8. No menu Arquivo, selecione Guardar tudo.
  9. No menu Compilação, selecione Compilar Solução.
  1. No menu Projeto, selecione Propriedades do SampleRules.
  2. Selecione a guia de assinatura.
  3. Selecione Assinar a montagem.
  4. No Escolha um arquivo de chave de nome forte, selecione <Novo>.
  5. Na caixa de diálogo Criar Chave de Nome Forte, em Nome do arquivo de chave, digite MyRefKey.
  6. (facultativo) Você pode especificar uma senha para seu arquivo de chave de nome forte.
  7. Selecione OK.
  8. No menu Arquivo, selecione Guardar tudo.
  9. No menu Compilação, selecione Compilar Solução.
  1. Abra a janela Terminal no Visual Studio Code selecionando o menu Exibir e, em seguida, Terminal.

  2. No Terminal, digite o seguinte comando para criar o projeto:

    dotnet build /p:Configuration=Release
    
  1. Navegue até o diretório SampleRules.

  2. Execute o seguinte comando para criar o projeto:

    dotnet build /p:Configuration=Release
    

Etapa 5: Instalar e testar a nova regra de análise de código

Em seguida, você deve instalar o assembly para que ele seja carregado quando você criar um projeto de banco de dados SQL.

Para instalar uma regra que será executada quando você criar um projeto SQL original com o Visual Studio, você deve copiar o assembly e o arquivo .pdb associado para a pasta Extensões.

Etapa 5.1: Instalar o assembly SampleRules

  1. Em seguida, copie as informações do assembly para o diretório Extensões. Quando o Visual Studio é iniciado, ele identifica todas as extensões em <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions diretório e subdiretórios e as disponibiliza para uso. Para o Visual Studio 2022, o <Visual Studio Install Dir> geralmente é C:\Program Files\Microsoft Visual Studio\2022\Enterprise. Substitua Enterprise por Professional ou Community dependendo da edição do Visual Studio instalada.
  2. Copie o arquivo de assembly SampleRules.dll do diretório de saída para o diretório <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions. Por padrão, o caminho do arquivo .dll compilado é YourSolutionPath\YourProjectPath\bin\Debug ou YourSolutionPath\YourProjectPath\bin\Release.

Note

Talvez seja necessário criar o diretório Extensions.

Sua regra agora deve ser instalada e aparece assim que você reiniciar o Visual Studio. Em seguida, inicie uma nova sessão do Visual Studio e crie um projeto de banco de dados.

Etapa 5.2: Iniciar uma nova sessão do Visual Studio e criar um projeto de banco de dados

  1. Inicie uma segunda sessão do Visual Studio.
  2. Selecione Arquivo>Novo>Projeto.
  3. Na caixa de diálogo Novo Projeto, localize e selecione o Projeto de Banco de Dados do SQL Server.
  4. Na caixa de texto Nome , digite SampleRulesDB e selecione OK.

Etapa 5.3: Habilitar a regra de análise de código AvoidWaitForRule

  1. No Gerenciador de Soluções , selecione o projeto SampleRulesDB.
  2. No menu Project, selecione Propriedades. A página de propriedades SampleRulesDB é exibida.
  3. Selecione Análise de Código. Você verá uma nova categoria chamada RuleSamples.CategorySamples.
  4. Expanda RuleSamples.CategorySamples. Você deve ver SR1004: Avoid WAITFOR DELAY statement in stored procedures, triggers, and functions.
  5. Habilite esta regra marcando a caixa de seleção ao lado do nome da regra e a caixa de seleção Habilitar análise de código na compilação. Para obter mais informações sobre como habilitar a análise de código, consulte a Visão geral da análise de código.
  6. Quando a ação de construção do projeto for usada, a regra será executada e quaisquer instruções WAITFOR DELAY encontradas serão relatadas como avisos.

Para instalar uma regra que será executada quando você criar um projeto SQL original com o Visual Studio, você deve copiar o assembly e o arquivo .pdb associado para a pasta Extensões.

Etapa 5.1: Instalar o assembly SampleRules

  1. Em seguida, copie as informações do assembly para o diretório Extensões. Quando o Visual Studio é iniciado, ele identifica todas as extensões em <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions diretório e subdiretórios e as disponibiliza para uso. Para o Visual Studio 2022, o <Visual Studio Install Dir> geralmente é C:\Program Files\Microsoft Visual Studio\2022\Enterprise. Substitua Enterprise por Professional ou Community dependendo da edição instalada do Visual Studio.
  2. Copie o arquivo de assembly SampleRules.dll do diretório de saída para o diretório <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions. Por padrão, o caminho do arquivo .dll compilado é YourSolutionPath\YourProjectPath\bin\Debug ou YourSolutionPath\YourProjectPath\bin\Release.

Note

Talvez seja necessário criar o diretório Extensions.

Sua regra agora deve ser instalada e aparece assim que você reiniciar o Visual Studio. Em seguida, inicie uma nova sessão do Visual Studio e crie um projeto de banco de dados.

Etapa 5.2: Iniciar uma nova sessão do Visual Studio e criar um projeto de banco de dados

  1. Inicie uma segunda sessão do Visual Studio.
  2. Selecione Arquivo>Novo>Projeto.
  3. Na caixa de diálogo Novo Projeto, localize e selecione Projeto de Banco de Dados do SQL Server, estilo SDK (visualização).
  4. Na caixa de texto Nome , digite SampleRulesDB e selecione OK.

Etapa 5.3: Habilitar a regra de análise de código AvoidWaitForRule

  1. No Gerenciador de Soluções , selecione o projeto SampleRulesDB.
  2. Clique duas vezes no nó do projeto para abrir o arquivo de projeto. O arquivo de projeto SampleRulesDB é exibido em um editor de texto.
  3. Habilite análise de código na compilação no arquivo de projeto SQL definindo a propriedade RunSqlCodeAnalysis como true.
  4. Quando a ação de construção do projeto for usada, a regra será executada e quaisquer instruções WAITFOR DELAY encontradas serão relatadas como avisos.

Etapa 5.1: Coloque o assembly SampleRules em uma fonte NuGet local

  1. Se você não tiver uma fonte local para pacotes NuGet, adicione uma pasta em sua máquina local para armazenar os pacotes NuGet para teste local. Você pode verificar seus códigos-fonte NuGet atuais executando o seguinte comando:
dotnet nuget list source
  1. Se uma fonte local não estiver listada, você poderá adicionar uma usando o seguinte comando, substituindo-<local folder path> pelo caminho para sua pasta local, como C:\NuGetPackages ou ~/NuGetPackages:
dotnet nuget add source <local folder path>
  1. Copie o arquivo de assembly SampleRules.dll do diretório de saída para o diretório de origem local do NuGet. Por padrão, o caminho do arquivo .dll compilado é YourSolutionPath\YourProjectPath\bin\Debug ou YourSolutionPath\YourProjectPath\bin\Release.

Etapa 5.2: Usar SampleRules em um projeto de banco de dados

  1. Crie um novo projeto Microsoft.Build.Sql ou abra um existente.
  2. Adicione uma referência de pacote ao do pacote NuGet SampleRules no ficheiro de projeto. O exemplo a seguir mostra como adicionar uma referência ao pacote SampleRules NuGet no arquivo .sqlproj:
<ItemGroup>
  <PackageReference Include="SampleRules" Version="1.0.0" />
</ItemGroup>

Etapa 5.3: Habilitar a análise de código na compilação

  1. Habilite análise de código na compilação no arquivo de projeto SQL definindo a propriedade RunSqlCodeAnalysis como true. O pacote NuGet SampleRules será restaurado quando o projeto for criado e incluído por padrão.
  2. Quando a ação de construção do projeto for usada, a regra será executada e quaisquer instruções WAITFOR DELAY encontradas serão relatadas como avisos.

Etapa 5.1: Coloque o assembly SampleRules em uma fonte NuGet local

  1. Se você não tiver uma fonte local para pacotes NuGet, adicione uma pasta em sua máquina local para armazenar os pacotes NuGet para teste local. Você pode verificar seus códigos-fonte NuGet atuais executando o seguinte comando:
dotnet nuget list source
  1. Se uma fonte local não estiver listada, você poderá adicionar uma usando o seguinte comando, substituindo-<local folder path> pelo caminho para sua pasta local, como C:\NuGetPackages ou ~/NuGetPackages:
dotnet nuget add source <local folder path>
  1. Copie o arquivo de assembly SampleRules.dll do diretório de saída para o diretório de origem local do NuGet. Por padrão, o caminho do arquivo .dll compilado é YourSolutionPath\YourProjectPath\bin\Debug ou YourSolutionPath\YourProjectPath\bin\Release.

Etapa 5.2: Usar SampleRules em um projeto de banco de dados

  1. Crie um novo projeto Microsoft.Build.Sql ou abra um existente.
  2. Adicione uma referência de pacote ao do pacote NuGet SampleRules no ficheiro de projeto. O exemplo a seguir mostra como adicionar uma referência ao pacote SampleRules NuGet no arquivo .sqlproj:
<ItemGroup>
  <PackageReference Include="SampleRules" Version="1.0.0" />
</ItemGroup>

Etapa 5.3: Habilitar a análise de código na compilação

  1. Habilite análise de código na compilação no arquivo de projeto SQL definindo a propriedade RunSqlCodeAnalysis como true. O pacote NuGet SampleRules será restaurado quando o projeto for criado e incluído por padrão.
  2. Quando a ação de construção do projeto for usada, a regra será executada e quaisquer instruções WAITFOR DELAY encontradas serão relatadas como avisos.