Compartilhar via


Criar regras de análise de código personalizadas

Aplica-se a: SQL Server Banco de Dados SQL do Azure Instância Gerenciada de SQL do Azure Banco 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.

Neste passo a passo, você criará uma regra personalizada para o Code Analysis estático do Transact-SQL ao usar as seguintes etapas:

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

Com exceção das instruções do Visual Studio (SQL Server Data Tools), o guia se concentra em projetos SQL no estilo SDK.

Pré-requisitos

Você precisará dos seguintes componentes para concluir este passo a passo:

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

Este passo a passo é destinado a usuários que já estão familiarizados com os recursos de SQL Server do SQL Server Data Tools. Você deve ter familiaridade com os conceitos do Visual Studio, por exemplo, como criar uma biblioteca de classes, adicionar pacotes do NuGet e usar o editor de código para adicionar códigos a uma classe.

Observação

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 é destinado a usuários que já estão familiarizados com os recursos de SQL Server do SQL Server Data Tools. Você deve ter familiaridade com os conceitos do Visual Studio, por exemplo, como criar uma biblioteca de classes, adicionar pacotes do NuGet e usar o editor de código para adicionar códigos a uma classe.

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

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

Este passo a passo é destinado a usuários que já estão familiarizados com projetos SQL. Você deve ter familiaridade com os conceitos de desenvolvimento, por exemplo, como criar uma biblioteca de classes, adicionar pacotes e usar o editor de código para editar código.

Etapa 1: criar um projeto de biblioteca de classes

Em primeiro lugar, crie uma biblioteca de classes. Para criar um projeto de biblioteca de classes:

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

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

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

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

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

A seguir, você adicionará as classes de suporte que serão usadas pela regra.

Em primeiro lugar, crie uma biblioteca de classes. Para criar um projeto de biblioteca de classes:

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

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

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

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

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

A seguir, você adicionará as classes de suporte que serão usadas pela regra.

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

  2. Abra uma janela Terminal no Visual Studio Code selecionando o menu Exibir, depois Terminal.

  3. Em Terminal, digite 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. Altere para o diretório SampleRules:

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

    dotnet add package Microsoft.SqlServer.DacFx
    

A seguir, você adicionará as classes de suporte que serão usadas pela regra.

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

  2. Em Terminal, digite 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. Altere para o diretório SampleRules:

    cd SampleRules
    
  4. Adicionar 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 atributos 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. Essa classe fornece acesso às instruções WAITFOR DELAY no modelo. As classes de visitante utilizam as APIs ScriptDom fornecidas pelo SQL Server. Nessa API, o código Transact-SQL é representado como uma árvore de sintaxe abstrata (AST) e as classes de visitantes podem ser úteis quando você deseja procurar por objetos de sintaxe específicos, como instruções WAITFOR DELAY. Essas instruções podem ser difíceis de localizar ao usar o modelo de objeto, pois não estão associadas a uma propriedade ou a um relacionamento específico do objeto. Entretanto, é possível encontrá-las ao usar o padrão de visitante e a API ScriptDom.

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

  2. No menu Projeto, selecione Adicionar classe. A caixa de diálogo Adicionar Novo Item aparecerá. Na caixa de texto Nome, digite WaitForDelayVisitor.cs e, em seguida, 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 Projeto, selecione Adicionar classe. A caixa de diálogo Adicionar Novo Item aparecerá. Na caixa de texto Nome, digite WaitForDelayVisitor.cs e, em seguida, selecione o botão Adicionar. O arquivo WaitForDelayVisitor.cs é adicionado ao projeto no Gerenciador de Soluções.

  1. Abra a exibição do 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 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 da classe, altere o modificador de acesso para interno e derive a classe usando TSqlConcreteFragmentVisitor:

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

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

    public WaitForDelayVisitor() {
       WaitForDelayStatements = new List<WaitForStatement>();
    }
    
  5. Substitua o método ExplicitVisit ao adicionar 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 consulta 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 Salvar.

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, em seguida, Novo Item. A caixa de diálogo Adicionar Novo Item aparecerá.

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

  3. Em Nome, digite RuleResources.resx. O editor de recurso aparece sem recursos definidos.

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

    Nome Valor
    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, em seguida, Novo Item. A caixa de diálogo Adicionar Novo Item aparecerá.

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

  3. Em Nome, digite RuleResources.resx. O editor de recurso aparece sem recursos definidos.

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

    Nome Valor
    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 nomeado RuleResources.resx.

  2. Abra o arquivo RuleResources.resxe 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 nomeado RuleResources.resx.

  2. Abra o arquivo RuleResources.resxe 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 interno fornecido pela estrutura que oferece suporte à leitura de DisplayName e de Description que são usados pela regra com um arquivo de recursos. Essa é uma classe útil se você pretender ter suas regras usadas em vários idiomas.

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

  2. No menu Projeto, selecione Adicionar classe. A caixa de diálogo Adicionar Novo Item aparecerá. Na caixa de texto Nome, digite LocalizedExportCodeAnalysisRuleAttribute.cs e, em seguida, 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 Projeto, selecione Adicionar classe. A caixa de diálogo Adicionar Novo Item aparecerá. Na caixa de texto Nome, digite LocalizedExportCodeAnalysisRuleAttribute.cs e, em seguida, selecione o botão Adicionar. O arquivo é adicionado ao projeto no Gerenciador de Soluções.

  1. Navegue até o diretório SampleRules na exibição do Explorer no Visual Studio Code.
  2. Crie um arquivo chamado LocalizedExportCodeAnalysisRuleAttribute.cs.
  1. Navegue até o diretório SampleRules.
  2. Crie um 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 faz referência aos recursos no arquivo de recursos que são usados pelo Visual Studio para exibir informações sobre a regra na interface do usuário.

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

  2. No menu Projeto, selecione Adicionar e, em seguida, Classe. A caixa de diálogo Adicionar Novo Item aparecerá. 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 e, em seguida, Classe. A caixa de diálogo Adicionar Novo Item aparecerá. 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 na exibição do Explorer no Visual Studio Code.
  2. Crie um arquivo chamado SampleRuleConstants.cs.
  1. Navegue até o diretório SampleRules.
  2. Crie um arquivo chamado SampleRuleConstants.cs.
  1. Abra o arquivo SampleRuleConstants.cs e adicione as seguintes instruções using ao arquivo:

    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 Salvar.

