Condividi tramite


Creare regole di analisi del codice personalizzate

Si applica a: SQL Server database SQL di Azure Istanza gestita di SQL di Azure database SQL in Microsoft Fabric

Questa procedura dettagliata illustra i passaggi necessari per creare una regola di analisi del codice di SQL Server. La regola creata in questa procedura dettagliata viene usata per evitare le istruzioni WAITFOR DELAY in stored procedure, trigger e funzioni.

In questa procedura dettagliata verrà creata una regola personalizzata per l'analisi del codice statico di Transact-SQL eseguendo i passaggi seguenti:

  1. Creare un progetto di libreria di classi, abilitare la firma per il progetto e aggiungere i riferimenti necessari.
  2. Creare due classi di helper di C#.
  3. Creare una classe di regola personalizzata C#.
  4. Compila il progetto di libreria di classi.
  5. Installare e testare la nuova regola di analisi del codice.

Ad eccezione delle istruzioni di Visual Studio (SQL Server Data Tools), la guida è incentrata sui progetti SQL in stile SDK.

Prerequisiti

Per completare questa procedura dettagliata, è necessario disporre dei componenti seguenti:

  • Una versione di Visual Studio installata, che include SQL Server Data Tools e supporta lo sviluppo in C# .NET Framework.
  • Un progetto di SQL Server contenente oggetti di SQL Server.
  • Un'istanza di SQL Server a cui sia possibile distribuire un progetto di database.

Questa procedura dettagliata è destinata a utenti che hanno già familiarità con le funzionalità di SQL Server Data Tools. È anche necessario che l'utente conosca i concetti di base di Visual Studio, ad esempio come creare una libreria di classi, aggiungere pacchetti NuGet e come usare l'editor di codice per aggiungere codice a una classe.

Nota

A causa delle limitazioni di anteprima di SQL Server Data Tools in stile SDK, per completare questa procedura dettagliata sono necessarie più installazioni di Visual Studio. La prima installazione è necessaria per creare il progetto di libreria di classi, la seconda installazione è necessaria per creare il progetto di database SQL in stile SDK.

Questa procedura dettagliata è destinata a utenti che hanno già familiarità con le funzionalità di SQL Server Data Tools. È anche necessario che l'utente conosca i concetti di base di Visual Studio, ad esempio come creare una libreria di classi, aggiungere pacchetti NuGet e come usare l'editor di codice per aggiungere codice a una classe.

  • Versione di Visual Studio Code installata, che include l'estensione database SQL Projects.
  • Un progetto di database SQL contenente oggetti di SQL.
  • .NET 8 SDK
  • Consigliato: estensione C# Dev Kit per VS Code

Questa procedura dettagliata è destinata agli utenti che hanno già familiarità con l'estensione progetti database SQL in Visual Studio Code. È anche necessario che l'utente conosca i concetti di sviluppo, ad esempio come creare una libreria di classi, aggiungere pacchetti e come usare l'editor di codice per editare il codice.

  • Un editor di testo, ad esempio l’editor di file in Visual Studio Code.
  • Un progetto di database SQL contenente oggetti di SQL.
  • .NET 8 SDK

Questa procedura dettagliata è destinata a utenti che abbiano già familiarità con SQL projects. È anche necessario che l'utente conosca i concetti di sviluppo, ad esempio come creare una libreria di classi, aggiungere pacchetti e come usare l'editor di codice per editare il codice.

Passaggio 1: creare un progetto libreria di classi

Per prima cosa creare una libreria di classi. Per creare un progetto libreria di classi:

  1. Create un progetto libreria di classi in C# (.NET Framework) denominato SampleRules.

  2. Rinominare il file Class1.cs in AvoidWaitForDelayRule.cs.

  3. In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Aggiungi, quindi Riferimento.

  4. Selezionare System.ComponentModel.Composition nella scheda Assembly\Frameworks.

  5. In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Gestisci pacchetti NuGet. Ricercare e installare il pacchetto NuGet Microsoft.SqlServer.DacFx. La versione selezionata deve essere 162.x.x (ad esempio 162.2.111) con Visual Studio 2022.

