연습: SQL의 사용자 지정 정적 코드 분석 규칙 어셈블리 작성

이 단계별 항목에서는 SQL 코드 분석 규칙을 만드는 데 사용되는 단계를 보여 줍니다. 이 연습에서 만든 규칙은 저장 프로시저, 트리거 및 함수에서 WAITFOR DELAY 문을 방지하는 데 사용됩니다.

이 연습에서는 다음 프로세스를 사용하여 Transact-SQL 정적 코드 분석을 위한 사용자 지정 규칙을 만듭니다.

  1. 클래스 라이브러리를 만들고, 해당 프로젝트에 서명을 사용하도록 설정한 다음, 필요한 참조를 추가합니다.

  2. 두 개의 도우미 C# 클래스를 만듭니다.

  3. C# 사용자 지정 규칙 클래스를 만듭니다.

  4. 어셈블리를 등록하는 데 사용되는 XML 파일을 만듭니다.

  5. 사용자가 만든 결과 DLL과 XML 파일을 등록하기 위해 Extensions 디렉터리에 복사합니다.

  6. 새 코드 분석 규칙이 준비되었는지 확인합니다.

사전 요구 사항

이 연습을 완료하려면 Visual Studio Premium 또는 Visual Studio Ultimate이 설치되어 있어야 합니다.

SQL에 대한 사용자 지정 코드 분석 규칙 만들기

먼저 클래스 라이브러리를 만듭니다.

클래스 라이브러리를 만들려면

  1. 파일 메뉴에서 새로 만들기를 클릭한 다음 프로젝트를 클릭합니다.

  2. 새 프로젝트 대화 상자의 설치된 템플릿 목록에서 **Visual C#**을 클릭합니다.

  3. 세부 정보 창에서 클래스 라이브러리를 선택합니다.

  4. 이름 텍스트 상자에 SampleRules를 입력한 다음 확인을 클릭합니다.

다음으로, 프로젝트에 서명합니다.

프로젝트에 서명을 사용하도록 설정하려면

  1. 솔루션 탐색기에서 SampleRules 프로젝트 노드를 선택한 상태로 프로젝트 메뉴에서 속성을 클릭하거나, 솔루션 탐색기의 프로젝트 노드를 마우스 오른쪽 단추로 클릭한 다음 속성을 클릭합니다.

  2. 서명 탭을 클릭합니다.

  3. 어셈블리 서명 확인란을 선택합니다.

  4. 새 키 파일을 지정합니다. 강력한 이름 키 파일 선택 드롭다운 목록에서 **<새로 만들기...>**를 선택합니다.

    강력한 이름 키 만들기 대화 상자가 나타납니다. 자세한 내용은 강력한 이름 키 만들기 대화 상자를 참조하십시오.

  5. 강력한 이름 키 만들기 대화 상자에서 새 키 파일의 이름 텍스트 상자에 SampleRulesKey를 입력합니다. 이 연습에서는 암호를 제공할 필요가 없습니다. 자세한 내용은 어셈블리 및 매니페스트 서명 관리를 참조하십시오.

다음으로, 프로젝트에 필요한 참조를 추가합니다.

프로젝트에 적용 가능한 참조를 추가하려면

  1. 솔루션 탐색기에서 SampleRules 프로젝트를 선택합니다.

  2. 프로젝트 메뉴에서 참조 추가를 클릭합니다.

    참조 추가 대화 상자가 열립니다. 자세한 내용은 방법: Visual Studio에서 참조 추가 또는 제거를 참조하십시오.

  3. .NET 탭을 선택합니다.

  4. 구성 요소 이름 열에서 다음 구성 요소를 찾습니다.

    참고

    구성 요소를 여러 개 선택하려면 Ctrl 키를 누른 채 한 개씩 클릭합니다.

  5. 필요한 모든 구성 요소를 선택했으면 확인을 클릭합니다.

    솔루션 탐색기에서 프로젝트의 참조 노드 아래에 선택한 참조가 표시됩니다.

사용자 지정 코드 분석 규칙 지원 클래스 만들기

규칙 자체에 대한 클래스를 만들기 전에 프로젝트에 방문자 클래스와 도우미 클래스를 각각 하나씩 추가합니다.

이러한 클래스는 추가 사용자 지정 규칙을 만드는 데 유용할 수 있습니다.