Etapa 3: criar uma classe de regra personalizada

Após adicionar as classes auxiliares que a regra de análise de código personalizada usará, crie uma classe de regra personalizada e nomeie-a como 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 e, em seguida, Classe. A caixa de diálogo Adicionar Novo Item aparecerá. Na caixa de texto Nome, digite AvoidWaitForDelayRule.cs e, em seguida, 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 e, em seguida, Classe. A caixa de diálogo Adicionar Novo Item aparecerá. Na caixa de texto Nome, digite AvoidWaitForDelayRule.cs e, em seguida, selecione Adicionar. O arquivo AvoidWaitForDelayRule.cs é adicionado ao projeto no Gerenciador de Soluções.

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

    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 LocalizedExportCodeAnalysisRuleAttribute à sua classe.

    O atributo LocalizedExportCodeAnalysisRuleAttribute permite que o serviço de análise de código revele as regras de análise de código personalizadas. Somente as classes marcadas com ExportCodeAnalysisRuleAttribute (ou um atributo que seja herdeiro deste) podem ser usadas no Code Analysis.

    O atributo LocalizedExportCodeAnalysisRuleAttribute fornece alguns metadados necessários que são usados pelo serviço. Isso inclui uma ID exclusiva para essa regra, um nome de exibição que será mostrado na interface do usuário do Visual Studio e uma Description que pode ser usada 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 essa regra analisa elementos específicos. A regra será chamada uma vez para cada elemento correspondente no modelo. Caso deseje analisar um modelo inteiro, você pode usar Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleScope.Model em vez disso.

  5. Adicione um construtor que configure Microsoft.SqlServer.Dac.CodeAnalysis.SqlAnalysisRule.SupportedElementTypes. Isso é necessário para regras de escopo do elemento. Ele define os tipos de elementos para os quais essa 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âmetro de entrada. Esse método retorna uma lista de possíveis problemas.

    O método obtém Microsoft.SqlServer.Dac.Model.TSqlModel, Microsoft.SqlServer.Dac.Model.TSqlObject e TSqlFragment usando o parâmetro de contexto. Em seguida, a classe WaitForDelayVisitor é usada para obter uma lista de todas as instruções WAITFOR DELAY presentes no modelo.

    Para cada WaitForStatement nessa lista, há a criação de 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 de SampleRules.
  2. Selecione a guia Assinatura.
  3. Selecione Assinar Assembly.
  4. Em Escolher um Arquivo de Chave com Nome Forte, selecione <Novo>.
  5. Na caixa de diálogo Criar Chave com Nome Forte, em Nome de Arquivo de Chave, digite MyRefKey.
  6. (opcional) Você pode especificar uma senha para o arquivo de chave de nome forte.
  7. Selecione OK.
  8. No menu Arquivo, selecione Salvar Tudo.
  9. No menu Build, selecione Compilar Solução.
  1. No menu Projeto, selecione Propriedades de SampleRules.
  2. Selecione a guia Assinatura.
  3. Selecione Assinar Assembly.
  4. Em Escolher um Arquivo de Chave com Nome Forte, selecione <Novo>.
  5. Na caixa de diálogo Criar Chave com Nome Forte, em Nome de Arquivo de Chave, digite MyRefKey.
  6. (opcional) Você pode especificar uma senha para o arquivo de chave de nome forte.
  7. Selecione OK.
  8. No menu Arquivo, selecione Salvar Tudo.
  9. No menu Build, selecione Compilar Solução.
  1. Abra a janela Terminal no Visual Studio Code selecionando o menu Exibir, depois Terminal.

  2. No Terminal, insira o seguinte comando no terminal para criar o projeto:

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

  2. Execute o comando a seguir, 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, é necessário instalar o assembly de modo que ele seja carregado quando você desenvolver 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 associado .pdb para a pasta Extensões.