A questo punto aggiungere le classi di supporto che verranno usate dalla regola.

Per prima cosa creare una libreria di classi. Per creare un progetto libreria di classi:

  1. Create un progetto libreria di classi in C# (.NET Framework) denominato SampleRules.

  2. Rinominare il file Class1.cs in AvoidWaitForDelayRule.cs.

  3. In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Aggiungi, quindi Riferimento.

  4. Selezionare System.ComponentModel.Composition nella scheda Assembly\Frameworks.

  5. In Esplora soluzioni fare clic con il pulsante destro del mouse sul nodo del progetto e scegliere Gestisci pacchetti NuGet. Ricercare e installare il pacchetto NuGet Microsoft.SqlServer.DacFx. La versione selezionata deve essere 162.x.x (ad esempio 162.2.111) con Visual Studio 2022.

A questo punto aggiungere le classi di supporto che verranno usate dalla regola.

  1. Avviare Visual Studio Code e aprire la cartella in cui si vuole creare il progetto.

  2. In Visual Studio Code aprire la finestra del terminale selezionando il menu Visualizza, quindi Terminale.

  3. Nel Terminale immettere i comandi seguenti per creare una nuova soluzione e progetto:

    dotnet new sln
    dotnet new classlib -n SampleRules -o SampleRules
    dotnet sln add SampleRules/SampleRules.csproj
    
  4. Passare alla directory SampleRules:

    cd SampleRules
    
  5. Aggiungere i pacchetti NuGet necessari:

    dotnet add package Microsoft.SqlServer.DacFx
    

A questo punto aggiungere le classi di supporto che verranno usate dalla regola.

  1. Aprire un prompt dei comandi o una finestra di terminale e passare alla cartella in cui si vuole creare il progetto.

  2. Nel Terminale immettere i comandi seguenti per creare una nuova soluzione e progetto:

    dotnet new sln
    dotnet new classlib -n SampleRules -o SampleRules
    dotnet sln add SampleRules/SampleRules.csproj
    
  3. Passare alla directory SampleRules:

    cd SampleRules
    
  4. Aggiungere i pacchetti NuGet necessari:

    dotnet add package Microsoft.SqlServer.DacFx
    

Passaggio 2: creare classi helper di regole personalizzate

Prima di creare la classe per la regola stessa, aggiungere al progetto una classe visitor e una classe attribute. Queste classi possono rivelarsi utili per la creazione di altre regole personalizzate.

Passaggio 2.1: definizione della classe WaitForDelayVisitor

