きよくらの備忘録

「三日坊主と呼ばせない!日記」改め。主にソフトウェア開発関連の話題。

SQL Server Data Toolsのユニットテスト実行前に複数DBにデプロイする

SQL Server Data Tools (SSDT)のユニットテスト機能では、テスト実行前にソリューション内のデータベースプロジェクトをテスト実行対象のデータベースに自動でデプロイしてくれる機能があります。

これは非常に便利な機能です。しかし、複数のデータベースにまたがるような開発していると、依存関係があるなどの理由で複数のデータベースプロジェクトの内容をデプロイしたいことが出てきたりします。

SSDTの設定を調べて見ましたがそういった機能は用意されていなさそうで、一旦は諦めていました。が、別件で思案してたところでふと思いついたことを試してみた……ら、なんとか実現できなのでメモしておきます。

 

SSDTがユニットテスト実行前にデプロイしている仕組み

まず、SSDTがユニットテスト実行前にどうやってデプロイしているかを見てみます。

SSDTで作成されるテストプロジェクトでは、テストが実行されるとまずSqlDatabaseSetupクラスInitializeAssemblyメソッドが呼ばれます。 このメソッドはMsTest(Microsoft.VisualStudio.QualityTools.UnitTestFrameworkアセンブリ)のAssemblyInitialize属性がついた属性です。

この中で実行されているの処理は二つ。 そのうちのSqlDatabaseTestClass.TestService.DeployDatabaseProject();がデプロイ処理であることは名前からして疑う余地はなさそうです。

f:id:kiyokura:20161213232318p:plain

この処理が実装されているMicrosoft.Data.Tools.Schema.Sql.UnitTestingアセンブリのソースは公開されていませんので具体的にどのような処理をしているのかはわかりませんが、MSDNには一応載っていました。

SqlDatabaseTestService.DeployDatabaseProject Method

この DeployDatabaseProjectメソッドは、上記のMSDN

Deploys the database project by using the settings of the user in the app.config file.

と記載されている通り、app.confgのSqlUnitTestingセクションに記載された設定に従ってDBをデプロイします。この記載内容は、テストプロジェクト作成時や「SQL Server テスト構成」のダイアログで設定する内容です。

f:id:kiyokura:20161213232418p:plain

 

複数のDB・プロジェクトをデプロイする方法(強引)

追記:もっと適切だと思う方法がありましたので、ぜひそちらを参照してください kiyokura.hateblo.jp

