ASP.NET MVCレッスンD.足場

レッスンの目的。 Scaffoldingを使用してプロトタイププロジェクトを作成する方法を学びます。 リポジトリの構造を定義および修正します。 クラスのシンプルな言語バージョン。 Scaffolderの使用をテストしており、「ガイド」属性を使用しています。 Scaffolderのパラメーター。 コントロール属性の作成。 管理パネルでオブジェクトを作成および管理する完全なサイクル。



Visual Studio 2013の足場T4は適用されません。



足場。 スタート。


このレッスンと次のレッスンでは、何倍も速くアプリケーションを開発するのに役立つものを学びます。 遠くから始めましょう。 最初のサイトを作成したとき、1つまたは別の機能をどのように実装し、アプリケーションで使用できるかを検討しました。 次に、2番目のプロジェクトを取得したときに、機能を改善し始めました。 以前のレッスンで説明した主要なポイントとツールを強調しました。 私は多くの機械的な仕事をしていることに気づき始めました。例えば:









そして、それは本当に退屈だったので、私はしばしばステップの1つでミスをしました-そして、平凡なエラーを修正する必要がありました。 スニペットを作成しましたが、問題の半分しか解決しませんでしたが、データモデル、コントローラー、index.cshtml、edit.cshtmlは解決しませんでした。



そして、スティーブン・サンダーソンの記事「 MvcScaffoldingパッケージでASP.NET MVC 3プロジェクトをスキャフォールド 」を読み火をつけました。 足場は私に完全に適合しましたが、それは私のソリューションのために書かれていませんでした。 そして、勉強を始めました。 T4( Text Template Transformation Toolkit )に基づいており、この構文はテンプレートで使用されますが、 Windows PowerShellはテンプレート前のロジックに使用されます。 実際、PackageManager ConsoleでPowerShellを使用しています(なんとねじれています!)。 Windows PowerShellとT4については、プロジェクトで使用する足場をいくつか作成するために、かなり詳しく説明します。



そのため、PowerGUIをインストールしてPowerShellと連携することが最初に必要です。 VS2010にはPowerShell用のエディターが多数あります。 しかし、私たちはVS2012で作業しており、これまでのところそれほど幸運ではありません。



OK、インストール済み。 t4- http://t4-editor.tangible-engineering.comのエディターのインストールに進みます。 また、現時点では、VS2012の唯一のエディターです。 さて-バックライトがあります



T4


次に、私たちが持っているものを研究します。 T4から始めましょう。 このリンクを使用しました: http : //www.olegsych.com/2007/12/text-template-transformation-toolkit/



新しいプロジェクト、クラスライブラリLesssonProject.T4を作成しましょう。 そして、そこにHelloWorld.ttを追加します。







少し変えましょう:

<#@ template debug="true" hostSpecific="true" #> <#@ output extension=".cs" #> <#@ Assembly Name="System.Core" #> <#@ Assembly Name="System.Windows.Forms" #> <#@ import namespace="System" #> <#@ import namespace="System.IO" #> <#@ import namespace="System.Diagnostics" #> <#@ import namespace="System.Linq" #> <#@ import namespace="System.Collections" #> <#@ import namespace="System.Collections.Generic" #> <# var greeting = "Hello, World!"; #> // This is the output code from your template // you only get syntax-highlighting here - not intellisense namespace MyNameSpace { class MyGeneratedClass { static void main (string[] args) { System.Console.WriteLine("<#= greeting #>"); } } } <#+ // Insert any template procedures here void foo(){} #>
      
      





OK、結果は次のようになります。



 // This is the output code from your template // you only get syntax-highlighting here - not intellisense namespace MyNameSpace { class MyGeneratedClass { static void main (string[] args) { System.Console.WriteLine("Hello, World!"); } } }
      
      







実際、.ttファイルは、TextTransformationを継承する特定のクラスを作成するコードに変換されます。 このコードが実行され、結果ファイルが生成されます。 次のようになります。



 <#@ template language="C#" #> Hello World!
      
      







に変換:

 public class GeneratedTextTransform : Microsoft.VisualStudio.TextTemplating.TextTransformation { public override string TransformText() { this.Write("Hello, World!"); return this.GenerationEnvironment.ToString(); } }
      
      







結果は.csファイルになります。

 Hello World!
      
      







aspxに非常によく似ているブロックとテンプレートの構文を学習します。ブラケット<%%>の代わりに<##>のみが使用されます。 しかし、aspxを勉強しなかったので、





一般に、この知識とReflectionの知識は必要なファイルを生成するのに十分ですが、MvcScaffoldingプロジェクトに移りましょう。