La prima classe da definire è la classe WaitForDelayVisitor, derivata da TSqlConcreteFragmentVisitor. Questa classe fornisce l'accesso alle istruzioni WAITFOR DELAY nel modello. Le classi visitor usano le API ScriptDom fornite da SQL Server. In questa API il codice Transact-SQL viene rappresentato come un albero sintattico astratto e le classi visitor possono essere utili per trovare oggetti di sintassi specifici quali le istruzioni WAITFOR DELAY. Può essere difficile trovare queste istruzioni usando il modello a oggetti, poiché non sono associate a una proprietà o a una relazione di un oggetto specifico, mentre è facile trovarle con il modello visitor e l'API ScriptDom.

  1. In Esplora soluzioni selezionare il progetto SampleRules.

  2. Nel menu Progetto selezionare Aggiungi classe. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento. Nella casella di testo Nome, digitare WaitForDelayVisitor.cs e quindi selezionare Aggiungi. Il file WaitForDelayVisitor.cs viene aggiunto al progetto in Esplora soluzioni.

  1. In Esplora soluzioni selezionare il progetto SampleRules.

  2. Nel menu Progetto selezionare Aggiungi classe. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento. Nella casella di testo Nome, digitare WaitForDelayVisitor.cs e quindi selezionare Aggiungi. Il file WaitForDelayVisitor.cs viene aggiunto al progetto in Esplora soluzioni.

  1. In Visual Studio Code aprire la vista Esplora.

  2. Nella cartella WaitForDelayVisitor.cs, creare un nuovo file denominato SampleRules.

  1. Passare alla directory SampleRules.
  2. Creare un file denominato WaitForDelayVisitor.cs.
  1. Aprire il file WaitForDelayVisitor.cs e aggiornare il contenuto in modo che corrisponda al codice seguente:

    using System.Collections.Generic;
    using Microsoft.SqlServer.TransactSql.ScriptDom;
    namespace SampleRules {
        class WaitForDelayVisitor {}
    }
    
  2. Nella dichiarazione di classe impostare il modificatore di accesso su internal e derivare la classe da TSqlConcreteFragmentVisitor:

    internal class WaitForDelayVisitor : TSqlConcreteFragmentVisitor {}
    
  3. Aggiungere il codice seguente per definire la variabile membro dell'elenco:

    public IList<WaitForStatement> WaitForDelayStatements { get; private set; }
    
  4. Definire il costruttore della classe aggiungendo il codice seguente:

    public WaitForDelayVisitor() {
       WaitForDelayStatements = new List<WaitForStatement>();
    }
    
  5. Eseguire l'override del metodo ExplicitVisit aggiungendo il codice seguente:

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

    Questo metodo visita le istruzioni WAITFOR nel modello e aggiunge quelle per cui è specificata l'opzione DELAY all'elenco di istruzioni WAITFOR DELAY. La classe principale a cui si fa riferimento qui è WaitForStatement.

  6. Scegliere Save (Salva) dal menu File.

Passaggio 2.2: Aggiungere un file di risorse e tre stringhe di risorse

A questo punto aggiungere un file di risorse che definirà il nome della regola, la descrizione della regola e la categoria in cui la regola verrà visualizzata nell'interfaccia di configurazione delle regole.

  1. In Esplora soluzioni selezionare il progetto SampleRules. Nel menu Progetto, selezionare Aggiungi e poi Nuovo elemento. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento.

  2. Nell'elenco dei Modelli installati, fare clic su Generale. Nel riquadro dei dettagli, fare clic su File di risorse.

  3. In Nomedigitare RuleResources.resx. Viene visualizzato l'editor delle risorse, senza alcuna risorsa definita.

  4. Definire quattro stringhe di risorse come segue:

    Nome Valore
    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. Nel menu Salva RuleResources.resx, selezionare Salva RuleResources.resx.

  1. In Esplora soluzioni selezionare il progetto SampleRules. Nel menu Progetto, selezionare Aggiungi e poi Nuovo elemento. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento.

  2. Nell'elenco dei Modelli installati, fare clic su Generale. Nel riquadro dei dettagli, fare clic su File di risorse.

  3. In Nomedigitare RuleResources.resx. Viene visualizzato l'editor delle risorse, senza alcuna risorsa definita.

  4. Definire quattro stringhe di risorse come segue:

    Nome Valore
    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. Nel menu Salva RuleResources.resx, selezionare Salva RuleResources.resx.

  1. Creare un nuovo file denominato RuleResources.resx nella directory SampleRules.

  2. Aprire il file RuleResources.resx e aggiungere il codice seguente:

    <?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. Salvare il file RuleResources.resx.

  4. Aprire il file SampleRules.csproj e aggiungere il codice seguente per aggiornare e includere il contenuto della risorsa nel progetto:

    <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. Salvare il file SampleRules.csproj.

  1. Creare un nuovo file denominato RuleResources.resx nella directory SampleRules.

  2. Aprire il file RuleResources.resx e aggiungere il codice seguente:

    <?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. Salvare il file RuleResources.resx.

  4. Aprire il file SampleRules.csproj e aggiungere il codice seguente per aggiornare e includere il contenuto della risorsa nel progetto:

    <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. Salvare il file SampleRules.csproj.

Passaggio 2.3: Definire la classe LocalizedExportCodeAnalysisRuleAttribute

