Creación de reglas de Code Analysis personalizadas
Se aplica a: SQL Server Azure SQL Database Azure SQL Managed Instance Base de datos de Azure SQL de Microsoft Fabric
En este tutorial se muestran los pasos utilizados para crear una regla de Code Analysis de SQL Server. La regla creada en este tutorial se utiliza para evitar las instrucciones WAITFOR DELAY
en procedimientos almacenados, desencadenadores y funciones.
En este tutorial, crearás una regla personalizada de análisis de código estático de Transact-SQL mediante el uso de los siguientes pasos:
- Cree un proyecto de biblioteca de clases, habilite la firma para el proyecto y agregue las referencias necesarias.
- Crea dos clases del asistente de C#.
- Crea una clase de regla personalizada de C#.
- Compile el proyecto de biblioteca de clases.
- Instale y pruebe la nueva regla de Code Analysis.
Excepto para las instrucciones de Visual Studio (SQL Server Data Tools), la guía se centra en proyectos SQL de estilo SDK.
Requisitos previos
Necesitará los componentes siguientes para completar este tutorial:
- Una versión de Visual Studio instalada que incluya SQL Server Data Tools y admita el desarrollo de C# .NET Framework.
- Un proyecto de SQL que contenga objetos de SQL Server.
- Una instancia de SQL Server a la que pueda implementar un proyecto de base de datos.
Este tutorial está destinado a usuarios que ya están familiarizados con las características de SQL Server de SQL Server Data Tools. Debes estar familiarizado con los conceptos de Visual Studio, por ejemplo, cómo crear una biblioteca de clases, agregar paquetes NuGet o cómo utilizar el editor de código para agregar código a una clase.
Nota:
Debido a las limitaciones de la versión preliminar de SQL Server Data Tools de estilo SDK, se requieren varias instalaciones de Visual Studio para completar este tutorial. La primera instalación es necesaria para crear el proyecto de biblioteca de clases; la segunda instalación es necesaria para crear el proyecto de base de datos SQL de estilo SDK.
- SDK DE .NET 8
- Visual Studio 2022 Community, Professional o Enterprise
- SQL Server Data Tools, estilo SDK (versión preliminar) instalado en Visual Studio 2022
- Una versión de Visual Studio instalada que admita el desarrollo de C# .NET.
- Un proyecto de SQL que contenga objetos de SQL Server.
Este tutorial está destinado a usuarios que ya están familiarizados con las características de SQL Server de SQL Server Data Tools. Debes estar familiarizado con los conceptos de Visual Studio, por ejemplo, cómo crear una biblioteca de clases, agregar paquetes NuGet o cómo utilizar el editor de código para agregar código a una clase.
- Una versión de Visual Studio Code instalada, que incluye la extensión Proyectos de SQL Database.
- Un proyecto de base de datos SQL que contenga objetos de SQL.
- SDK DE .NET 8
- Recomendado: Extensión del kit de desarrollo de C# para VS Code
Este tutorial está diseñado para los usuarios que ya están familiarizados con la extensión Proyectos de base de datos SQL en Visual Studio Code. Debes estar familiarizado con los conceptos de desarrollo, por ejemplo, cómo crear una biblioteca de clases, agregar paquetes o cómo utilizar el editor de código para editar código.
- Un editor de texto, como el editor de archivos de Visual Studio Code.
- Un proyecto de base de datos SQL que contenga objetos de SQL.
- SDK DE .NET 8
Este tutorial está destinado a usuarios que ya están familiarizados con los proyectos de SQL. Debes estar familiarizado con los conceptos de desarrollo, por ejemplo, cómo crear una biblioteca de clases, agregar paquetes o cómo utilizar el editor de código para editar código.
Paso 1: cree un nuevo proyecto de biblioteca de clases
En primer lugar, cree una biblioteca de clases. Para crear un proyecto de biblioteca de clases:
Cree un proyecto de biblioteca de clases (.NET Framework) en C# llamado
SampleRules
.Cambie el nombre del archivo
Class1.cs
aAvoidWaitForDelayRule.cs
.En el Explorador de soluciones, haz clic con el botón derecho en el nodo de proyecto y, a continuación, selecciona Agregar; después, selecciona Referencia.
Selecciona
System.ComponentModel.Composition
en la pestaña Ensamblados\Marcos.En el Explorador de soluciones, haz clic con el botón derecho en el nodo del proyecto y, después, selecciona Administrar paquetes NuGet. Busca e instala el paquete de NuGet
Microsoft.SqlServer.DacFx
. La versión seleccionada debe ser162.x.x
(por ejemplo,162.2.111
) con Visual Studio 2022.
A continuación, agrega las clases auxiliares que utilizará la regla.
En primer lugar, cree una biblioteca de clases. Para crear un proyecto de biblioteca de clases:
Cree un proyecto de biblioteca de clases (.NET Framework) en C# llamado
SampleRules
.Cambie el nombre del archivo
Class1.cs
aAvoidWaitForDelayRule.cs
.En el Explorador de soluciones, haz clic con el botón derecho en el nodo de proyecto y, a continuación, selecciona Agregar; después, selecciona Referencia.
Selecciona
System.ComponentModel.Composition
en la pestaña Ensamblados\Marcos.En el Explorador de soluciones, haz clic con el botón derecho en el nodo del proyecto y, después, selecciona Administrar paquetes NuGet. Busca e instala el paquete de NuGet
Microsoft.SqlServer.DacFx
. La versión seleccionada debe ser162.x.x
(por ejemplo,162.2.111
) con Visual Studio 2022.
A continuación, agrega las clases auxiliares que utilizará la regla.
Inicie Visual Studio Code y abra la carpeta donde desea crear el proyecto.
Abra una ventana Terminal en Visual Studio Code seleccionando el menú Visualizar y, a continuación, Terminal.
En el Terminal, escriba los siguientes comandos para crear una nueva solución y un nuevo proyecto:
dotnet new sln dotnet new classlib -n SampleRules -o SampleRules dotnet sln add SampleRules/SampleRules.csproj
Cambie al directorio
SampleRules
:cd SampleRules
Añada el paquete NuGet necesario:
dotnet add package Microsoft.SqlServer.DacFx
A continuación, agrega las clases auxiliares que utilizará la regla.
Abra una ventana del símbolo del sistema o del terminal y vaya a la carpeta donde quiere crear el proyecto.
En el Terminal, escriba los siguientes comandos para crear una nueva solución y un nuevo proyecto:
dotnet new sln dotnet new classlib -n SampleRules -o SampleRules dotnet sln add SampleRules/SampleRules.csproj
Cambie al directorio
SampleRules
:cd SampleRules
Añada el paquete NuGet necesario:
dotnet add package Microsoft.SqlServer.DacFx
Paso 2: Creación de clases auxiliares de reglas personalizadas
Antes de crear la clase para la regla en sí, deberás agregar al proyecto una clase de visitante y una clase de atributos. Estas clases pueden ser útiles para crear reglas personalizadas adicionales.
Paso 2.1: Definición de la clase WaitForDelayVisitor
La primera clase que debes definir es la clase WaitForDelayVisitor
, que se deriva de TSqlConcreteFragmentVisitor. Esta clase proporciona acceso a las instrucciones WAITFOR DELAY
en el modelo. Las clases de visitante hacen uso de la API ScriptDom, proporcionada por SQL Server. En esta API, el código Transact-SQL se representa como un árbol de sintaxis abstracta (AST) y las clases de visitante pueden ser útiles para buscar objetos de sintaxis específica, como instrucciones WAITFOR DELAY
. Puede ser difícil encontrar estas instrucciones utilizando el modelo de objetos, ya que no están asociadas a una propiedad de objeto o relación específicas, pero puedes encontrarlas mediante el patrón de visitante y la API ScriptDom.
En el Explorador de soluciones, seleccione el proyecto
SampleRules
.En el menú Proyecto, seleccione Agregar clase. Aparecerá el cuadro de diálogo Agregar nuevo elemento . En el cuadro de texto Nombre, escribe
WaitForDelayVisitor.cs
y, después, selecciona Agregar. El archivoWaitForDelayVisitor.cs
se agrega al proyecto en el Explorador de soluciones.
En el Explorador de soluciones, seleccione el proyecto
SampleRules
.En el menú Proyecto, seleccione Agregar clase. Aparecerá el cuadro de diálogo Agregar nuevo elemento . En el cuadro de texto Nombre, escribe
WaitForDelayVisitor.cs
y, después, selecciona Agregar. El archivoWaitForDelayVisitor.cs
se agrega al proyecto en el Explorador de soluciones.
En Visual Studio Code, abra la vista Explorer (Explorador).
En la carpeta
WaitForDelayVisitor.cs
, cree un nuevo archivo denominadoSampleRules
.
- Vaya al directorio
SampleRules
. - Cree un nuevo archivo llamado
WaitForDelayVisitor.cs
.
Abre el archivo
WaitForDelayVisitor.cs
y actualiza el contenido para que coincida con el código siguiente:using System.Collections.Generic; using Microsoft.SqlServer.TransactSql.ScriptDom; namespace SampleRules { class WaitForDelayVisitor {} }
En la declaración de clase, cambia el modificador de acceso a internal y deriva la clase de
TSqlConcreteFragmentVisitor
:internal class WaitForDelayVisitor : TSqlConcreteFragmentVisitor {}
Agregue el código siguiente para definir la variable de miembro de lista:
public IList<WaitForStatement> WaitForDelayStatements { get; private set; }
Defina el constructor de clase agregando el código siguiente:
public WaitForDelayVisitor() { WaitForDelayStatements = new List<WaitForStatement>(); }
Anula el método
ExplicitVisit
al agregar el código siguiente:public override void ExplicitVisit(WaitForStatement node) { // We are only interested in WAITFOR DELAY occurrences if (node.WaitForOption == WaitForOption.Delay) WaitForDelayStatements.Add(node); }
Este método pasa por las instrucciones
WAITFOR
del modelo y agrega las que tienen la opciónDELAY
especificada a la lista de instruccionesWAITFOR DELAY
. La clase clave a la que se hace referencia es WaitForStatement.En el menú Archivo, seleccione Guardar.
Paso 2.2: Agregar un archivo de recursos y tres cadenas de recursos
A continuación, agrega un archivo de recursos en el que se defina el nombre de regla, su descripción y la categoría en la que aparecerá la regla en la interfaz de configuración de reglas.
En el Explorador de soluciones, seleccione el proyecto
SampleRules
. En el menú Proyecto, selecciona Agregar y, a continuación, Nuevo elemento. Aparecerá el cuadro de diálogo Agregar nuevo elemento.En la lista de Plantillas instaladas, selecciona General. En el panel de detalles, selecciona Archivo de recursos.
En Nombre, escriba
RuleResources.resx
. Aparece el editor de recursos, sin recursos definidos.Defina cuatro cadenas de recursos, como sigue:
Nombre 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}.
En el menú Archivo, selecciona Guardar RuleResources.resx.
En el Explorador de soluciones, seleccione el proyecto
SampleRules
. En el menú Proyecto, selecciona Agregar y, a continuación, Nuevo elemento. Aparecerá el cuadro de diálogo Agregar nuevo elemento.En la lista de Plantillas instaladas, selecciona General. En el panel de detalles, selecciona Archivo de recursos.
En Nombre, escriba
RuleResources.resx
. Aparece el editor de recursos, sin recursos definidos.Defina cuatro cadenas de recursos, como sigue:
Nombre 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}.
En el menú Archivo, selecciona Guardar RuleResources.resx.
En el directorio
SampleRules
, cree un nuevo archivo denominadoRuleResources.resx
.Abra el archivo
RuleResources.resx
y agregue el código siguiente:<?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>
Guarde el archivo
RuleResources.resx
.Abra el archivo
SampleRules.csproj
y agregue el código siguiente para actualizar e incluir el contenido del recurso en el proyecto:<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>
Guarde el archivo
SampleRules.csproj
.
En el directorio
SampleRules
, cree un nuevo archivo denominadoRuleResources.resx
.Abra el archivo
RuleResources.resx
y agregue el código siguiente:<?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>
Guarde el archivo
RuleResources.resx
.Abra el archivo
SampleRules.csproj
y agregue el código siguiente para actualizar e incluir el contenido del recurso en el proyecto:<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>
Guarde el archivo
SampleRules.csproj
.
Paso 2.3: Definir la clase LocalizedExportCodeAnalysisRuleAttribute
La segunda clase es LocalizedExportCodeAnalysisRuleAttribute.cs
. Se trata de una extensión de la versión integrada Microsoft.SqlServer.Dac.CodeAnalysis.ExportCodeAnalysisRuleAttribute
proporcionada por el marco de trabajo y admite la lectura de DisplayName
y Description
usadas por la regla desde un archivo de recursos. Esta clase es útil si desea que las reglas puedan utilizarse en varios idiomas.
En el Explorador de soluciones, seleccione el proyecto
SampleRules
.En el menú Proyecto, seleccione Agregar clase. Aparecerá el cuadro de diálogo Agregar nuevo elemento . En el cuadro de texto Nombre, escribe
LocalizedExportCodeAnalysisRuleAttribute.cs
y, después, selecciona Agregar. El archivo se agrega al proyecto en el Explorador de soluciones.
En el Explorador de soluciones, seleccione el proyecto
SampleRules
.En el menú Proyecto, seleccione Agregar clase. Aparecerá el cuadro de diálogo Agregar nuevo elemento . En el cuadro de texto Nombre, escribe
LocalizedExportCodeAnalysisRuleAttribute.cs
y, después, selecciona Agregar. El archivo se agrega al proyecto en el Explorador de soluciones.
- Vaya al directorio
SampleRules
en la vista Explorador de Visual Studio Code. - Cree un nuevo archivo llamado
LocalizedExportCodeAnalysisRuleAttribute.cs
.
- Vaya al directorio
SampleRules
. - Cree un nuevo archivo llamado
LocalizedExportCodeAnalysisRuleAttribute.cs
.
Abre el archivo y actualiza el contenido para que coincida con el código siguiente:
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; } } } }
Paso 2.4: Definición de la clase SampleConstants
A continuación, defina una clase que haga referencia a los recursos del archivo de recursos que Visual Studio utiliza para mostrar información acerca de la regla en la interfaz de usuario.
En el Explorador de soluciones, seleccione el proyecto
SampleRules
.En el menú Proyecto, selecciona Agregar y, a continuación, Clase. Aparecerá el cuadro de diálogo Agregar nuevo elemento. En el cuadro de texto Nombre, escribe
SampleRuleConstants.cs
y selecciona el botón Agregar. El archivoSampleRuleConstants.cs
se agrega al proyecto en el Explorador de soluciones.
En el Explorador de soluciones, seleccione el proyecto
SampleRules
.En el menú Proyecto, selecciona Agregar y, a continuación, Clase. Aparecerá el cuadro de diálogo Agregar nuevo elemento. En el cuadro de texto Nombre, escribe
SampleRuleConstants.cs
y selecciona el botón Agregar. El archivoSampleRuleConstants.cs
se agrega al proyecto en el Explorador de soluciones.
- Vaya al directorio
SampleRules
en la vista Explorador de Visual Studio Code. - Cree un nuevo archivo llamado
SampleRuleConstants.cs
.
- Vaya al directorio
SampleRules
. - Cree un nuevo archivo llamado
SampleRuleConstants.cs
.
Abre el archivo
SampleRuleConstants.cs
y agrega lo siguiente al archivo usando instrucciones: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"; } }
En el menú Archivo, seleccione Guardar.
Paso 3: cree una clase de regla personalizada
Después de agregar las clases del asistente que la regla de análisis de código personalizada utilizará, deberás crear una clase de reglas personalizada y asignarle el nombre AvoidWaitForDelayRule
. La regla personalizada AvoidWaitForDelayRule
se utilizará para ayudar a los desarrolladores de base de datos a evitar las instrucciones WAITFOR DELAY
en los procedimientos, desencadenadores y funciones almacenados.
Paso 3.1: Creación de la clase AvoidWaitForDelayRule
En el Explorador de soluciones, seleccione el proyecto
SampleRules
.En el menú Proyecto, selecciona Agregar y, a continuación, Clase. Aparecerá el cuadro de diálogo Agregar nuevo elemento. En el cuadro Nombre, escribe
AvoidWaitForDelayRule.cs
y, después, selecciona Agregar. El archivoAvoidWaitForDelayRule.cs
se agrega al proyecto en el Explorador de soluciones.
En el Explorador de soluciones, seleccione el proyecto
SampleRules
.En el menú Proyecto, selecciona Agregar y, a continuación, Clase. Aparecerá el cuadro de diálogo Agregar nuevo elemento. En el cuadro Nombre, escribe
AvoidWaitForDelayRule.cs
y, después, selecciona Agregar. El archivoAvoidWaitForDelayRule.cs
se agrega al proyecto en el Explorador de soluciones.
- Vaya al directorio
SampleRules
en la vista Explorador de Visual Studio Code. - Cree un nuevo archivo llamado
AvoidWaitForDelayRule.cs
.
- Vaya al directorio
SampleRules
. - Cree un nuevo archivo llamado
AvoidWaitForDelayRule.cs
.
Abre el archivo
AvoidWaitForDelayRule.cs
y agrega lo siguiente al archivo usando instrucciones: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 {} }
En la declaración de clase
AvoidWaitForDelayRule
, cambia el modificador de acceso a 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
Deriva la clase
AvoidWaitForDelayRule
de la clase baseMicrosoft.SqlServer.Dac.CodeAnalysis.SqlCodeAnalysisRule
:public sealed class AvoidWaitForDelayRule : SqlCodeAnalysisRule
Agregue
LocalizedExportCodeAnalysisRuleAttribute
a la clase.LocalizedExportCodeAnalysisRuleAttribute
permite al servicio de análisis de código detectar reglas de análisis de código personalizado. Solo las clases marcadas con unExportCodeAnalysisRuleAttribute
(o un atributo que hereda de este) pueden utilizarse en el análisis de código.LocalizedExportCodeAnalysisRuleAttribute
proporciona algunos metadatos necesarios usados por el servicio. Esto incluye un identificador único para esta regla, un nombre que se mostrará en la interfaz de usuario de Visual Studio y unaDescription
que la regla puede utilizar para identificar los 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"; }
La propiedad RuleScope debe ser
Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleScope.Element
, ya que esta regla analiza elementos específicos. La regla se llamará una vez para cada elemento coincidente del modelo. Si deseas analizar un modelo completo,Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleScope.Model
se puede usar en su lugar.Agrega un constructor que configure
Microsoft.SqlServer.Dac.CodeAnalysis.SqlAnalysisRule.SupportedElementTypes
. Esto es necesario para las reglas de ámbito de elemento. Define los tipos de elemento a los que se aplicará esta regla. En este caso, la regla se aplicará a los procedimientos, desencadenadores y funciones almacenados. La claseMicrosoft.SqlServer.Dac.Model.ModelSchema
enumera todos los tipos de elementos disponibles que se pueden analizar.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 }; }
Agrega una invalidación para el método
Microsoft.SqlServer.Dac.CodeAnalysis.SqlAnalysisRule.Analyze
(Microsoft.SqlServer.Dac.CodeAnalysis.SqlRuleExecutionContext)
, que usaMicrosoft.SqlServer.Dac.CodeAnalysis.SqlRuleExecutionContext
como parámetros de entrada. Este método devuelve una lista de posibles problemas.El método obtiene
Microsoft.SqlServer.Dac.Model.TSqlModel
,Microsoft.SqlServer.Dac.Model.TSqlObject
y TSqlFragment del parámetro de contexto. A continuación se utiliza la claseWaitForDelayVisitor
para obtener una lista de todas las instruccionesWAITFOR DELAY
del modelo.Para cada WaitForStatement de esa lista, se crea un
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); }
En el menú Archivo , seleccione Guardar.
Paso 4: compile la biblioteca de clases
- En el menú Proyecto, haz clic en Propiedades de SampleRules.
- Selecciona la pestaña Firma.
- Seleciona la casilla Firmar el ensamblado.
- En la lista Elija un archivo de clave de nombre seguro, selecciona <Nuevo>.
- En el cuadro de diálogo Crear clave de nombre seguro, en el Nombre del archivo clave, escribe
MyRefKey
. - (opcional) Puede especificar una contraseña para el archivo de clave de nombre seguro.
- Seleccione Aceptar.
- En el menú Archivo, seleccione Guardar todo.
- En el menú Compilar, seleccione Compilar solución.
- En el menú Proyecto, haz clic en Propiedades de SampleRules.
- Selecciona la pestaña Firma.
- Seleciona la casilla Firmar el ensamblado.
- En la lista Elija un archivo de clave de nombre seguro, selecciona <Nuevo>.
- En el cuadro de diálogo Crear clave de nombre seguro, en el Nombre del archivo clave, escribe
MyRefKey
. - (opcional) Puede especificar una contraseña para el archivo de clave de nombre seguro.
- Seleccione Aceptar.
- En el menú Archivo, seleccione Guardar todo.
- En el menú Compilar, seleccione Compilar solución.
Abra la ventana Terminal en Visual Studio Code seleccionando el menú Visualizar y, a continuación, Terminal.
En el Terminal, escriba el siguiente comando para compilar el proyecto:
dotnet build /p:Configuration=Release
Vaya al directorio
SampleRules
.Para compilar el proyecto, ejecute el siguiente comando:
dotnet build /p:Configuration=Release
Paso 5: instale y pruebe la nueva regla de Code Analysis
A continuación, debe instalar el ensamblado para que se cargue cuando compile un proyecto de base de datos SQL.
Para instalar una regla que se ejecutará al compilar un proyecto SQL original con Visual Studio, debe copiar el ensamblado y el archivo .pdb
asociado a la carpeta Extensiones.
Paso 5.1: Instalación del ensamblado SampleRules
Después, copia la información del ensamblado en el directorio Extensions. Cuando se inicie Visual Studio, este identificará todas las extensiones en el directorio <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions
y sus subdirectorios y las dejará disponibles para su uso.
Para Visual Studio 2022, <Visual Studio Install Dir>
normalmente es C:\Program Files\Microsoft Visual Studio\2022\Enterprise
. Reemplaza Enterprise
por Professional
o Community
en función de la edición de Visual Studio instalada.
Copia el archivo de ensamblado SampleRules.dll del directorio de salida en el directorio <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions
. De manera predeterminada, la ruta de acceso del archivo compilado .dll
es YourSolutionPath\YourProjectPath\bin\Debug
o YourSolutionPath\YourProjectPath\bin\Release
.
Nota:
Es posible que tengas que crear el directorio Extensions
.
La regla deberá entonces instalarse y aparecer al reiniciar Visual Studio. Después, iniciarás una nueva sesión de Visual Studio y crearás un proyecto de base de datos.
Paso 5.2: Inicio de una nueva sesión de Visual Studio y creación de un proyecto de base de datos
- Inicie una segunda sesión de Visual Studio.
- Seleccione Archivo>Nuevo>Proyecto.
- En el cuadro de diálogo Nuevo proyecto, busca y selecciona Proyecto de base de datos de SQL Server.
- En el cuadro Nombre, escribe
SampleRulesDB
y selecciona Aceptar.
Paso 5.3: Habilitar la regla de análisis de código AvoidWaitForRule
- En el Explorador de soluciones, seleccione el proyecto
SampleRulesDB
. - En el menú Proyecto, seleccione Propiedades. Se muestra la página Propiedades de
SampleRulesDB
. - Selecciona Análisis de código. Deberías ver una nueva categoría denominada
RuleSamples.CategorySamples
. - Expanda
RuleSamples.CategorySamples
. Deberías verSR1004: Avoid WAITFOR DELAY statement in stored procedures, triggers, and functions
. - Habilite esta regla seleccionando la casilla situada junto al nombre de la regla y la casilla Habilitar el análisis de código en la compilación. Para obtener más información sobre cómo habilitar el análisis de código, consulte la introducción al análisis de código.
- Cuando se usa la acción compilar el proyecto, la regla se ejecutará y las instrucciones
WAITFOR DELAY
encontradas se notificarán como advertencias.
Para instalar una regla que se ejecutará al compilar un proyecto SQL original con Visual Studio, debe copiar el ensamblado y el archivo .pdb
asociado a la carpeta Extensiones.
Paso 5.1: Instalación del ensamblado SampleRules
Después, copia la información del ensamblado en el directorio Extensions. Cuando se inicie Visual Studio, este identificará todas las extensiones en el directorio <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions
y sus subdirectorios y las dejará disponibles para su uso.
Para Visual Studio 2022, <Visual Studio Install Dir>
normalmente es C:\Program Files\Microsoft Visual Studio\2022\Enterprise
. Reemplaza Enterprise
por Professional
o Community
en función de la edición de Visual Studio instalada.
Copia el archivo de ensamblado SampleRules.dll del directorio de salida en el directorio <Visual Studio Install Dir>\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\Extensions
. De manera predeterminada, la ruta de acceso del archivo compilado .dll
es YourSolutionPath\YourProjectPath\bin\Debug
o YourSolutionPath\YourProjectPath\bin\Release
.
Nota:
Es posible que tengas que crear el directorio Extensions
.
La regla deberá entonces instalarse y aparecer al reiniciar Visual Studio. Después, iniciarás una nueva sesión de Visual Studio y crearás un proyecto de base de datos.
Paso 5.2: Inicio de una nueva sesión de Visual Studio y creación de un proyecto de base de datos
- Inicie una segunda sesión de Visual Studio.
- Seleccione Archivo>Nuevo>Proyecto.
- En el cuadro de diálogo Nuevo proyecto, busque y seleccione Proyecto de base de datos de SQL Server, estilo SDK (versión preliminar).
- En el cuadro Nombre, escribe
SampleRulesDB
y selecciona Aceptar.
Paso 5.3: Habilitar la regla de análisis de código AvoidWaitForRule
- En el Explorador de soluciones, seleccione el proyecto
SampleRulesDB
. - Haga doble clic en el nodo de proyecto para abrir el archivo de proyecto. El archivo de proyecto
SampleRulesDB
se muestra en un editor de texto. - Habilite el análisis de código en la compilación en el archivo de proyecto SQL estableciendo la propiedad
RunSqlCodeAnalysis
comotrue
. - Cuando se usa la acción compilar el proyecto, la regla se ejecutará y las instrucciones
WAITFOR DELAY
encontradas se notificarán como advertencias.
Hay disponible una solución alternativa para instalar reglas personalizadas en proyectos de estilo SDK hasta que se admita la compatibilidad con las referencias de paquetes.
- Ejecute
dotnet restore
para restaurar las dependencias del proyecto de SQL, asegurándose de que la memoria caché de los paquetes NuGet locales contiene Microsoft.Build.Sql. - Tenga en cuenta la versión de Microsoft.Build.Sql que se usa en el archivo de proyecto de SQL, como
0.1.19-preview
. - Copie el archivo de ensamblado
SampleRules.dll
del directorio de salida al directorio~/.nuget/packages/microsoft.build.sql/0.1.19-preview/tools/netstandard2.1
. La ruta de acceso exacta del directorio puede variar en función de la versión de Microsoft.Build.Sql usada en el archivo de proyecto SQL. - Habilite el análisis de código en la compilación en el archivo de proyecto SQL estableciendo la propiedad
RunSqlCodeAnalysis
comotrue
. - Ejecute
dotnet build
para compilar el proyecto SQL y ejecutar la regla personalizada.
Hay disponible una solución alternativa para instalar reglas personalizadas en proyectos de estilo SDK hasta que se admita la compatibilidad con las referencias de paquetes.
- Ejecute
dotnet restore
para restaurar las dependencias del proyecto de SQL, asegurándose de que la memoria caché de los paquetes NuGet locales contiene Microsoft.Build.Sql. - Tenga en cuenta la versión de Microsoft.Build.Sql que se usa en el archivo de proyecto de SQL, como
0.1.19-preview
. - Copie el archivo de ensamblado
SampleRules.dll
del directorio de salida al directorio~/.nuget/packages/microsoft.build.sql/0.1.19-preview/tools/netstandard2.1
. La ruta de acceso exacta del directorio puede variar en función de la versión de Microsoft.Build.Sql usada en el archivo de proyecto SQL. - Habilite el análisis de código en la compilación en el archivo de proyecto SQL estableciendo la propiedad
RunSqlCodeAnalysis
comotrue
. - Ejecute
dotnet build
para compilar el proyecto SQL y ejecutar la regla personalizada.