Etapa 5.1: instalar o assembly SampleRules

Em seguida, copie as informações do assembly para o diretório Extensões. Quando o Visual Studio é iniciado, ele identifica as extensões no diretório <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions e nos subdiretórios e as disponibiliza para uso.

Para o Visual Studio 2022, <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.

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.

Observação

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

Agora, a regra deve estar instalada e ser exibida quando você reiniciar o Visual Studio. A seguir, você iniciará uma nova sessão do Visual Studio e criará 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.
  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 Projeto, selecione Propriedades. A página de propriedades SampleRulesDB será exibida.
  3. Selecione Code Analysis. Você deverá ver uma nova categoria chamada RuleSamples.CategorySamples.
  4. Expanda RuleSamples.CategorySamples. Você deverá ver SR1004: Avoid WAITFOR DELAY statement in stored procedures, triggers, and functions.
  5. Habilite essa 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 no build. 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 build do projeto for usada, a regra será executada e todas as 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 associado .pdb para a pasta Extensões.

Etapa 5.1: instalar o assembly SampleRules

Em seguida, copie as informações do assembly para o diretório Extensões. Quando o Visual Studio é iniciado, ele identifica as extensões no diretório <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions e nos subdiretórios e as disponibiliza para uso.

Para o Visual Studio 2022, <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.

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.

Observação

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

Agora, a regra deve estar instalada e ser exibida quando você reiniciar o Visual Studio. A seguir, você iniciará uma nova sessão do Visual Studio e criará 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 (versão prévia).
  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ó de projeto para abrir o arquivo de projeto. O arquivo de projeto SampleRulesDB é exibido em um editor de texto.
  3. Habilite a análise de código no build no arquivo de projeto SQL definindo a propriedade RunSqlCodeAnalysis como true.
  4. Quando a ação de build do projeto for usada, a regra será executada e todas as instruções WAITFOR DELAY encontradas serão relatadas como avisos.

Uma solução alternativa está disponível para projetos no estilo SDK para instalar regras personalizadas até que haja suporte para referências de pacote.

  1. Execute dotnet restore para restaurar as dependências do projeto no projeto SQL, garantindo que o cache de pacotes NuGet local contenha Microsoft.Build.Sql.
  2. Observe a versão do Microsoft.Build.Sql usada no arquivo de projeto SQL, como 0.1.19-preview.
  3. Copie o arquivo do assembly SampleRules.dll do diretório de saída para o diretório ~/.nuget/packages/microsoft.build.sql/0.1.19-preview/tools/netstandard2.1. O caminho exato do diretório pode variar dependendo da versão do Microsoft.Build.Sql usada no arquivo de projeto SQL.
  4. Habilite a análise de código no build no arquivo de projeto SQL definindo a propriedade RunSqlCodeAnalysis como true.
  5. Execute dotnet build para criar o projeto SQL e executar a regra personalizada.

Uma solução alternativa está disponível para projetos no estilo SDK para instalar regras personalizadas até que haja suporte para referências de pacote.

  1. Execute dotnet restore para restaurar as dependências do projeto no projeto SQL, garantindo que o cache de pacotes NuGet local contenha Microsoft.Build.Sql.
  2. Observe a versão do Microsoft.Build.Sql usada no arquivo de projeto SQL, como 0.1.19-preview.
  3. Copie o arquivo do assembly SampleRules.dll do diretório de saída para o diretório ~/.nuget/packages/microsoft.build.sql/0.1.19-preview/tools/netstandard2.1. O caminho exato do diretório pode variar dependendo da versão do Microsoft.Build.Sql usada no arquivo de projeto SQL.
  4. Habilite a análise de código no build no arquivo de projeto SQL definindo a propriedade RunSqlCodeAnalysis como true.
  5. Execute dotnet build para criar o projeto SQL e executar a regra personalizada.