MVCScaffolding


T4Scaffoldingをインストールします。

 PM> Install-Package T4Scaffolding
      
      







LessonProject.ModelにCodeTemplates / Scaffolders / IRepositoryフォルダーを作成し、その中にIRepository.ps1ファイル(LessonProject.Model / CodeTemplates / Scaffolders / IRepository / IRepository.ps1)を追加します。

 [T4Scaffolding.Scaffolder(Description = "Create IRepository interface")][CmdletBinding()] param( [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)][string]$ModelType, [string]$Project, [string]$CodeLanguage, [string[]]$TemplateFolders, [switch]$Force = $false ) $foundModelType = Get-ProjectType $ModelType -Project $Project -BlockUi if (!$foundModelType) { return } # Find the IRepository interface, or create it via a template if not already present $foundIRepositoryType = Get-ProjectType IRepository -Project $Project -AllowMultiple if(!$foundIRepositoryType) { #Create IRepository $outputPath = "IRepository" $defaultNamespace = (Get-Project $Project).Properties.Item("DefaultNamespace").Value Add-ProjectItemViaTemplate $outputPath -Template IRepositoryTemplate ` -Model @{ Namespace = $defaultNamespace } ` -SuccessMessage "Added IRepository at {0}" ` -TemplateFolders $TemplateFolders -Project $Project -CodeLanguage $CodeLanguage -Force:$Force $foundIRepositoryType = Get-ProjectType IRepository -Project $Project } # Add a new property on the DbContext class if ($foundIRepositoryType) { $propertyName = $foundModelType.Name $propertyNames = Get-PluralizedWord $propertyName # This *is* a DbContext, so we can freely add a new property if there isn't already one for this model Add-ClassMemberViaTemplate -Name $propertyName -CodeClass $foundIRepositoryType -Template IRepositoryItemTemplate -Model @{ EntityType = $foundModelType; EntityTypeNamePluralized = $propertyNames; } -SuccessMessage "Added '$propertyName' to interface '$($foundIRepositoryType.FullName)'" -TemplateFolders $TemplateFolders -Project $Project -CodeLanguage $CodeLanguage } return @{ DbContextType = $foundDbContextType }
      
      







次に、IRepositoryItemTemplate.cs.t4:

 <#@ Template Language="C#" HostSpecific="True" Inherits="DynamicTransform" #> #region <#= ((EnvDTE.CodeType)Model.EntityType).Name #> IQueryable<<#= ((EnvDTE.CodeType)Model.EntityType).Name #>> <#= Model.EntityTypeNamePluralized #> { get; } bool Create<#= ((EnvDTE.CodeType)Model.EntityType).Name #>(<#= ((EnvDTE.CodeType)Model.EntityType).Name #> instance); bool Update<#= ((EnvDTE.CodeType)Model.EntityType).Name #>(<#= ((EnvDTE.CodeType)Model.EntityType).Name #> instance); bool Remove<#=((EnvDTE.CodeType)Model.EntityType).Name #>(int id<#= ((EnvDTE.CodeType)Model.EntityType).Name #>); #endregion  IRepositoryTemplate.cs.t4: <#@ Template Language="C#" HostSpecific="True" Inherits="DynamicTransform" #> <#@ Output Extension="cs" #> using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace <#= Model.Namespace #> { public interface IRepository { IQueryable<T> GetTable<T>() where T : class; } }
      
      







新しいNotifyテーブルを作成します。

お名前 データ型


UserIDint(外部キーからユーザー)

Messagenvarchar(140)

AddedDatedatetime

Isreadedbit







DbContext(LessonProjectDb.dbml)に転送して保存(ctrl-S):





パッケージマネージャーコンソールで、LessonProject.Modelプロジェクトに書き込みます。

 PM> Scaffold IRepository Notify Added 'Notify' to interface 'LessonProject.Model.IRepository'
      
      







やった! すべてが機能します! シンプルでしょ? 何もはっきりしていませんか? OK、IRepository.ps1を順番に見てみましょう。

 [T4Scaffolding.Scaffolder(Description = "Create IRepository interface")][CmdletBinding()] param( [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)][string]$ModelType, [string]$Project, [string]$CodeLanguage, [string[]]$TemplateFolders, [switch]$Force = $false )
      
      





これはscaffolderコード宣言構造です。 $ModelType



は特に注意を払う必要があります-これはクラスの名前です。これはScaffold IRepository Notify



ます。 他のパラメーターは、デフォルトでForceとして、またはデフォルトでProject、CodeLanguageとして知られています。