La seconda classe è LocalizedExportCodeAnalysisRuleAttribute.cs. Si tratta di un'estensione del Microsoft.SqlServer.Dac.CodeAnalysis.ExportCodeAnalysisRuleAttribute predefinito fornito dal framework e supporta la lettura di DisplayName e Description usati dalla regola da un file di risorse. È una classe utile se si prevede di usare le regole in più lingue.

  1. In Esplora soluzioni selezionare il progetto SampleRules.

  2. Nel menu Progetto selezionare Aggiungi classe. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento. Nella casella di testo Nome, digitare LocalizedExportCodeAnalysisRuleAttribute.cs e quindi selezionare Aggiungi. Il file viene aggiunto al progetto in Esplora soluzioni.

  1. In Esplora soluzioni selezionare il progetto SampleRules.

  2. Nel menu Progetto selezionare Aggiungi classe. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento. Nella casella di testo Nome, digitare LocalizedExportCodeAnalysisRuleAttribute.cs e quindi selezionare Aggiungi. Il file viene aggiunto al progetto in Esplora soluzioni.

  1. Passare alla directory SampleRules nella vista Esplora in Visual Studio Code.
  2. Creare un file denominato LocalizedExportCodeAnalysisRuleAttribute.cs.
  1. Passare alla directory SampleRules.
  2. Creare un file denominato LocalizedExportCodeAnalysisRuleAttribute.cs.
  1. Aprire il file e aggiornare il contenuto in modo che corrisponda al codice seguente:

    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;
                }
            }
        }
    }
    

Passaggio 2.4: definizione della classe SampleConstants

A questo punto definire una classe che faccia riferimento alle risorse nel file di risorse usate da Visual Studio per visualizzare le informazioni sulla regola nell'interfaccia utente.

  1. In Esplora soluzioni selezionare il progetto SampleRules.

  2. Nel menu Progetto selezionare Aggiungi, quindi Classe. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento. Nella casella di testo Nome, digitare SampleRuleConstants.cs, quindi selezionare il pulsante Agiungi. Il file SampleRuleConstants.cs viene aggiunto al progetto in Esplora soluzioni.

  1. In Esplora soluzioni selezionare il progetto SampleRules.

  2. Nel menu Progetto selezionare Aggiungi, quindi Classe. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento. Nella casella di testo Nome, digitare SampleRuleConstants.cs, quindi selezionare il pulsante Agiungi. Il file SampleRuleConstants.cs viene aggiunto al progetto in Esplora soluzioni.

  1. Passare alla directory SampleRules nella vista Esplora in Visual Studio Code.
  2. Creare un file denominato SampleRuleConstants.cs.
  1. Passare alla directory SampleRules.
  2. Creare un file denominato SampleRuleConstants.cs.
  1. Aprire il file SampleRuleConstants.cs e aggiungere le istruzioni using seguente al file:

    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. Scegliere Save (Salva) dal menu File.

Passaggio 3: creare una classe di regole personalizzate

Dopo avere aggiunto le classi helper che verranno usate dalla regola di analisi del codice personalizzata, creare una classe di regole personalizzate e denominarla AvoidWaitForDelayRule. La regola personalizzata AvoidWaitForDelayRule sarà usata per consentire agli sviluppatori di database di evitare le istruzioni WAITFOR DELAY in stored procedure, trigger e funzioni.