TSqlConcreteFragmentVisitor에서 파생된 WaitForDelayVisitor 클래스를 가장 먼저 정의해야 합니다. 이 클래스는 모델의 WAITFOR DELAY 문에 액세스할 수 있게 해 줍니다.

WaitForDelayVisitor 클래스를 정의하려면

  1. 솔루션 탐색기에서 SampleRules 프로젝트를 선택합니다.

  2. 프로젝트 메뉴에서 클래스 추가를 선택합니다.

    새 항목 추가 대화 상자가 나타납니다.

  3. 이름 텍스트 상자에 WaitForDelayVisitor.cs를 입력한 다음 추가 단추를 클릭합니다.

    솔루션 탐색기에서 해당 프로젝트에 WaitForDelayVisitor.cs 파일이 추가됩니다.

  4. WaitForDelayVisitor.cs 파일을 열고 해당 내용을 다음 코드와 같이 업데이트합니다.

    using System.Collections.Generic;
    using Microsoft.Data.Schema.ScriptDom.Sql;
    
    namespace SampleRules
    {
        class WaitForDelayVistor
        {
        }
    }
    
  5. 클래스 선언에서 액세스 한정자를 internal로 변경하고 TSqlConcreteFragmentVisitor에서 파생 클래스를 만듭니다.

        internal class WaitForDelayVisitor : TSqlConcreteFragmentVisitor
        {
        }
    
  6. 다음 코드를 추가하여 List 멤버 변수를 정의합니다.

            private List<WaitForStatement> _waitForDelayStatments;
    
  7. 다음 코드를 추가하여 클래스 생성자를 정의합니다.

            #region ctor
            public WaitForDelayVisitor()
            {
                _waitForDelayStatments = new List<WaitForStatement>();
            }
            #endregion
    
  8. 다음 코드를 추가하여 읽기 전용 WaitForDelayStatements 속성을 정의합니다.

            #region properties
            public List<WaitForStatement> WaitForDelayStatements
            {
                get
                {
                    return _waitForDelayStatments;
                }
            }
            #endregion
    
  9. 다음 코드를 추가하여 ExplicitVisit 메서드를 재정의합니다.

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

    이 메서드는 모델의 각 WAITFOR 문을 방문하여 해당 문에 DELAY 옵션이 지정되어 있으면 WAITFOR DELAY 문의 목록에 추가합니다. 여기에서 참조하는 주요 클래스는 WaitForStatement입니다.

  10. 파일 메뉴에서 저장을 클릭합니다.

두 번째 클래스는 SqlRuleUtils.cs로, 이 클래스에는 이 연습의 뒷부분에 있는 사용자 지정 코드 분석 규칙 클래스 만들기 단원에서 만들 사용자 지정 코드 분석 규칙 클래스에 사용할 일부 유틸리티 메서드가 포함되어 있습니다. 이러한 방법은 다음과 같습니다.

  • GetElementName 이스케이프되고 정규화된 모델 요소 이름을 가져오는 데 사용합니다.

  • UpdateProblemPosition 줄 및 열 정보를 계산하는 데 사용합니다.

  • ReadFileContent 파일 내용을 읽는 데 사용합니다.

  • GetElementSourceFile 소스 파일을 가져오는 데 사용합니다.

  • ComputeLineColumn ScriptDom의 오프셋을 스크립트 파일의 줄과 열로 변환하는 데 사용합니다.

