きよくらの備忘録

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

ExcelとT4 と私とLinq to Excel

本エントリはC# Advent Calendar 2015 の11日目の記事です。

 

Excelからソースコードの自動生成というと何やらSIerめいた感を受ける方もおられるかもしれません。が、例えばExcel形式のデータベース定義などはコトの進め方によって普通にありだと思いますし、『柔軟なスキーマ定義ができ利用者の間口が広い高機能な編集ツールがあり場合によっては印刷や処理の自動化にも様々な方法で対応できるしかもオープンな規格*1のフォーマット』と捉えれば、やはり優秀なフォーマットだと言わざるを得ません(異論は認める)。 (個人的にはgitと親和性の高いdiffとマージを行う手段があれば割と満足というかそこが最大の難点*2

 

まあぶっちゃけそんなことは割とどうでもいい話で、何らかのコンテキストによってExcelからのソースコード自動生成が必要になった/それが最善だと判断したケースがあるとしましょう。きっとありますよ、そういうことも。

 

Excelの内容からコードを自動生成するにはいくつかアプローチがあると思います。 今回はT4からLinq to Excelを使う方法を紹介してみます。

 

Linq to Excel

その名のとおりExcelに対してLINQの文法でクエリを書けるものです。

オフィシャルなリソースはこちらあたりを参照

linqtoexcel - Use LINQ to retrieve data from spreadsheets. - Google Project Hosting

github.com

CSVから読めたり簡単にクラスとマップできたりと色々機能がありますが、そのあたりは割愛しますのでgithub上のreadmeをざざっと読んでもらえればと。

内部的にはJetまたはACEのOLEDBドライバを使ってアクセスしているようです。つまりはADO.NETのラッパー的な。

 

T4からLinq to Excel を使う

さて、ここからが本題です。T4からでもLinq to Excelを使うことも可能です。

T4とはVisual Studioで利用できるテキストテンプレートエンジンです。T4自体についての詳細はこの辺りを参照:コード生成と T4 テキスト テンプレート

 

Linq to Excelのインストール

Linq to ExcelそのものはNuGetでパッケージが提供されているのでパッケージインストーラーから簡単にインストールできます。

> Install-Package LinqToExcel

……できるんですが、現時点(LinqToExcel 1.10.1)では、log4netの参照周りでちょと問題があります。それについては後述。

 

参照の解決

T4からLinq to Excelを使いたい場合、LinqToExcel名前空間のインポートと、以下の依存するアセンブリの参照を行わないと怒られます。

  • System.Data
  • System.Data.DataSetExtensions
  • log4net.dll
  • Remotion.Data.Linq.dll
  • Remotion.Interfaces.dll
  • LinqToExcel.dll

特に下4つのdllの参照をどうするか……ですが、色々考えだすと面倒なので、適当にフォルダを作って必要なdllをすべてコピーしておき……

f:id:kiyokura:20151211222327p:plain

こんな感じで参照してやるほうがもう手っ取り早くて楽でよい気がしています。

f:id:kiyokura:20151211222341p:plain

……ズボラですかね:p

 

LinqToExcelを使ったコード

あとは実際にLinqToExcelを使ったT4を書けばよいだけです。 例えば、以下のようなテーブル定義ちっくなのExcelファイル「Def.xlsx」(シート名:People)があるとして。

項目名 サイズ 和名
Name NVARCHAR 50 氏名
Age INT 年齢
Email NVARCHAR 255 メールアドレス
Salary money 給料

以下のようなT4を書けば…

<#@ template debug ="false" hostspecific="true" language= "C#" #>
<#@ assembly name ="System.Core"  #>
<#@ import namespace ="System.Linq"  #>
<#@ import namespace ="System.Text"  #>
<#@ import namespace ="System.Collections.Generic"  #>
<#@ output extension =".cs" encoding="utf-8" #>

<#@ assembly name ="System.Data"  #>
<#@ assembly name ="System.Data.DataSetExtensions"  #>
<#@ assembly name ="$(ProjectDir)Lib\log4net.dll"  #>
<#@ assembly name ="$(ProjectDir)Lib\Remotion.Data.Linq.dll" #>
<#@ assembly name ="$(ProjectDir)Lib\Remotion.Interfaces.dll" #>
<#@ assembly name ="$(ProjectDir)Lib\LinqToExcel.dll"  #>
<#@ import namespace ="LinqToExcel"  #>
<#
  var xlsxPath = @"C:\Def.xlsx"; // フルパス
  var sheetName = "People";

  using(var excel = new ExcelQueryFactory(xlsxPath)){
    excel.ReadOnly = true;
    var columns =  excel.Worksheet<ColumnDef>(sheetName);
#>
public class People
{
<#
    foreach ( var column in columns){ #>
  /// <summary>
  /// <#= column.和名 #>
  /// </summary>
  public <#= GetType(column.型) #> <#= column.項目名 #> { get; set ; }

<#
    }
#>
}
<#
  }
#>
<#+
  // ここから下は本題じゃないので気にしないで下さい()
  static string GetType(string type){
    switch(type.ToUpper()){
      case "NVARCHAR":
        return "string" ;
      case "INT":
        return "int" ;
      case "MONEY":
        return "decimal" ;
      default:
        // 必要なマッピングは随時追加する雰囲気
        return "string" ;
    }
  }

  class ColumnDef {
    public string 項目名 { get ; set; }
    public string 型 { get ; set; }
    public int? サイズ { get ; set; }
    public string 和名 { get ; set; }
  }
#>

以下のようなC# のコードが自動生成されます。

public class People
{
  /// <summary>
  /// 氏名
  /// </summary>
  public string Name { get ; set; }

  /// <summary>
  /// 年齢
  /// </summary>
  public int Age { get ; set; }

  /// <summary>
  /// メールアドレス
  /// </summary>
  public string Email { get ; set; }

  /// <summary>
  /// 給料
  /// </summary>
  public decimal Salary { get ; set; }

}

……全然LINQのメリットを生かしてないサンプルコードですが、特にマッピングを定義することも無く、シート中の列名っぽいのとメンバ名を合わせたクラスを用意してファイルとシート名を指定して呼び出すだけで、さくっとマッピングして読み込んでくれるあたりは感じ取っていただけるのではないかと思います。

 

エラー対処というかはまりどころというか……について

T4…というよりLinqToExcelを使おうとすると、いくつかはまりどころがあるかもしれません。

 

log4netのバージョンが……

現在、LinqToExcel 1.10.1をNuGetでそのままインストールして利用すると、以下のようなエラーが出ました。

変換を実行しています:System.IO.FileNotFoundExceotion: ファイルまたはアセンブリ'log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a'、またはその依存関係の1つが読み込めませんでした。指定されたファイルが見つかりません。

ファイル名 'log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a' です。'log4net, Version=1.2.13.0, Culture=neutral, PublicKeyToken=669e0ddf0bb1aa2a'

場所 LinqToExcel.ExcelQueryFactory..ctor(String fileName)

......

f:id:kiyokura:20151211222522p:plain

どうやら、LinqToExcelのパッケージがのlog4netの特定の(古い)バージョンに依存しているにもかかわらず、nuspecで最新のlog4netをインストールするように設定されているために起こっている齟齬です*3

とりあえず以下のようにやることで対処は可能です。

  • 一旦LinqToExcelのアンインストール
  • バージョンを指定してlog4netのインストール
  • LinqToExcelのインストール

lg4net 1.2.13はNuGetのパッケージでは2.0.3ですので、こんな感じで入れてしまいましょう。

Install-Package log4net -Version 2.0.3

ひとまずは現時点ではこれで動きました。

 

Microsoft.ACE.OLEDB.12.0' プロバイダーはローカルのコンピューターに登録されていません

別の例外でm

変換を実行しています:System.InvalidOperationException: 'Microsoft.ACE.OLEDB.12.0' プロバイダーはローカルのコンピューターに登録されていません。

場所 System.Data.OleDb.OleDbServicesWrapper.GetDataSource(OleDbConnectionString constr, DataSourceWrapper& datasrcWrapper)

場所 System.Data.OleDb.OleDbConnectionInternal..ctor(OleDbConnectionString constr, OleDbConnection connection)

......

となった場合は、内部的に使っているOLEDBプロバイダがインストールされていません(そのまんま)。これはMS-Officeに付属するものですが、単体でダウンロードしてインストールすることができます*4

Download 2007 Office system ドライバ: データ接続コンポーネント from Official Microsoft Download Center

なお、PCが64bitであっても、32bit版である必要があります*5

 

まとめ

ということで、T4からLinqToExcelを使ってExcel内の情報からコードを自動生成する方法を紹介してみました。

……が、改めてこれを書きながら冷静に見ると結構微妙という気になってきた気がしなくもない……ですが、一度導入してしまえばADO.NETとDapperあたり組み合わせるよりも手数が少なくて済むと思いますし、使う意味はあると思います。きっと。

log4netの変なバージョン依存だけはどうにかしてほしいですが、このプロジェクト年単位でメンテされてない感があるので(実際log4netの件はPRも来てるけど処置なし)、もう自分フォークしてビルドしたの使ったほうがいいんじゃないのという気がしてきたりもしたのでぼちぼちこのあたりで終わりたいと思います()

*1:2007以降のxlsx等の形式はOffice Open XMLというれっきとしたオープン企画です一応

*2:現状はOffice 2013 ProとかについてるSpred Sheet Compare とか使うとなんとかいけるかという感じ http://nasunoblog.blogspot.jp/2013/04/spreadsheet-compare.html

*3:プロジェクトファイルでのSpecificVersion=Falseの意味を取り違えているかnuspecの設定で意識していなかったのどちらかでしょうか

*4:これは@ahiru_spが遭遇したことで把握しました

*5:T4を実行するVisual Studioが32bitプロセスであるためだと思います

ASP.NET WebHook (Preview)を試してみた

本エントリはASP.NET Advent Calendar 2015の1日目のエントリです。 今年はなぜかASP.NET Advent Calendar 2015を立てることになったので(とはいえ言い出しっぺではありません)、とりあえず1日目を担当させていただきます。

 

ASP.NET WebHooks

少し前のことですが、ASP.NET の新しいフレームワーク?として、ASP.NET Web Hooks (Preview)というのが登場しました。 f:id:kiyokura:20151130235836p:plain

 

アナウンスのエントリはこちら:
Introducing Microsoft ASP.NET WebHooks Preview

 

Webフック(WebHooks)とは?

WebHooks(Webフック)とはWebサービス同士を連携させるパターンというか方式というか……などど僕が説明するまでもなく、githubやSlackなど、開発者が利用するサービスではをはじめ色々なwebサービスで利用されているものですね。

参考:Webhook - Wikipedia, the free encyclopedia

 

そういえば、去年のASP.NET Advent CalendarでVS Online(現Visual Studio Team Services)のService Hookを受け取るサンプルを作ったエントリ書きましたが、まさにこれですね。

ASP.NET MVC と Azure Web Sites で VS Online のカスタムService Hookを作成してサクッとリモートデバッグする - きよくらの備忘録

 

ASP.NET WebHooksとは

詳細は上記のアナウンスのエントリや、少し前にいさみさんが翻訳されたInfoQの記事などを読んでいただくのが良いと思いますが、ざっくりいえば、

  • (いろんなWebサービスの)Webフックによる通知を受信する機能をサクっと実装する
  • 自分でWebフックを発行する機能をサクっと実装する

ためのインフラを提供するライブラリというかフレームワーク…ととらえて貰えれば良いように思います。

現時点では、 ASP.NET Web API 2 と ASP.NET MVC 5、つまるところ.NET Framework 4.xがターゲットになっているようです。

 

Receiverによるサービス対応

受信側の機能はサービスごとにReceiverを作成することで、プラガブルかつ再利用可能な形でいろいろなサービスに対応できる構造になっています。 現時点でも以下のReceiverが実装・NuGet経由で提供されています。

  • for Azure WebHooks
  • for BitBucket
  • for Dropbox
  • for Github
  • for MailChimp
  • for Paypal
  • for Pusher
  • for Salesforce
  • for Slack
  • for Stripe
  • for Trello
  • for Wordpress
  • for your custom WebHooks implementation
  • for generic WebHooks with special validation logic or security requirements

Visual Studio Onlineに対応したWeb Hooksが無い当たりどうよ、とは思いますがまあ言わないでおきます*1。 もちろん上記のようなドンピシャのReceiverが存在しないサービスであっても、RESTなWeb Hooksのサービスであれば最後の二つのパッケージを利用して(一からやるよりは)楽して実装できそうですし、オリジナルのReceiverを実装することも可能です。

また、Visual Studio 2015向けのExtension、ASP.NET WebHooks Connected Serviceもリリースされています。 このExtensionを利用すると、受信したいサービスを選択するだけで必要なReceiverのパッケージを取り込むなどの下準備を整えてくれます(後ほど実際に試してみます)。

 

もちろんOSS

ASP.NET Web HooksはもちろんOSSで、github上のリポジトリはこちら。 aspnet/WebHooks

Receiverのソースも含まれているので、独自にReceiverを実装する場合も参考にすればよさそうです。

 

リソース

オフィシャルなリソースを以下に整理しておきます。チュートリアル的な記事もあるので軽く目を通して手を動かすのもよさそうです。

 

試してみる(Slack連携)

ではさっそく、少し試してみます。 公式のエントリにもありますが、まずはSlackでサクっとやってみます。

*1:言ってる

続きを読む

Visual Studio 2015ではPowerPoint用ストーリーボード・アドオンが下位エディションでも使える

便利…だけどお高かった『ストーリーボード』機能

アプリケーションの画面デザイン案なんかを簡単に作成できる、PowerPoint用のストーリーボーディングのアドオン。こんな感じで、部品をドラッグアンドドロップでペタペタ張って画面のプロタイプを作成していく…とかできるやつです。

f:id:kiyokura:20151023002332p:plain

しばらく前から存在しているのですが(2012年ころ?)、元々Visual Studioの高価な上位エディション*1に付属するアドオンで、『知ってるけどウチの環境だと使えないし…』という人も少なくなかったと思います。

 

そんなあなたに朗報です!

 

無償版のVSでも利用できるようになった!!

このストリーボード、Visual Studio 2015では、下位の Professional どころか無償の Community エディションでも利用できるようになりました。

(……というのを今日の今日まで私もすっかり忘れていたわけですが)

 

ということで。 MSDNなどでVS2015のライセンスを持っているようでしたら、『まだ開発環境はVS2013から上げれないのよ……』というような方でもとりあえずVS2015をインストールだけしてストーリーボードだけ使うのもアリなじゃないかと思います。

Visual Studio Community 2015 でも利用出来る…のですが、使用許諾条件が私には良くわからない(VSに付属するものなのでVSの利用条件が適用されてもおかしくない気がする/VS Community 2015 の企業利用には条件がいろいろある)ので、企業で利用する場合はこのあたり気を付けたほうがよさそうです。(※企業内でも普通に使えそうな雰囲気です。末尾に追記しました。)

もちろん個人ユーザで委託業務とかで使わない分には何も気にすることは無いと思いますので、そういった方はぜひCommunityで。

 

何にせよExcelのオートシェイプやフォーム部品(!)*2を組み合わせて資料をでっちあげたりしてる方は、これを使えるとずいぶん捗るのではないでしょうか!

参考情報: PowerPoint を使用したアイデアのストーリーボード

 

追記

@kkamegawaさんに教えていただいたのですが、VS Commuity 2015でいれた場合でも、ストーリーボードアドオンの使用許諾はVS側とは異なるようです*3

Licensing and packaging changes for TFS 2015 - Brian Harry's blog - Site Home - MSDN Blogs

関連するところを抜粋してみます。

Storyboarding

With the 2015 release, we have decided to make our Power Point based storyboarding tool available for free (it was previously only available in Test Professional with MSDN, VS Premium with MSDN and VS Ultimate with MSDN). 
For now, we have included it in VS 2015 Community. 
When the new “Office integration” installer ships in the TFS 2015 Update 1 timeframe, we will include the storyboarding tool there as well to make it even easier to access.

ざっくりかいつまむと、

  • パワポのストーリーボード機能をフリーにするよ!
  • 当初は(無償版は)VS 2015 Communityに同梱するよ!
  • TFS 2015 Update 1リリースのタイミングで新しいOffice統合installer(?)を出すよ!

ということで、なので、VS Cimmunityでインストールされた場合でも、特に気にすることなく使えそうな風に読めます。

またTFS 2015 Update 1はちょっと前にRC1がリリースされました。ですので、もう少したらVisual Studio同梱ではない、単体のインストールパッケージがリリースされるっぽいです。

*1:と特定のTFSのエディション

*2:画面設計書.xlsにフォーム部品をならべて作っておいて「印刷時にずれるんだけど」と憤ってた人を見たことあります

*3:ただし、具体的に使用許諾がどんなものかは見つけれていません

10月のWindows UpdateでOneDrive for Businessで同期エラーが出ることがあるので注意(修正パッチあり)

本日…というか先週末あたりから微妙にOneDrive for Businessの調子が悪く、ファイルによってはさっぱり同期できない状況が続いていました*1

[同期の問題の表示]を表示するとこんな感じで、「資格情報が必要です」「資格情報を入力してください」と出ます。

f:id:kiyokura:20151023000743p:plain

環境は Windows 8.1 + OneDrive for Business 2013, OneDrive for Business はOffice 2013 Pro Plusのもの(俗にいうMSIインストーラー版)です。

 

ちなみに上記ダイアログをクリックしても資格情報入力ダイアログは表示されませんし、そもそもフォルダの同期はできているので本当に資格情報がないのか怪しいところです。

 

試行錯誤編

とりあえず[修復]を実行したのですが、結果から言うとNG。しかも、今まで同期できていたファイル類もこの過程で一度同期を解除してローカルから削除されたため、その後一切取得できなくなってしまいました(フォルダのみ作成され、ファイルは全て同期失敗して空、という状態)。

 

フォーラムやサポート情報などを検索しながら色々やってみたのですが、さっぱり解決しませんでした。ログアウトしてブラウザのキャッシュも消して資格情報も削除してOneDrive for Businessのキャッシュをして、挙句にはOneDrive for Business自体も再インストールして……。

 

それでもさっぱり直らず、途方に暮れていたところ……。

 

解決編

そんな折、O365側の管理コンソールをチェックしてくれていた id:sadynitro が該当しそうなKBを見つけてくれました。

October 21, 2015, update for Office 2013 (KB2986219) *2

……これやがな。というか10月21日って、現地時間的に出来立てほやほややないか……。

ということで、上記KBのリンクにあるパッチを適用すると解決しました!

 

まとめ

ということで、2015/10 月の月例のWindows Update 適用以降で OneDrive for Business の同期で問題が出るようになった場合は、上記KBの事象に該当している可能性があります。 (問題を引き起こしたKBは https://support.microsoft.com/en-us/kb/3085566 です)

そのうち問題解消のパッチもWindows Update から入手できるようになるかもしれませんが、現状はまだのようですので、該当する方は確認してみて下さい。

*1:ファイルによっては同期できていた…のですが、今から思うと OneDrive for Business じゃなくて、 WordやExcelファイルのアプリで直接開いて編集・同期してた分がうまくいっていた、という気がする

*2:日本語の機械翻訳がめちゃくちゃなので英語のリンクを張っています。en-usをja-jpに変えれば日本語になります

Visual Studio 2013を起動したらアドオンが読み込めない系のエラーが出た話

Visual Studio 2013 を起動したら『'TestWindowPackage' パッケージは正しく読み込まれませんでした』 みたいなダイアログが表示されました。

 

再起動後、テストエクスプローラー とチームエクスプローラーが死亡

例の『詳細は ActivityLog.xml 見てね』的な、…稀によく見るやつです:p

f:id:kiyokura:20151014220512p:plain

ダイアログで通知された通り、テストエクスプローラーが読み込まれていません。 f:id:kiyokura:20151014220541p:plain

さらによくよく見ると、チームエクスプローラーもお亡くなりに……。 f:id:kiyokura:20151014220616p:plain

この際どうでもいいですが、チームエクスプローラーのコンポーネントのGUIDは 312e8a59-2712-48a1-863e-0ef4e67961fc みたいですね*1

 

原因

正直、よくわかりません。10/14のWindows Updateを当てた後の再起動ではあったのですが、Visual Studioを手動で終了させていたにも関わらず、再起動時に「devenvを強制終了しました」的な文字が表示されていました。ので、Windows Updateは関係ない可能性があります*2

 

devenv /setup で修復できた

パッケージ関係でこういったエラーが出た時にはdevenv/setupスイッチを付けて実行するのが定石な気がします*3。 ということで、 - Visual Studioを終了させる - 管理者モードでcmdなりPowerShellなりを起動 - VS2013のdevenv(既定だとC:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE)に移動 - devenv.exe /setupを実行

環境によりますが割と時間がかかることがあるので、しばらく待ちます。

f:id:kiyokura:20151014220700p:plain

実行が終わったあとにVS2013を起動したら……エラーも出ず起動。テストエクスプローラーもチームエクスプローラも無事利用可能な状態になっていました。

#割と焦ったのは内緒

*1:ホントにどうでもいい

*2:隣の席の同僚はWU後も問題なかったし、少なくとも直接の原因ではないと思います

*3:多分