Passaggio 3.1: creazione della classe AvoidWaitForDelayRule

  1. In Esplora soluzioni selezionare il progetto SampleRules.

  2. Nel menu Progetto selezionare Aggiungi, quindi Classe. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento. Nella casella di testo Nome, digitare AvoidWaitForDelayRule.cs e quindi selezionare Aggiungi. Il file AvoidWaitForDelayRule.cs viene aggiunto al progetto in Esplora soluzioni.

  1. In Esplora soluzioni selezionare il progetto SampleRules.

  2. Nel menu Progetto selezionare Aggiungi, quindi Classe. Verrà visualizzata la finestra di dialogo Aggiungi nuovo elemento. Nella casella di testo Nome, digitare AvoidWaitForDelayRule.cs e quindi selezionare Aggiungi. Il file AvoidWaitForDelayRule.cs viene aggiunto al progetto in Esplora soluzioni.

  1. Passare alla directory SampleRules nella vista Esplora in Visual Studio Code.
  2. Creare un file denominato AvoidWaitForDelayRule.cs.
  1. Passare alla directory SampleRules.
  2. Creare un file denominato AvoidWaitForDelayRule.cs.
  1. Aprire il file AvoidWaitForDelayRule.cs e aggiungere le istruzioni using seguente al file:

    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. Nella dichiarazione della classe AvoidWaitForDelayRule impostare il modificatore di accesso su public:

    /// <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. Derivare la classe AvoidWaitForDelayRule dalla classe base Microsoft.SqlServer.Dac.CodeAnalysis.SqlCodeAnalysisRule:

    public sealed class AvoidWaitForDelayRule : SqlCodeAnalysisRule
    
  4. Aggiungere LocalizedExportCodeAnalysisRuleAttribute alla classe.

    LocalizedExportCodeAnalysisRuleAttribute consente al servizio di analisi del codice di individuare le regole di analisi del codice personalizzate. Solo le classi contrassegnate con ExportCodeAnalysisRuleAttribute (o con un attributo che eredita da questa classe) possono essere usate nell'analisi del codice.

    LocalizedExportCodeAnalysisRuleAttribute fornisce alcuni metadati necessari usati dal servizio. Tra cui un ID univoco per questa regola, un nome visualizzato che verrà visualizzato nell'interfaccia utente di Visual Studio e un Description che può essere usato dalla regola durante l'identificazione dei problemi.

    [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";
    }
    

    La proprietà RuleScope deve essere Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleScope.Element così come questa regola analizza elementi specifici. La regola viene chiamata una volta per ogni elemento corrispondente nel modello. Se si vuole analizzare un intero modello, allora è invece possibile usare Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleScope.Model.

  5. Aggiungere un costruttore che imposta Microsoft.SqlServer.Dac.CodeAnalysis.SqlAnalysisRule.SupportedElementTypes. Questa operazione è necessaria per le regole il cui ambito è costituito da elementi. Definisce i tipi di elementi a cui viene applicata questa regola. In questo caso, la regola viene applicata a stored procedure, trigger e funzioni. La classe Microsoft.SqlServer.Dac.Model.ModelSchema elenca tutti i tipi di elemento disponibili che possono essere analizzati.

    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. Aggiungere un override per il metodo Microsoft.SqlServer.Dac.CodeAnalysis.SqlAnalysisRule.Analyze (Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleExecutionContext), che usa Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleExecutionContext come parametri di input. Questo metodo restituisce un elenco di potenziali problemi.

    Il metodo ottiene Microsoft.SqlServer.Dac.Model.TSqlModel, Microsoft.SqlServer.Dac.Model.TSqlObject e TSqlFragment dal parametro di contesto. La classe WaitForDelayVisitor viene quindi usata per ottenere un elenco di tutte le istruzioni WAITFOR DELAY nel modello.

    Per ogni WaitForStatement in tale elenco, viene creato un oggetto 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. Nel menu File selezionare Salva.

Passaggio 4: compilare la libreria di classi

  1. Scegliere Proprietà SampleRules dal menu Progetto.
  2. Seleziona la scheda Firma.
  3. Selezionare Firma l’assembly.
  4. In Scegli un file chiave con nome sicuro, fare clic su <Nuovo>.
  5. Nella finestra di dialogo Crea chiave con nome sicuro, in Nome file di chiave, digitare MyRefKey.
  6. (facoltativo) È possibile specificare una password per il file di chiave con nome sicuro.
  7. Seleziona OK.
  8. Scegliere Save All (Salva tutto) dal menu File.
  9. Scegliere Compila soluzione dal menu Compila.
  1. Scegliere Proprietà SampleRules dal menu Progetto.
  2. Seleziona la scheda Firma.
  3. Selezionare Firma l’assembly.
  4. In Scegli un file chiave con nome sicuro, fare clic su <Nuovo>.
  5. Nella finestra di dialogo Crea chiave con nome sicuro, in Nome file di chiave, digitare MyRefKey.
  6. (facoltativo) È possibile specificare una password per il file di chiave con nome sicuro.
  7. Seleziona OK.
  8. Scegliere Save All (Salva tutto) dal menu File.
  9. Scegliere Compila soluzione dal menu Compila.
  1. In Visual Studio Code aprire la finestra del terminale selezionando il menu Visualizza, quindi Terminale.

  2. Immettere il comando seguente nel terminale per compilare il progetto:

    dotnet build /p:Configuration=Release
    
  1. Passare alla directory SampleRules.

  2. Eseguire il comando seguente per compilare il progetto:

    dotnet build /p:Configuration=Release
    