프로젝트에 SqlRuleUtils.cs 파일을 추가하려면

  1. 솔루션 탐색기에서 SampleRules 프로젝트를 선택합니다.

  2. 프로젝트 메뉴에서 클래스 추가를 선택합니다.

    새 항목 추가 대화 상자가 나타납니다.

  3. 이름 텍스트 상자에 SqlRuleUtils.cs를 입력한 다음 추가 단추를 클릭합니다.

    솔루션 탐색기의 프로젝트에 SqlRuleUtils.cs 파일이 추가됩니다.

  4. SqlRuleUtils.cs 파일을 열고 다음 using 문을 파일에 추가합니다.

    using System;
    using System.Diagnostics;
    using System.IO;
    using Microsoft.Data.Schema.SchemaModel;
    using Microsoft.Data.Schema.Sql.SchemaModel;
    using Microsoft.Data.Schema.StaticCodeAnalysis;
    using Microsoft.Data.Schema;
    
    
    namespace SampleRules
    {
    }
    
  5. SqlRuleUtils 클래스 선언에서 액세스 한정자를 public static으로 변경합니다.

        public static class SqlRuleUtils
        {
        }
    
  6. 다음 코드를 추가하여 SqlSchemaModelISqlModelElement를 입력 매개 변수로 사용하는 GetElementName 메서드를 만듭니다.

            /// <summary>
            /// Get escaped fully qualified name of a model element 
            /// </summary>
            /// <param name="sm">schema model</param>
            /// <param name="element">model element</param>
            /// <returns>name of the element</returns>
            public static string GetElementName(SqlSchemaModel sm, ISqlModelElement element)
            {
                return sm.DatabaseSchemaProvider.UserInteractionServices.GetElementName(element, ElementNameStyle.EscapedFullyQualifiedName);
            }
    
  7. 다음 코드를 추가하여 ReadFileContent 메서드를 만듭니다.

            /// <summary>
            /// Read file content from a file.
            /// </summary>
            /// <param name="filePath"> file path </param>
            /// <returns> file content in a string </returns>
            public static string ReadFileContent(string filePath)
            {
                //  Verify that the file exists first.
                if (!File.Exists(filePath))
                {
                    Debug.WriteLine(string.Format("Cannot find the file: '{0}'", filePath));
                    return string.Empty;
                }
    
                string content;
                using (StreamReader reader = new StreamReader(filePath))
                {
                    content = reader.ReadToEnd();
                    reader.Close();
                }
                return content;
            }
    
  8. 다음 코드를 추가하여 IModelElement를 입력 매개 변수로 사용하고 String을 사용하여 파일 이름을 검색하는 GetElementSourceFile 메서드를 만듭니다. 이 메서드는 IModelElement를 IScriptSourcedModelElement로 캐스팅한 다음 ISourceInformation을 사용하여 모델 요소에서 스크립트 파일 경로를 확인합니다.

            /// <summary>
            /// Get the corresponding script file path from a model element.
            /// </summary>
            /// <param name="element">model element</param>
            /// <param name="fileName">file path of the scripts corresponding to the model element</param>
            /// <returns></returns>
            private static Boolean GetElementSourceFile(IModelElement element, out String fileName)
            {
                fileName = null;
    
                IScriptSourcedModelElement scriptSourcedElement = element as IScriptSourcedModelElement;
                if (scriptSourcedElement != null)
                {
                    ISourceInformation elementSource = scriptSourcedElement.PrimarySource;
                    if (elementSource != null)
                    {
                        fileName = elementSource.SourceName;
                    }
                }
    
                return String.IsNullOrEmpty(fileName) == false;
            }
    
  9. 다음 코드를 추가하여 ComputeLineColumn 메서드를 만듭니다.

            /// This method converts offset from ScriptDom to line\column in script files.
            /// A line is defined as a sequence of characters followed by a carriage return ("\r"), 
            /// a line feed ("\n"), or a carriage return immediately followed by a line feed. 
            public static bool ComputeLineColumn(string text, Int32 offset, Int32 length,
                                                out Int32 startLine, out Int32 startColumn, out Int32 endLine, out Int32 endColumn)
            {
                const char LF = '\n';
                const char CR = '\r';
    
                // Setting the initial value of line and column to 0 since VS auto-increments by 1.
                startLine = 0;
                startColumn = 0;
                endLine = 0;
                endColumn = 0;
    
                int textLength = text.Length;
    
                if (offset < 0 || length < 0 || offset + length > textLength)
                {
                    return false;
                }
    
                for (int charIndex = 0; charIndex < length + offset; ++charIndex)
                {
                    char currentChar = text[charIndex];
                    Boolean afterOffset = charIndex >= offset;
                    if (currentChar == LF)
                    {
                        ++endLine;
                        endColumn = 0;
                        if (afterOffset == false)
                        {
                            ++startLine;
                            startColumn = 0;
                        }
                    }
                    else if (currentChar == CR)
                    {
                        // CR/LF combination, consuming LF.
                        if ((charIndex + 1 < textLength) && (text[charIndex + 1] == LF))
                        {
                            ++charIndex;
                        }
    
                        ++endLine;
                        endColumn = 0;
                        if (afterOffset == false)
                        {
                            ++startLine;
                            startColumn = 0;
                        }
                    }
                    else
                    {
                        ++endColumn;
                        if (afterOffset == false)
                        {
                            ++startColumn;
                        }
                    }
                }
    
                return true;
            }
    
  10. 다음 코드를 추가하여 DataRuleProblem을 입력 매개 변수로 사용하는 UpdateProblemPosition 메서드를 만듭니다.

            /// <summary>
            /// Compute the start Line/Col and the end Line/Col to update problem info
            /// </summary>
            /// <param name="problem">problem found</param>
            /// <param name="offset">offset of the fragment having problem</param>
            /// <param name="length">length of the fragment having problem</param>
            public static void UpdateProblemPosition(DataRuleProblem problem, int offset, int length)
            {
                if (problem.ModelElement != null)
                {
                    String fileName = null;
                    int startLine = 0;
                    int startColumn = 0;
                    int endLine = 0;
                    int endColumn = 0;
    
                    bool ret = GetElementSourceFile(problem.ModelElement, out fileName);
                    if (ret)
                    {
                        string fullScript = ReadFileContent(fileName);
    
                        if (fullScript != null)
                        {
                            if (ComputeLineColumn(fullScript, offset, length, out startLine, out startColumn, out endLine, out endColumn))
                            {
                                problem.FileName = fileName;
                                problem.StartLine = startLine + 1;
                                problem.StartColumn = startColumn + 1;
                                problem.EndLine = endLine + 1;
                                problem.EndColumn = endColumn + 1;
                            }
                            else
                            {
                                Debug.WriteLine("Could not compute line and column");
                            }
                        }
                    }
                }
            }
    
  11. 파일 메뉴에서 저장을 클릭합니다.