次に、このクラスを探します(保存しない場合、目的のクラスはまだ書き込まれず、見つかりません)。

 $foundModelType = Get-ProjectType $ModelType -Project $Project -BlockUi if (!$foundModelType) { return }
      
      







クラスが見つかったので、次のパートに進みます。 ファイルIRepository.csを見つけて、存在しない場合は作成します。

 # Find the IRepository interface, or create it via a template if not already present $foundIRepositoryType = Get-ProjectType IRepository -Project $Project -AllowMultiple if(!$foundIRepositoryType) { #Create IRepository $outputPath = "IRepository" $defaultNamespace = (Get-Project $Project).Properties.Item("DefaultNamespace").Value Add-ProjectItemViaTemplate $outputPath -Template IRepositoryTemplate ` -Model @{ Namespace = $defaultNamespace } ` -SuccessMessage "Added IRepository at {0}" ` -TemplateFolders $TemplateFolders -Project $Project -CodeLanguage $CodeLanguage -Force:$Force $foundIRepositoryType = Get-ProjectType IRepository -Project $Project }
      
      







ここでは、必要に応じてIRepositoryTemplate.cs.t4が呼び出され、そこにオブジェクトが転送されます(ビューのように)

 -Model @{ Namespace = $defaultNamespace } `
      
      







defaultNamespaceはプロジェクトプロパティから取得されました

 Get-Project $Project).Properties.Item("DefaultNamespace").Value
      
      







テンプレートでは、これを使用します(CodeTemplates / Scaffolders / IRepository / IRepositoryTemplate.cs.t4):

 namespace <#= Model.Namespace #>
      
      







OK、ファイルが作成(または検出)され、次のステップに進みます。 すべてが適切に生成された場合( $foundIRepositoryType



)、パラメーターを持つIRepositoryItemTemplate



テンプレートに従って、このクラスにいくつかのプロパティを追加します。



 # Add a new property on the DbContext class if ($foundIRepositoryType) { $propertyName = $foundModelType.Name $propertyNames = Get-PluralizedWord $propertyName # This *is* a DbContext, so we can freely add a new property if there isn't already one for this model Add-ClassMemberViaTemplate -Name $propertyName -CodeClass $foundIRepositoryType -Template IRepositoryItemTemplate -Model @{ EntityType = $foundModelType; EntityTypeNamePluralized = $propertyNames; } -SuccessMessage "Added '$propertyName' to interface '$($foundIRepositoryType.FullName)'" -TemplateFolders $TemplateFolders -Project $Project -CodeLanguage $CodeLanguage }
      
      





パラメータ:

 -Model @{ EntityType = $foundModelType; EntityTypeNamePluralized = $propertyNames; }
      
      







ところで、 Get-PluralizedWord



と、作成されたテンプレートでの役割に注意してください。

  IQueryable<Notify> Notifies { get; }
      
      







つまり スニペットのように文字「s」を追加するだけでなく、通常は複数形を形成します。

これらのT4Scaffoldingコマンドレットを調べてみましょう。





まあ何? プロジェクトのコピーペーストを既に置き換えるパワーを感じますか? しかし(!)これらのコマンドはすべて、人々によっても実装されたことに留意してください。 また、たとえば、フィールドがIDと呼ばれる場合にのみ主キーが受信され、PervichniyKlyuchと呼ばれる場合、ほとんどの場合これは機能しません。 また、翻訳に大きく依存しないでください。 これは足場です。 ドラフトプロジェクトの作成ではなく、最高の設定。 足場の本質は、お茶を作り、始め、飲みに行くことですが、プログラムは自動的に最も厄介な機械的なルーチンを作ります。



再びテンプレート、EnvDTE.CodeType




テンプレートに戻って、EnvDTE.CodeTypeについて学びましょう。

CodeTypeは、Get-ProjectTypeを通じて取得したクラス情報をキャストできるインターフェイスです。

このインターフェイスについて何を知っていますか。 たとえば、プロパティについて:





メソッドはまだありますが、使用していません。

ちなみに、T4ScaffoldingのEnvDTEExtensions.csに注意してください(ソースはここからダウンロードできます: http ://mvcscaffolding.codeplex.com/SourceControl/changeset/view/7cd57d172314)。他の補助クラスを利用できます。

ふう! さて、物事を整理し、プログラムでコードを押しつぶしてから、プログラムを作成してお茶を追いかける方法をコンピューターに説明しましょう。



新しいプロジェクト:LessonProject.Scaffoldingを作成し、最初のレッスンのクラスのペアを、剣と戦士で作成しましょう。

IWeapon.cs:

 public interface IWeapon { void Kill(); }
      
      





Bazuka.cs:

 public class Bazuka : IWeapon { public void Kill() { Console.WriteLine("BIG BADABUM!"); } }
      
      







Sword.cs:

 public class Sword : IWeapon { public void Kill() { Console.WriteLine("Chuk-chuck"); } }
      
      







Warrior.cs:

 /// <summary> /// This is LEGENDARY WARRIOR! /// </summary> public class Warrior { readonly IWeapon Weapon; public Warrior(IWeapon weapon) { this.Weapon = weapon; } public void Kill() { Weapon.Kill(); } }
      
      







T4Scaffoldingをインストールします。

 Install-Package T4Scaffolding
      
      







最も単純なPowerShell(/CodeTemplates/Scaffolders/Details/Details.ps1)を作成します。

 [T4Scaffolding.Scaffolder(Description = "Print Details for class")][CmdletBinding()] param( [parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)][string]$ModelType, [string]$Project, [string]$CodeLanguage, [string[]]$TemplateFolders, [switch]$Force = $false ) $foundModelType = Get-ProjectType $ModelType -Project $Project -BlockUi if (!$foundModelType) { return } $outputPath = Join-Path "Details" $ModelType Add-ProjectItemViaTemplate $outputPath -Template Details ` -Model @{ ModelType = $foundModelType } ` -SuccessMessage "Yippee-ki-yay"` -TemplateFolders $TemplateFolders -Project $Project -CodeLanguage $CodeLanguage -Force:$Force
      
      