Passaggio 5: installare e testare la nuova regola di analisi del codice

È quindi necessario installare l'assembly in modo che venga caricato quando si compilano progetti di database di SQL.

Per installare una regola che verrà eseguita quando si compila un progetto SQL originale con Visual Studio, è necessario copiare l'assembly e il file associato .pdb nella cartella Estensioni.

Passaggio 5.1: installare l'assembly SampleRules

Successivamente, copiare le informazioni sull'assembly nella directory Estensioni. All'avvio di Visual Studio, le eventuali estensioni vengono identificate nella directory <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions e relative sottodirectory, quindi vengono rese disponibili per l'uso.

Per Visual Studio 2022, è <Visual Studio Install Dir> in genere C:\Program Files\Microsoft Visual Studio\2022\Enterprise. Sostituire Enterprise con Professional o Community a seconda dell'edizione di Visual Studio installata.

Copiare il file di assembly SampleRules.dll dalla directory di output alla directory <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions. Per impostazione predefinita, il percorso del file .dll compilato è YourSolutionPath\YourProjectPath\bin\Debug o YourSolutionPath\YourProjectPath\bin\Release.

Nota

Potrebbe essere necessario creare la directory Extensions.

La regola verrà quindi installata e verrà visualizzata al riavvio di Visual Studio. Quindi, avviare una nuova sessione di Visual Studio e creare un progetto di database.

Passaggio 5.2: avviare una nuova sessione di Visual Studio e creare un progetto di database

  1. Avviare una seconda sessione di Visual Studio.
  2. Selezionare File>New (Nuovo) >Project (Progetto).
  3. Nella finestra di dialogo Nuovo progetto individuare e selezionare Progetto di database di SQL Server.
  4. Nella casella di testo Nome digitare SampleRulesDB e quindi selezionare OK.

Passaggio 5.3: abilitare la regola di analisi del codice AvoidWaitForRule

  1. In Esplora soluzioni selezionare il progetto SampleRulesDB.
  2. Scegliere Proprietà dal menu Progetto. Verrà visualizzata la pagina proprietà SampleRulesDB.
  3. Selezionare Analisi del codice. Verrà visualizzata una nuova categoria denominata RuleSamples.CategorySamples.
  4. Espandere RuleSamples.CategorySamples. Dovrebbe essere visualizzato SR1004: Avoid WAITFOR DELAY statement in stored procedures, triggers, and functions.
  5. Abilitare questa regola selezionando la casella di controllo accanto al nome della regola e alla casella di controllo Abilita l'analisi del codice nella compilazione. Per altre informazioni sull'abilitazione dell'analisi del codice, vedere Panoramica dell'analisi del codice.
  6. Quando viene usata l'azione di compilazione del progetto, la regola verrà eseguita e tutte le istruzioni WAITFOR DELAY trovate verranno segnalate come avvisi.

Per installare una regola che verrà eseguita quando si compila un progetto SQL originale con Visual Studio, è necessario copiare l'assembly e il file associato .pdb nella cartella Estensioni.

Passaggio 5.1: installare l'assembly SampleRules

Successivamente, copiare le informazioni sull'assembly nella directory Estensioni. All'avvio di Visual Studio, le eventuali estensioni vengono identificate nella directory <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions e relative sottodirectory, quindi vengono rese disponibili per l'uso.