다음으로, 규칙 이름, 규칙 설명, 그리고 규칙 구성 인터페이스에서 해당 규칙이 표시될 범주를 정의할 리소스 파일을 추가합니다.

리소스 파일 및 세 개의 리소스 문자열을 추가하려면

  1. 솔루션 탐색기에서 SampleRules 프로젝트를 선택합니다.

  2. 프로젝트 메뉴에서 새 항목 추가를 선택합니다.

    새 항목 추가 대화 상자가 나타납니다.

  3. 설치된 템플릿 목록에서 일반을 클릭합니다.

  4. 세부 정보 창에서 리소스 파일을 클릭합니다.

  5. 이름에 SampleRuleResource.resx를 입력합니다.

    리소스 편집기가 나타나지만 아직 리소스는 정의되어 있지 않습니다.

  6. 다음과 같이 세 개의 리소스 문자열을 정의합니다.

    Name

    AvoidWaitForDelay_ProblemDescription

    WAITFOR DELAY statement was found in {0}.

    AvoidWaitForDelay_RuleName

    Avoid using WaitFor Delay statements in stored procedures, functions and triggers.

    CategorySamples

    SamplesCategory

  7. 파일 메뉴에서 SampleRuleResource.resx 저장을 클릭합니다.

다음으로, 이 리소스 파일의 리소스 중 Visual Studio에서 해당 규칙에 대한 정보를 사용자 인터페이스에 표시하는 데 사용되는 리소스를 참조하는 클래스를 정의합니다.

SampleConstants 클래스를 정의하려면

  1. 솔루션 탐색기에서 SampleRules 프로젝트를 선택합니다.

  2. 프로젝트 메뉴에서 클래스 추가를 선택합니다.

    새 항목 추가 대화 상자가 나타납니다.

  3. 이름 텍스트 상자에 SampleRuleConstants.cs를 입력한 다음 추가 단추를 클릭합니다.

    솔루션 탐색기의 프로젝트에 SampleRuleConstants.cs 파일이 추가됩니다.

  4. SampleRuleConstants.cs 파일을 열고 다음 using 문을 파일에 추가합니다.

    namespace SampleRules
    {
        internal class SampleConstants
        {
            public const string NameSpace = "SamplesRules";
            public const string ResourceBaseName = "SampleRules.SampleRuleResource";
            public const string CategorySamples = "CategorySamples";
    
            public const string AvoidWaitForDelayRuleId = "SR1004";
            public const string AvoidWaitForDelay_RuleName = "AvoidWaitForDelay_RuleName";
            public const string AvoidWaitForDelay_ProblemDescription = "AvoidWaitForDelay_ProblemDescription";
        }
    }
    
  5. 파일 메뉴에서 저장을 클릭합니다.

사용자 지정 코드 분석 규칙 클래스 만들기