指定されたデータ型はDetails.t4(/CodeTemplates/Scaffolders/Details/Details.cs.t4)に渡されます。

 <#@ template language="C#" HostSpecific="True" Inherits="DynamicTransform" debug="true" #> <#@ assembly name="System.Data.Entity" #> <#@ import namespace="System.Linq" #> <#@ import namespace="EnvDTE" #> <#@ Output Extension="txt" #> <# var modelType = (EnvDTE.CodeType)Model.ModelType; #> FullName : <#= modelType.FullName #> Name : <#= modelType.Kind #> <#= modelType.Name #> Access : <#= modelType.Access #> Attributes : <# foreach(var codeElement in modelType.Attributes) { var attr = (EnvDTE.CodeAttribute)codeElement; #> <#= attr.Name #> <# } #> Bases : <# foreach(var codeElement in modelType.Bases) { var @base = (EnvDTE.CodeType)codeElement; #> <#= @base.Name #> <# } #> Comment : <#= modelType.Comment #> DocComment : <#= modelType.DocComment #> StartPoint : Line: <#= ((EnvDTE.TextPoint)modelType.StartPoint).Line #> EndPoint : Line : <#= ((EnvDTE.TextPoint)modelType.EndPoint).Line #> Members : <# foreach(var codeElement in modelType.Members) { var member = (EnvDTE.CodeElement)codeElement; #> <#= member.Kind #> <#= member.Name #> <# } #>
      
      







Warrior.csの派生

 PM> Scaffold Details Warrior -Force:$true Yippee-ki-yay
      
      











クラスを学習し、ガイド属性を使用し、これに基づいて中間クラスを作成できます。 手作業では日常的すぎるプロセスを自動化します。 同時に、人的要因の一部を削除するため、自動生成されたコードのエラーが少ないため、利点があります。



足場の説明


そのため、ここで使用するすべての足場のコードは提供しません。ここでは、起動用のパラメーターのみを説明します。 ただし、最初にManageAttributeについて説明します。 これらの属性は、特定のコードを生成するためのマーカーとして将来使用したいフィールドに割り当てられます。 たとえば、LangColumn属性は、フィールドが「言語」であることを示す属性です。 したがって、ModelViewを生成し、それらを考慮することもできます。





まとめ


足場は万能薬ではありませんが、必要なコードをすばやく作成できる優れたツールです。 記述されたクラスを使用すると、データベースのコンテンツの管理を迅速に開始し、多くの手作業を排除できます。

新しいテーブル(オブジェクト)を作成する手順は次のとおりです。





これがプロジェクトの開始または大規模なパッチである場合、これらはすべて一度に複数のテーブルで実行されます。 最大20〜30個のテーブルを生成することもありましたが、約5分かかりましたが、これがなければ1日を過ごす必要がありました。

足場の実装を見ると、プログラムの内部機能とその構造をよりよく理解できます。



すべてのソースはhttps://bitbucket.org/chernikov/lessonsにあります



All Articles