Per Visual Studio 2022, è <Visual Studio Install Dir> in genere C:\Program Files\Microsoft Visual Studio\2022\Enterprise. Sostituire Enterprise con Professional o Community a seconda dell'edizione di Visual Studio installata.

Copiare il file di assembly SampleRules.dll dalla directory di output alla directory <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions. Per impostazione predefinita, il percorso del file .dll compilato è YourSolutionPath\YourProjectPath\bin\Debug o YourSolutionPath\YourProjectPath\bin\Release.

Nota

Potrebbe essere necessario creare la directory Extensions.

La regola verrà quindi installata e verrà visualizzata al riavvio di Visual Studio. Quindi, avviare una nuova sessione di Visual Studio e creare un progetto di database.

Passaggio 5.2: avviare una nuova sessione di Visual Studio e creare un progetto di database

  1. Avviare una seconda sessione di Visual Studio.
  2. Selezionare File>New (Nuovo) >Project (Progetto).
  3. Nella finestra di dialogo Nuovo progetto individuare e selezionare Progetto di database di SQL Server in stile SDK (anteprima).
  4. Nella casella di testo Nome digitare SampleRulesDB e quindi selezionare OK.

Passaggio 5.3: abilitare la regola di analisi del codice AvoidWaitForRule

  1. In Esplora soluzioni selezionare il progetto SampleRulesDB.
  2. Doppio clic su un nodo del progetto per aprire il file di progetto. Il file di progetto SampleRulesDB viene visualizzato in un editor di testo.
  3. Abilitare l'analisi del codice in fase di compilazione nel file di progetto SQL impostando la proprietà RunSqlCodeAnalysis su true.
  4. Quando viene usata l'azione di compilazione del progetto, la regola verrà eseguita e tutte le istruzioni WAITFOR DELAY trovate verranno segnalate come avvisi.

Una soluzione alternativa è disponibile per i progetti in stile SDK per installare regole personalizzate fino a quando non sono supportati i riferimenti ai pacchetti.

  1. Eseguire dotnet restore per ripristinare le dipendenze del progetto nel progetto SQL, assicurandosi che la cache dei pacchetti NuGet locale contenga Microsoft.Build.Sql.
  2. Si noti la versione di Microsoft.Build.Sql usata nel file di progetto SQL, ad esempio 0.1.19-preview.
  3. Copiare il file di assembly SampleRules.dll dalla directory di output alla directory ~/.nuget/packages/microsoft.build.sql/0.1.19-preview/tools/netstandard2.1. Il percorso esatto della directory può variare a seconda della versione di Microsoft.Build.Sql usata nel file di progetto SQL.
  4. Abilitare l'analisi del codice in fase di compilazione nel file di progetto SQL impostando la proprietà RunSqlCodeAnalysis su true.
  5. Eseguire dotnet build per compilare il progetto SQL ed eseguire la regola personalizzata.

Una soluzione alternativa è disponibile per i progetti in stile SDK per installare regole personalizzate fino a quando non sono supportati i riferimenti ai pacchetti.

  1. Eseguire dotnet restore per ripristinare le dipendenze del progetto nel progetto SQL, assicurandosi che la cache dei pacchetti NuGet locale contenga Microsoft.Build.Sql.
  2. Si noti la versione di Microsoft.Build.Sql usata nel file di progetto SQL, ad esempio 0.1.19-preview.
  3. Copiare il file di assembly SampleRules.dll dalla directory di output alla directory ~/.nuget/packages/microsoft.build.sql/0.1.19-preview/tools/netstandard2.1. Il percorso esatto della directory può variare a seconda della versione di Microsoft.Build.Sql usata nel file di progetto SQL.
  4. Abilitare l'analisi del codice in fase di compilazione nel file di progetto SQL impostando la proprietà RunSqlCodeAnalysis su true.
  5. Eseguire dotnet build per compilare il progetto SQL ed eseguire la regola personalizzata.