이제 사용자 지정 코드 분석 규칙에 사용할 도우미 클래스를 추가했으므로 사용자 지정 규칙 클래스를 만들고 이름을 AvoidWaitForDelayRule로 지정할 것입니다. AvoidWaitForDelayRule 사용자 지정 규칙은 데이터베이스 개발자가 저장 프로시저, 트리거 및 함수에서 WAITFOR DELAY 문을 방지하는 데 유용합니다.

AvoidWaitForDelayRule 클래스를 만들려면

  1. 솔루션 탐색기에서 SampleRules 프로젝트를 선택합니다.

  2. 프로젝트 메뉴에서 새 폴더를 선택합니다.

  3. 솔루션 탐색기에 새 폴더가 표시됩니다. 폴더 이름을 AvoidWaitForDelayRule로 지정합니다.

  4. 솔루션 탐색기에서 AvoidWaitForDelayRule 폴더가 선택되었는지 확인합니다.

  5. 프로젝트 메뉴에서 클래스 추가를 선택합니다.

    새 항목 추가 대화 상자가 나타납니다.

  6. 이름 텍스트 상자에 AvoidWaitForDelayRule.cs를 입력한 다음 추가 단추를 클릭합니다.

    솔루션 탐색기에서 프로젝트에 AvoidWaitForDelayRule 폴더에 AvoidWaitForDelayRule.cs 파일이 추가됩니다.

  7. AvoidWaitForDelayRule.cs 파일을 열고 다음 using 문을 파일에 추가합니다.

    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;
    using Microsoft.Data.Schema.Extensibility;
    using Microsoft.Data.Schema.SchemaModel;
    using Microsoft.Data.Schema.ScriptDom.Sql;
    using Microsoft.Data.Schema.Sql.SchemaModel;
    using Microsoft.Data.Schema.Sql;
    using Microsoft.Data.Schema.StaticCodeAnalysis;
    namespace SampleRules
    {
        public class AvoidWaitForDelayRule
        {
        }
    }
    

    참고

    SampleRules.AvoidWaitForDelayRule에서 SampleRules로 네임스페이스 이름을 변경해야 합니다.

  8. AvoidWaitForDelayRule 클래스 선언에서 액세스 한정자를 public으로 변경합니다.

        /// <summary>
        /// This is a SQL rule which returns a warning message 
        /// whenever there is a WAITFOR DELAY statement appears inside a subroutine body. 
        /// This rule only applies to SQL stored procedures, functions and triggers.
        /// </summary>
        public class AvoidWaitForDelayRule
    
  9. StaticCodeAnalysisRule 기본 클래스에서 AvoidWaitForDelayRule 클래스를 파생시킵니다.

        public class AvoidWaitForDelayRule : StaticCodeAnalysisRule
    
  10. 클래스에 DatabaseSchemaProviderCompatibilityAttribute, DataRuleAttributeSupportedElementTypeAttribute를 추가합니다. 기능 확장 호환성 특성에 대한 자세한 내용은 Visual Studio의 데이터베이스 기능 확장을 참조하십시오.

        [DatabaseSchemaProviderCompatibility(typeof(SqlDatabaseSchemaProvider))]
        [DataRuleAttribute(
            SampleConstants.NameSpace,
            SampleConstants.AvoidWaitForDelayRuleId,
            SampleConstants.ResourceBaseName,
            SampleConstants.AvoidWaitForDelay_RuleName,
            SampleConstants.CategorySamples,
            DescriptionResourceId = SampleConstants.AvoidWaitForDelay_ProblemDescription)]
        [SupportedElementType(typeof(ISqlProcedure))]
        [SupportedElementType(typeof(ISqlTrigger))]
        [SupportedElementType(typeof(ISqlFunction))]
        public class AvoidWaitForDelayRule : StaticCodeAnalysisRule
    

    DataRuleAttribute는 데이터베이스 코드 분석 규칙을 구성할 때 Visual Studio에 표시되는 정보를 지정합니다. SupportedElementTypeAttribute는 이 규칙이 적용될 요소의 형식을 정의합니다. 이 경우에는 저장 프로시저, 트리거 및 함수에 규칙이 적용됩니다.

  11. DataRuleSettingDataRuleExecutionContext를 입력 매개 변수로 사용하는 Analyze 메서드에 대한 재정의를 추가합니다. 이 메서드는 잠재적 문제 목록을 반환합니다.

    이 메서드는 컨텍스트 매개 변수에서 IModelElementTSqlFragment를 가져옵니다. SqlSchemaModelISqlModelElement는 모델 요소에서 가져옵니다. 그런 다음 WaitForDelayVisitor 클래스가 사용되어 모델의 모든 WAITFOR DELAY 문이 들어 있는 목록을 가져옵니다.

    이 목록의 각 WaitForStatement에 대해 DataRuleProblem이 만들어집니다.

            #region Overrides
            /// <summary>
            /// Analyze the model element
            /// </summary>
            public override IList<DataRuleProblem> Analyze(DataRuleSetting ruleSetting, DataRuleExecutionContext context)
            {
                List<DataRuleProblem> problems = new List<DataRuleProblem>();
    
                IModelElement modelElement = context.ModelElement;
    
                // this rule does not apply to inline table-valued function
                // we simply do not return any problem
                if (modelElement is ISqlInlineTableValuedFunction)
                {
                    return problems;
                }
    
                // casting to SQL specific 
                SqlSchemaModel sqlSchemaModel = modelElement.Model as SqlSchemaModel;
                Debug.Assert(sqlSchemaModel!=null, "SqlSchemaModel is expected");
    
                ISqlModelElement sqlElement = modelElement as ISqlModelElement;
                Debug.Assert(sqlElement != null, "ISqlModelElement is expected");
    
                // Get ScriptDom for this model element
                TSqlFragment sqlFragment = context.ScriptFragment as TSqlFragment;
                Debug.Assert(sqlFragment != null, "TSqlFragment is expected");
    
                // visitor to get the ocurrences of WAITFOR DELAY statements
                WaitForDelayVisitor visitor = new WaitForDelayVisitor();
                sqlFragment.Accept(visitor);
                List<WaitForStatement> waitforDelayStatements = visitor.WaitForDelayStatements;
    
                // Create problems for each WAITFOR DELAY statement found 
                foreach (WaitForStatement waitForStatement in waitforDelayStatements)
                {
                    DataRuleProblem problem = new DataRuleProblem(this,
                                                String.Format(CultureInfo.CurrentCulture, this.RuleProperties.Description, SqlRuleUtils.GetElementName(sqlSchemaModel, sqlElement)),
                                                sqlElement);
    
                    SqlRuleUtils.UpdateProblemPosition(problem, waitForStatement.StartOffset, waitForStatement.FragmentLength);
                    problems.Add(problem);
                }
    
                return problems;
            }
    
            #endregion    
    
    
  12. 파일 메뉴에서 저장을 클릭합니다.