SSDTが生成するユニットテストプロジェクトで自動デプロイが行われている仕組みをもう一度整理すると、こういうことです。

  • AssemblyInitialize属性の追加メソッド内でDeployDatabaseProjectメソッドでデプロイが実施される
  • DeployDatabaseProjectメソッド`はapp.configの設定に従って処理を行う

 

……ここまでくればピンと来たかもおられるでしょう。 そうです。

app.configを書き換えて DeployDatabaseProjectを呼ぶ

ようにすればいくらでもデプロイできそうじゃありませんか(

 

……ということで、例えば以下のようにapp.configを書き換えて実行してやることで、複数のデータベース/プロジェクトをすんなりデプロイすることができました。

using System;
using System.Configuration;
using Microsoft.Data.Tools.Schema.Sql.UnitTesting;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Xml;

namespace BletillaTestsNext
{
  [TestClass()]
  public class SqlDatabaseSetup
  {
    // ターゲットデータベース
    const string TARGET_DB_PROJECT = "..\\..\\..\\ MainDb\\MainDb.sqlproj";
    const string TARGET_DB_CONNECTION_STRING = "<デプロイ先のDBの接続文字列>";
    
    // 依存データベース
    const string DEPEND_DB_PROJECT = "..\\..\\..\\SubDb\\SubDb.sqlproj";
    const string DEPEND_DB_CONNECTION_STRING = "<デプロイ先のDBの接続文字列> ";

    [AssemblyInitialize()]
    public static void InitializeAssembly(TestContext ctx)
    {
      // テスト実行ターゲットをデプロイ
      RewriteConfig(TARGET_DB_PROJECT, TARGET_DB_CONNECTION_STRING);
      SqlDatabaseTestClass.TestService.DeployDatabaseProject();
 
      // 依存DBをデプロイ
      RewriteConfig(DEPEND_DB_PROJECT, DEPEND_DB_CONNECTION_STRING);
      SqlDatabaseTestClass.TestService.DeployDatabaseProject();
 
      // テスト実行用に元に戻しておく
      RewriteConfig(TARGET_DB_PROJECT, TARGET_DB_CONNECTION_STRING);


      SqlDatabaseTestClass.TestService.GenerateData();
    }
    
    private static void RewriteConfig(string projectFile, string connectionString)
    {
      // デプロイは特権コンテキスト(PrivilegedContext)で行われるのでそちらだけ書き換えればよい
      var xmlDoc = new XmlDocument();
      xmlDoc.Load(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
      xmlDoc.SelectSingleNode("//SqlUnitTesting/DatabaseDeployment").Attributes["DatabaseProjectFileName"].Value = projectFile;
      xmlDoc.SelectSingleNode("//SqlUnitTesting/PrivilegedContext").Attributes["ConnectionString"].Value = connectionString;
      xmlDoc.Save(AppDomain.CurrentDomain.SetupInformation.ConfigurationFile);
      ConfigurationManager.RefreshSection("SqlUnitTesting");
    }
  }
}

見てのとおり、app.configを読み込んで、

  • SqlUnitTesting/DatabaseDeploymentノードDatabaseProjectFileName属性に対象のプロジェクトファイルを
  • SqlUnitTesting/PrivilegedContextノードConnectionString属性にでデプロイ先のプロジェクトファイルを

書き込んで反映、念のためリフレッシュしています。

なお、SqlUnitTestingセクションで接続文字列を宣言してる箇所としてPrivilegedContextとExecutionContextの二つがありますが、この最初のでデプロイで利用されるのはPrivilegedContextですのでそこは間違えないようにする必要があります。 またプロジェクトファイルのパスは、このテストプロジェクトのアセンブリ出力パス(bin\Debug)からの相対パスで指定しています。

そのほかこの例ではプロジェクトのパスや接続文字列を直書きしてますが、実際にはapp.configにAppSettingsセクションを追加したりして管理するといいかもしれません。

 

まとめ

多少強引感もありますが、割とすんなり動いてる感があります。というか標準で複数デプロイ先へのデプロイに標準で対応してくれればもっと嬉しいのですが:p

オープンソースカンファレンス2016広島でASP.NET Coreについてお話しさせていただきました

ぼやぼやしている間にずいぶんマが空いてしまったのですが、11/27(日)に開催されたオープンソースカンファレンス 2016 Hiroshimaにて、ASP.NET Core on Linuxのタイトルでお話しさせていただきました。

 

セッション資料はこちらです。

資料にも明記していますが、開発環境と実行環境という環境面(とデプロイについて)について、Linuxを実行環境としたデモを中心にしてお話しさせていただきました。 当日、実際に配置して実行した(手元のWebサーバからアクセスした)のは、クラウド上のLinuxUbuntu)でした。

Windows上のVisual Studio Codeで開発し、そのままWindows上でUbuntu用のELF形式の実行ファイルの形でビルドしてサーバ上に転送、実行というデモもやらせていただきました。

ASP.NET Coreのプログラミンよりの部分についてはほぼ(というか全く)触れれませんでしたが、実際に触ってみようと思われた方は、ぜひ以下のオフィシャルのチュートリアルやセッション中でも紹介した書籍などを参考されるとよいのではないかと思います。

ASP.NET MVCプログラミング入門 (マイクロソフト関連書)

ASP.NET MVCプログラミング入門 (マイクロソフト関連書)

 

告知:ASP.NET Core on Macやります

今週末、 12/17(土)に開催される 合同勉強会 in 大都会岡山 -2016 Winter-にて、Macでの開発のデモをやってみる予定です。 Visual Studio Code, Visual Studio for Mac, Riderあたりでそれぞれデモをやってみようかなと思っています。

時間の都合上、デプロイ周りとか細かな説明はおそらく出来ないので、そのあたり興味あるかたは前述の資料をご覧いただくか、当日個別に捕まえて聞いていただければと思います。

DapperのQuery<dynamic>()の結果セットのフィールド名を取得する

ちょっと必要があったのでメモ。

 

Querydynamic()>が返すdynamicの実体はDapper.SqlMapper.DapperRowのコレクション

Query<dynamic()>()が返すdynamicの実体はDapper.SqlMapper.DapperRowのコレクションです。

f:id:kiyokura:20161209130932p:plain

 

このDapperRowはDapperのDapper.SqlMapperのprivateな型ですが、以下の通りIDictionary<string, object> の実装です。

github.com

 

ということで素直にIDictionary<string, object>にキャストしてみます。

  // SQLは実際にはSELECT * とか結果セット戻すストアドとか
  var result = cn.Query("SELECT 1 AS Id, 'Taro' AS Name , 20 AS Age"); 
  var fieldList = ((IDictionary<string, object>)result.First())
                    .Select(x => x.Key)
                    .ToList();

 

こんな感じで取れました。 f:id:kiyokura:20161209130950p:plain

 

どこでつかうん?

『どこでそんなもの使うの?』とか思う向きもかもしれないですが、クエリが返すフィールド名をハードコーディングしたくないケースって意外とあるというか、まあそんな感じで。 (例えばプログラム部分が『土管』に徹する場合(DB→JSONtとかDB→Excelとか)等だと、両端の柔軟性を生かす事ができると思います。というか、今回やりたいケースがまさにそれでした。)

Visual Studio Team Serviceで別のチームプロジェクトにリポジトリをforkして運用するメモ

Visual Studio Team Service(以下VSTS)で 別のチームプロジェクトにリポジトリをforkして運用してみよう と試行錯誤中です。とりあえず今やり始めたことをメモがてら。

 

実現したいこと

実現したいのはgithubでよくあるような『手元で修正してpull requestを送るためのfork』では無く。どちらかと逆で。『forkしてカスタマイズしたソースに、適宜分岐元の修正やバージョンアップを取り込む』という運用です。

有体に言うと、

  • パッケージ販売するソリューションを開発していて
  • 顧客後のカスタマイズが発生した場合はフォークしたプロジェクトで開発
  • フォーク先は標準パッケージのバージョンアップや修正も適宜取り込む

ということをやりたい。

リポジトリの話だけではなく、VSTSその他の機能(WorkItem関連とかCI系の機能とかビルドサービスとか)もベースの開発プロジェクトとは分離さているほうが望ましいという事情もあって。で、今回はこういうのがうまくできないか試してみようとしているという次第です。

 

私が知る限り2016/12/06現在はVSTSにはこういった簡単にリポジトリをforkできるような機能がない(はず)です。しかし所詮リポジトリはgitですのでremoteでフォーク元を追跡すればどうにもでできるはず。少しググると、割と似たようなことをVSTS(当時はVSO)やってている記事を見つけたので、参考にさせていただきながらやってみました。

www.woodcp.com

 

注意:

これから紹介する内容は、実際に私が実務で「これから本格的に利用しよう」と思ってまずは実験的に作ってみた構成のメモです。 ほぼこのまま実務で利用しようとしてはいますが、まだ本格的に使っているわけではないので、気が付いていない不味いことや問題点などがあることは十分に考えられます。お気づきの点があればぜひ、教えていただけると本当にうれしいです。

続きを読む

Visual Studio Code で ASP.NET Coreをデバッグ実行する(Win/Ubuntu/Mac)

表題のとおりです。 オフィシャルのドキュメントもあるので基本は悩むところないと思うのですが、現時点ではWindows環境のみproject.jsonに追記しないとうまくいかない点があります(そこでちょっと悩んだ)。

 

オフィシャルのドキュメントはこちら: Your First ASP.NET Core Application on a Mac Using Visual Studio Code | Microsoft Docs

 

上記ドキュメントはMacについて書かれていますが、SDKとnode.js、VSCodeのインストール方法が違うだけで、そこから先は大体同じだと思います。 取り急ぎ、WindowsUbuntu Desktopでは以下の手順でステップ実行できるところまでは確認しました。macは自分では試してないですが、そもそも参照してるドキュメントがmacようなのでmacでできない事は流石にないと信じています:p。

下はUbuntu Desktopでのデバッグ実行の様子。 f:id:kiyokura:20161125005037p:plain

 

必要なもの

必要なものは以下

  1. .NET Core SDK
  2. Visual Studio Code
  3. C# for Visual Studio Code (Visual Studio Code の Extension)
  4. Node.js
  5. yeoman(npm)
  6. bower(npm)
  7. generetor-aspnet(npm)

 

インストール方法

以下、入れていきます。

 

.NET Core SDK

オフィシャルサイトを参考に、各環境用のSDKをインストールします

.NET Core installation guide

全体的に丁寧な Step-by-step instructions になっていますので、迷うことはないと思います。 Windowsの場合は、[Select your environment]-[Command Line / Other]が該当します。

 

Visual Studio Code

こちらもオフィシャルサイトを参考に、各環境向けのガイドを見ながらインストールします。

Download Visual Studio Code

 

C# for Visual Studio Code

Visual Studio Code の C#拡張機能をインストールしておきます。 コード補完などの他、デバッグに関する機能などのあるので事実上必須です。

C# for Visual Studio Code (powered by OmniSharp)

インストール方法は上記サイトにもありますが、Visual Studio Codeのコマンドパレットで ext install csharp で入ります。

 

Node.js

次にNode.jsです。後述するYeomanを使ってプロジェクトのひな型を作るのにも使いますが、タスクランナーやbowerを動かすためにも必要なので、Yeomanは使わないとしても、事実上はほぼ必須なんじゃないでしょうか。 インストール方法はいろいろあると思います。

下記のオフィシャルサイトからバイナリを取得するなり、各ディストリビューションのパッケージ管理システムなどからインストールするなりしてください*1https://nodejs.org/

 

npmパッケージ類

Yeoman、Bower、generetor-aspnetをnpmでインストールします。 Yeomanはプロジェクトの雛型を生成するエンジンで、generator-aspnetはYeomanのASP.NET Coreのテンプレート生成アドオンです。Bowerは主にJavaScriptCSSなどのクライアントサイドライブラリのパッケージ管理システムです。generetor-aspnet が依存しているので、入れておきましょう。

これらのパッケージは一括でインストール可能です。nodeにパスが通っている個所で以下のコマンドでインストールできます。

npm install -g yo bower generator-aspnet

Linuxの場合、 -gオプションでこのあたりのnpmパッケージをインストールするときはsudoしないとエラーになると思います。nvm使うほうがいいんですかね?

 

アプリケーションの生成

generator-aspnetでアプリケーションの雛型を生成します。

 

1. 適当なディレクトリでコマンドラインからyo(Yeoman)を実行

> yo aspnet

初めてYeomanを実行したときは、情報の提供するかどうかみたいな質問が出てくるかもしれません。その場合はお好みでこたえておきましょう。

 

2. テンプレートの種類を選択

Yeomanが起動して、どのテンプレートを利用するか聞いてきます。今回は Web Appkication を選択しましょう。カーソルキーで選択肢を移動し、Enterで確定します。

f:id:kiyokura:20161125005822p:plain

 

3. UIデザインフレームワークを選択

次に、bootstrapかSemantic UIかどちらかを聞いてきます。今回はbootstrapを選びました。

f:id:kiyokura:20161125005832p:plain

 

4. アプリケーション名の入力

最後にアプリケーション名を入れます。任意ですが、今回はSampleAspNetAppとしました。

f:id:kiyokura:20161125005842p:plain

こで、カレントディレクトリ下にSampleAspNetAppディレクトリが作成され、プロジェクトの雛型が展開されます。 以下が表示された完了です。

f:id:kiyokura:20161125005848p:plain

 

Visual Studio Codeによるデバッグ実行

いよいよここからが本番です。 が、ここまで来たらもう、することはほぼ何もないです(^^;

 

プロジェクトを開く

Visual Studio Codeではディレクトリを指定して開くと、そのディレクトリをプロジェクト(ワークスペース)として扱います。Visual Studio Codeを起動してからディレクトリを開いても良いのですが、コマンドラインから起動しても楽です。 作成したプロジェクト のディレクトリに移動して、code .と入力します(「.(どっと)」が重要)。

> cd SampleAspNetApp
> code .

これで、カレントディレクトリを読み込んだ状態でVisual Studio Codeが起動します。

f:id:kiyokura:20161125005859p:plain

起動してしばらくすると、おそらく以下のようなメッセージが出ると思います。これについては後述します。 f:id:kiyokura:20161125005919p:plain

 

デバッグ用ファイルの生成

二つ表示されるメッセージのうち、「警告」となっている Required assets to build and debug are missing from ...のメッセージは、要するに「デバッグ実行に必要なVSCodeの設定ファイル類がないのけど作る?」という確認です。 [Yes]を選択しましょう。

こんな感じで必要なファイルが作成されます。 f:id:kiyokura:20161125005928p:plain

 

プロジェクトのrestore

下側のメッセージは「未解決の依存関係があるからrestoreしてね」ということなので、こちらもやっておきましょう。[Restore]ボタンをクリックすればOKです。ネットワーク越しに必要なものをダウンロードして依存を解決するので、少し時間がかかることがあります。 (事前にコマンドラインdotnet restoreをしている場合は表示されません)

 

シンボルファイルの生成のための設定(Windowsのみ)

Windowsの場合は、デバッグ用のシンボルを生成するproject.jsonに1行だけ設定を追加する必要があります。 詳細は Portable PDBs · OmniSharp/omnisharp-vscode Wiki · GitHub を参照のこと。

かいつまむと、project.json の buildOptionsのセクションに、"debugType": "portable"の記述を追加します。Visual Studio Code上で編集すればインテリセンスも効くので特に難しくないと思います。

  "buildOptions": {
    "debugType": "portable",
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

最初これが分からなくて、Windows環境でブレークポイントに止まらないし、ステップ実行もできないしで少し悩みました……。

 

デバッグ実行

では、デバッグ実行してみます。 事前にHomeController.csのIndexアクションメソッドにブレークポイントを張っておきます。

f:id:kiyokura:20161125010021p:plain

次に、左のナビゲーションからデバッグアイコン(虫みたいなやつ)をクリックしてデバッグ画面に入り、F5キーでデバッグ実行開始です。 f:id:kiyokura:20161125010049p:plain

しばらくするとブラウザが立ち上がりつつ、設定したブレークポイントで止まっているのが確認できます。 f:id:kiyokura:20161125010058p:plain

f:id:kiyokura:20161125010106p:plain

 

まとめ

mac用のチュートリアル記事を見ながらWindowsLinuxで環境を整えて試してみましたが、割とすんなりいきました。 名実ともにクロスプラットフォームと言って良いのではないでしょうか!

*1:ubuntuの場合はapt-getのリポジトリにある奴が激しく古かったりするので、ググって情報を探すとかしたほうがいいような気がします。この一連の手順でこれが一番面倒くさかったような気がします