다음으로, 프로젝트를 빌드합니다.

프로젝트를 빌드하려면

  • 빌드 메뉴에서 솔루션 빌드를 클릭합니다.

다음으로, 프로젝트에서 생성된 버전, 문화권, PublicKeyToken 등의 어셈블리 정보를 수집합니다.

어셈블리 정보를 수집하려면

  1. 보기 메뉴에서 다른 창, 명령 창을 차례로 클릭하여 명령 창을 엽니다.

  2. 명령 창에서 다음 코드를 입력합니다. FilePath 대신 컴파일된 .dll 파일의 경로 및 파일 이름을 입력합니다. 이때 경로 및 파일 이름을 따옴표로 묶습니다.

    참고

    기본적으로 FilePath는 Projects\SampleRules\SampleRules\bin\Debug\YourDLL 또는 Projects\SampleRules\SampleRules\bin\Release\YourDLL입니다.

    ? System.Reflection.Assembly.LoadFrom(@"FilePath")
    
  3. Enter 키를 누릅니다. 이 줄은 특정 PublicKeyToken이 포함된 다음과 유사합니다.

    "SampleRules, Version=1.0.0.0, Culture=neutral, PublicKeyToken=nnnnnnnnnnnnnnnn"
    

    이 어셈블리 정보를 적어 두거나 복사합니다. 이 정보는 다음 절차에서 사용됩니다.

다음으로, 이전 절차에서 수집한 어셈블리 정보를 사용하여 XML 파일을 만듭니다.

XML 파일을 만들려면

  1. 솔루션 탐색기에서 SampleRules 프로젝트를 선택합니다.

  2. 프로젝트 메뉴에서 새 항목 추가를 선택합니다.

  3. 템플릿 창에서 XML 파일 항목을 찾아 선택합니다.

  4. 이름 텍스트 상자에 SampleRules.Extensions.xml을 입력한 다음 추가 단추를 클릭합니다.

    솔루션 탐색기의 프로젝트에 SampleRules.Extensions.xml 파일이 추가됩니다.

  5. SampleRules.Extensions.xml 파일을 열고 다음 XML과 일치하도록 업데이트합니다. 버전, 문화권 및 PublicKeyToken 값을 이전 절차에서 검색한 값으로 바꿉니다.

    <?xml version="1.0" encoding="utf-8"?>
    <extensions assembly=""
                version="1" xmlns="urn:Microsoft.Data.Schema.Extensions"
                xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                xsi:schemaLocation="urn:Microsoft.Data.Schema.Extensions Microsoft.Data.Schema.Extensions.xsd">
    
      <extension type="SampleRules.AvoidWaitForDelayRule" assembly="SampleRules, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b4deb9b383d021b0" enabled="true"/>
    </extensions> 
    
  6. 파일 메뉴에서 저장을 클릭합니다.

다음으로, 어셈블리 정보와 XML 파일을 Extensions 디렉터리에 복사합니다. Visual Studio는 시작 시 Microsoft Visual Studio 10.0\VSTSDB\Extensions 디렉터리 및 하위 디렉터리에 있는 모든 확장을 확인하여 세션에서 사용할 수 있도록 등록합니다.

어셈블리 정보와 XML 파일을 Extensions 디렉터리에 복사하려면

  1. Microsoft Visual Studio 10.0\VSTSDB\Extensions\ 디렉터리에 CustomRules라는 새 폴더를 만듭니다.

  2. Projects\SampleRules\SampleRules\bin\Debug\ 디렉터리의 SampleRules.dll 어셈블리 파일을 사용자가 만든 Microsoft Visual Studio 10.0\VSTSDB\Extensions\CustomRules 디렉터리에 복사합니다.

  3. Projects\SampleRules\SampleRules\ 디렉터리의 SampleRules.Extensions.xml 어셈블리 파일을 사용자가 만든 Microsoft Visual Studio 10.0\VSTSDB\Extensions\CustomRules 디렉터리에 복사합니다.

    참고

    Microsoft Visual Studio 10.0\VSTSDB\Extensions 디렉터리의 폴더에 확장 어셈블리를 저장하는 것이 좋습니다. 이렇게 하면 제품에 포함된 확장과 사용자 지정 확장을 식별하는 데 도움이 됩니다. 확장을 특정 범주로 구성하는 데 폴더를 사용하는 것도 좋습니다.

다음으로, 새 Visual Studio 세션을 시작하고 데이터베이스 프로젝트를 만듭니다.

새 Visual Studio 세션을 시작하고 데이터베이스 프로젝트를 만들려면

  1. 두 번째 Visual Studio 세션을 시작합니다.

  2. 파일 메뉴에서 새로 만들기를 클릭한 다음 프로젝트를 클릭합니다.

  3. 새 프로젝트 대화 상자의 설치된 템플릿 목록에서 데이터베이스 프로젝트 노드를 확장하고 SQL Server를 클릭합니다.

  4. 세부 정보 창에서 SQL Server 2008 데이터베이스 프로젝트를 선택합니다.

  5. 이름 텍스트 상자에 SampleRulesDB를 입력한 다음 확인을 클릭합니다.

마지막으로, 새 규칙이 SQL Server 프로젝트에 표시되는 것을 확인합니다.

새 AvoidWaitForRule 코드 분석 규칙을 보려면

  1. 솔루션 탐색기에서 SampleRulesDB 프로젝트를 선택합니다.

  2. 프로젝트 메뉴에서 속성을 선택합니다.

    SampleRulesDB 속성 페이지가 표시됩니다.

  3. 코드 분석을 클릭합니다.

    CategorySamples라는 새 범주가 표시됩니다.

  4. CategorySamples를 확장합니다.

    **SR1004: 저장 프로시저, 트리거 및 함수에서 WAITFOR DELAY 문을 방지합니다.**가 표시됩니다.

참고 항목

작업

방법: 기능 확장 등록 및 관리

방법: 팀 멤버에게 사용자 지정 기능 확장 배포

참조

ISqlProcedure

ISqlTrigger

ISqlFunction

ISqlInlineTableValuedFunction

개념

Visual Studio의 데이터베이스 기능 확장

데이터베이스 코드를 분석하여 코드 품질 향상

코드 분석을 사용하여 관리 코드 품질 분석