kazuk は null に触れてしまった

C# / .NET 系技術ネタ縛りでお送りしております

ASP.NET メンバーシップ、ロールを使って初期スーパーユーザーが無くて困る


タイトルのような事って起こりませんか?

管理者ロールみたいなの作ったとして、その管理者ロールに最初のユーザーをどうやって入れるねんとか。

IISマネージャがつながるとか、ASP.NETの構成ツールがつながれば、そっちからいかようにもできるんですが、そうもいかない環境ってありますよね。

簡単に言えば ASP.NET を Azure Web Sites で動かしてる時とか。

最初のユーザーを管理者ロールに入れるとかやるとして、ソレってできた瞬間から表に出てる Azure Web Sites でやって安全なん?とかとか。

アプリのつながるDBにユーザーレコード直接作ればいいっちゃ良いんだけど、IP固定してる回線でない場合には、現在IP調べてSQL Azure に一時的にそのIPを許可入れて、レコード作って、ここでIP許可外し忘れると同一プロバイダの誰かが偶然にもつながる穴が残るよねと。

まぁ、諸々面倒なんですわ、ロールベースで管理者ロール作って、しっかり管理系作ったとして最初のスーパーユーザーが居ないって事が。

そうですよね?

そんなわけで作った

要するにDBベースのASP.NET標準のメンバーシップやロールだけだと、初期ユーザーの作成とかがややこしいので、展開されるファイルベースの認証プロバイダがあればサイトが展開された時にはそのファイルに記述されたユーザーは居る事になると。

これをDBベースの認証プロバイダとカスケードしてスーパーユーザー以外はそっちにユーザー登録したり、認証するようにすればいいよねと。

PM> Install-Package ConfigBasedSecurityProviders

やってる事は単純に ExtendedMembershipProvider と RoleProvider の実装ですが、基本的にすべての更新系は基本となるプロバイダに転送し、同様に知らん事の参照系も基本となるプロバイダに流します。

そのうえでXMLで指定された多少の知っている事だけを認証処理したり認定します。

使い方

Nuget からパッケージをインストールすると、bin に認証プロバイダ本体が入ります。そして必要な web.config に対する修正が適用されます。App_Data 配下にサンプルとしてのxml が二つ入ります。あとルートに readme.html が入ります。

web.config の改行とかフォーマッティングが崩れるのは Nuget の仕業っぽいので気になるならオートフォーマットでも適用してください。

App_Data のXMLを修正して、ユーザーとパスワードを設定し、ロールのメンバーを設定します。

設定した XML は admin_users.xml / admin_roles.xml という名前に直せば、デフォルトで入る web.config の修正にあった形になります。逆に web.config 側でのファイルの位置指定を直せば、どこにでもファイルの置場や名前を設定できます。

これでファイルベースの認証を通した上で、必要な構成作業をやったうえで、要らなくなったら NuGet パッケージをアンインストールで取り外してしまってもいいし web.config の要らない所をコメントアウトして無効にしてしまっても良いでしょう。再デプロイでつぶしの反映を忘れずに。

まとめ

ASP.NET アプリケーションをクラウドに入れるのにあんまり安全じゃない事したくないよね。

認証回りの所に派手に作りこみしてバグ残すとセキュリティバグはすごく痛い思いするから初期構成の為に変な事もできないし、つけ外しがちゃんとできる格好でやらないと怖くてアレ。

そういったニーズに答えるパッケージのつもりでございます。

要するに、薄いゴムのアレですよ。うん。

注意事項

状態持たないので、ユーザーのパスワードミスによるロックアウトとかできません。なので強度の低いパスワードでユーザー作っておきっぱなしにすると、プルートフォースでやられる危険があります。

うん百文字のランダムとかプルートフォースされても「何千年頑張るの?」って言えるようにしておくか、初期構成作業を終えたら外すのお勧めです。

Doc of Code のコードから:プロバイダパターンの実装インフラ


Doc of Code では ASP.NET のプロバイダパターンを全面的に使って、モジュール間の依存性を解決しています。

というわけで、プロバイダパターンを実装する上での内部インフラストラクチャがあったりしまして、これの軽い紹介です。

プロバイダパターンとは

ASP.NET / ADO.NET その他で色々と使われているアプリケーション内でのモジュール差し込みメカニズムと言って良いでしょうかね、APIを定義するモジュールと、実装モジュールを分ける事ができ、実装は普通に web.config とかで指定する事ができます。

素の ASP.NET 上で実装する場合には ProviderBase 派生クラスを作ります。必要であれば Initialize をオーバライドし、初期化パラメーターを受け取ります。そして ProviderSettings を保持する構成セクションを作り、 ProviderCollection を初期化てプロバイダをインスタンス化します。

そのまま普通に実装するなら、以下の様なコードになります。

public abstract class HogeProvider : ProviderBase
{
    private static Lazy<ProviderCollection> _providers = new Lazy<ProviderCollection>( InitProviderCollection );
    public static ProviderCollection Providers
    {
        get { return _providers.Value; }
    }
    private static ProviderCollection InitProviderCollection()
    {
        var collection = new ProviderCollection();
        ProvidersHelper.InstantiateProviders(
            ConfigSettings.Providers,
            collection,
            typeof(HogeProvider));
        return collection;
    }
    private static Lazy<HogeSettings> _settings = new Lazy<HogeSettings>( InitSettings );
    public HogeSettings ConfigSettings
    {
        return _settings.Value;
    }
    private static HogeSettings InitSettings()
    {
        return (HogeSettings) ConfigurationManager.GetSection(“hogeProviders”);
    }
    // API’s goes here
}

public class HogeSettings : ConfigurationSection
{
    [ConfigurationProperty(“providers”, Options = ConfigurationPropertyOptions.IsRequired)]
    public ProviderSettingsCollection Providers
    {
        get { return (ProviderSettingsCollection)this[“providers”]; }
    }
    // Settings properties goes here
}

Lazy の initializer をメソッドバインドして遅延初期化とかまぁ普通にやればこうなるかなぐらいの実装ですね。

実際には defaultProvider プロパティの追加とか、それを元に Provider プロパティを出してとかやるともうちょっと伸びます。

んで、一個実装するぐらいならなんてことはない話なんですが、5つも6つも実装するとなるとぶっちゃけてお約束コードが長くて鬱になるという類です。

Initialize のオーバーライド

プロバイダ作ったら大抵なんかしら初期化のオーバーライドが必要になります。

このオーバライドをすると configs として渡される NameValueCollection をグチグチといじる必要があります。

これがコードでやると結構うっとおしいのです。

_configParam=configs[“parameterName”]==null ? defaultValue : int.Parse( configs[“parameterName”] );

をべたべた並べてやると int.Parse が失敗すれば例外吹っ飛んでいき、ダメならエラーになってくれるし、設定しくってる奴が悪いといえばそうなんだけど、ちゃんと何の設定違ってるとか例外の詳細カスタムしようとすると try {} catch { throw … } で括ってを並べる事になります。

世の中データバインディングにアノテーションだろって言ってもまぁアレです。

Doc<Code> のプロバイダ実装インフラを流用する

https://kazuktnd.wordpress.com/docofcode/ でライセンスに明記されてる通りで、「それ以外のソースコードおよびバイナリは自由に実行、解析、改変、再配布、他の製品への流用等ができます。 」の「他の製品への流用等ができます。」の通りです。アセンブリ一個取りだして流用も許諾されていますので、好きにしてください。って事です。

bin に展開されている CustomProviderInfrastructure.dll を取り出し、参照設定します。

using CustomProviderInfrastructure; // NameValueCollection の Bind 拡張メソッドに必要

public class HogeProvider: CustomProviderBase<HogeProvider, HogeSettings >
{
    [InitializeParameterRequired]
    private int _timeout;

    public override void Initialize(string name, NameValueCollection config)
    {
        config.Bind( this, self=>self._timeout, int.Parse );
    }
}
[DefaultConfigurationSectionName(“hogeSettings”)]
public class HogeSettings : CustomProviderSettingsBase
{
}

InitializeParameterRequired で _timeout が修飾されていますので、この場合 timeout は省略できません。

config.Bind は式木のプロパティ名/フィールド名から取得する要素名を決定します。デフォルトで先頭の _ は削られ、結果は camelCaseName にされます。(先頭が大文字なら小文字になる)、フィールドないしパラメータに InitializeParameterName 属性でパラメータ名が指定されれば、その名前で NameValueCollection の要素を取りだします。

変換時に例外が出たりすると、ConfigurationErrorsException にパラメータ名等付いた例外を再送出するので、例外を綺麗にするとかの為にコードを特に足す必要はありません。

Bind には省略可能パラメータでデフォルト値が指定できますので、InitializeParameterRequiredAttribute を付けない場合にはデフォルト値も指定してください。

以上で前述のコードでの ProviderCollection の絡みや ConfigurationSection の派生もすべて済みます。

web.config には DefaultConfigurationSectionName で指定されるセクションを記述します。

<hogeSettings defaultProvider=”default” >
    <providers>
        <add name=”default” type=”HogeProvider, HogeProviderServices” />
    </providers>
</hogeSettings>

あと、web.config の configSections にセクションの記述が要りますがそんなもん当然すぎるので割愛。

まとめ

好きに使って良いよなアセンブリも入ってますので、遊んであげてください。

Doc<Code> というツールをリリースします


技術特化 blog なんで、滅多にやらない事なのですが、宣伝させてください。

宣伝かよ

はい、宣伝です。軽く失注続きで本気にこのままだと路頭に迷う事態なので一人ならどうという事は無いのですが嫁子供居る身なので必死なわけで、個人で作って使ってるツールの類に値段を付けて並べてみようかとの第1弾です。

タダで手に入る物で全部回して主義の方はこの先読んでも意味ないのでお帰り下さい。

Doc<Code> “doc of code” とは

.NET Framework アセンブリとその XML ドキュメントファイルを投げ込むとドキュメントを閲覧できる ASP.NET アプリケーションです。

同様なXMLドキュメントコメントの整形を行うアプリケーションとしては Sandcastle があります。Sandcastle プロジェクト自体は現状 Sandcastle Help File Builder でメンテナンスされているようですが、若干プロジェクトに不安定要素があり、ちょっとややこしい事になっているようです。

Sandcastle との違いは、あちらはビルドプロセスでのバッチ処理でHTML、およびヘルプファイルを作成する枠組みですが、Doc<Code> では、ASP.NET アプリケーションとして要求に応じてアセンブリを随時解析してXMLドキュメントと結合表示する仕組みですので、簡単に言えばビルド時に XMLドキュメントファイルの生成以上の追加処理を必要としません。結果的にビルド時間に対するインパクトを殆ど0にする事ができます。

要するにスロービルドの原因である、誰も見ないようなドキュメント生成を、オンライン解析変換処理にする事で開発スループットをより伸ばせるツールという事です。

インストールに必要な物は?インストールの手順は?

IIS 7.5 以降(Express でも可) 、 .NET Framework 4.5が必要です。 VS2012で普通に開発してる環境なら入っている物ですね。

DocOfCode の紹介とインストールデモ等

普通に NuGet からパッケージ入れるだけで入ります。

どういう使い方が想定されていますか?

普通に開発現場でドキュメントを見る用途、および、オープンソースな物を作ってる人がAPIリファレンスをインターネット上に公開するとかに使って良い様に作っています。

インターネット公開サイトに使う場合に、アセンブリを勝手にアップロードされないようにしたい等は、AssemblyController とその関連Viewそのものを外してしまって下さい。(この場合、アップロードはファイルを直接 App_Data に配置する事でもできますし、アセンブリの一覧管理はプロバイダになっていますので、プロバイダを実装する事で管理方法そのものを変える事ができます)

表示のデザイン等に関わる View および、それに当たる css 等はすべてパッケージ内にありますので、NuGet パッケージを取りこんだうえで修正してもらえれば幾らでもカスタマイズできると思います。

使い方

単純に動かすと能書きの書かれた Index ページの上部にアセンブリと設定のリンクがありますので、アセンブリを選んでもらうと、アセンブリをアップロードするためのページへ遷移します。

アップロード時に指定するタイトルはそのままアセンブリの情報ページのパスとなります、アセンブリ内の名前空間や型、メンバ情報はすべてその配下でアクセスされます。

アップロード済みのファイルと同じタイトルでアップロードを行うと、アセンブリファイルおよび、ドキュメントコメントのXMLファイルの入れ替えになります。

後は飛び回って好きにドキュメントをみて下さいという事です。 Code Contracts で XML ドキュメントコメントを出すようにしておけばそれなりに契約内容も表示されます。

名前空間に関するドキュメントコメント

ドキュメンテーションコメントのXML仕様的には N: で名前空間についてのドキュメントを置けることになっているため、このドキュメントタグが付いた要素があれば表示されるようになっています。また、 NDoc / sandcastle と同様に NamspaceDoc という型に対するドキュメントがあれば、名前空間のドキュメントとして表示されるようにしています。

ドキュメンテーションコメント内のタグ

推奨されるドキュメンテーションコメントタグの殆どはレンダリングできるようになっています。

また、各種HTMLタグはそのままHTMLタグとして表示するようになっていますので、HTMLの aタグをドキュメントコメントに記述しておけばリンクになりますし、imgタグを記述しておけばイメージも表示されます。(当然に img はどっか Web サーバにホストしないと見れませんと思いますけど)

高度な使い方とスケーラビリティ等

Doc<Code> は解析対象アセンブリとドキュメントをすべてメモリ上に読み込んで処理を行う為、スケーラビリティのネックは基本的にはメモリ容量という事になります。また、閲覧されるドキュメントをできるだけ高速にレンダリングしたいため、メモリに読み込んだモジュールやドキュメントをできる限りメモリ保持しようとしますのでアセンブリを登録すれば登録したほどメモリを使います。開発中のドキュメント参照支援等で .NET Framework のすべてのアセンブリとドキュメントを閲覧できるサーバを立てるとかはメモリがきついとかが根本的なネックになるでしょう。

結果的に別々のサーバに、このアセンブリはこっちのサーバ、このアセンブリはこっちのサーバといった形で配置する事になります。これらのサーバ間でドキュメントのリンクを通す事がサーバリンク機能で実現できます。

App_Data/LinkedServers.txt ファイルにリンクされるサーバ名:ポート番号を記述しておくと、該当サーバに存在しないアセンブリへのドキュメントのリンクが自動で解決されます。たとえば A サーバに mscorlib を配置して、Bサーバに自前のライブラリのドキュメントを配置し、BサーバのLinkedServers.txt にAサーバを記述しておくと、Bサーバでドキュメントをレンダリングする場合に String 等 mscorlib 由来の型は A サーバへのリンクとしてレンダリングされます。

Doc<Code>サーバ間は Web API で保持しているアセンブリの問い合わせを行っていますので、Aサーバへのアセンブリの追加などを行った時にBサーバ側は特に何もしないでも自動で反映されます。

注:サーバリンクを使ってサーバ間のリンクをする場合、それぞれのサーバにライセンスが必要です。

解析系の独自拡張の実装

Microsoft CCI に関する知識は必須ですが、アセンブリ、名前空間、型、メンバのそれぞれについて、追加で解析処理を行うロジックを入れるフックポイントが用意されています。

これにより、メンバメソッドのサイクロマチック複雑度を計算するロジックを追加すると、メンバの情報取得時にそれが呼び出され、ロジックが出力した結果は View まで引き渡しされます。

今後の開発ロードマップ

現状では各種メタデータおよび、ドキュメントコメントの表示側に注力している形になっていますが、将来的にはドキュメントコメントの入力、編集ができるようにする事を計画しています。

というのも、綺麗に見えるようになれば欲が出るので、使用例とかの Example をドキュメントコメントに色々書きたくなったりするのですが、それをやるにはコメントの中にコードを書かなければならないし、コメントの中に書かれたコードの中で XML 的な制約で < や > をそのまま書けないし色々と痛々しい思いをしなければなりません。

ドキュメントを充実させたいという思いと、ソースをそんなに汚したくないという思いや色々な葛藤の結果としてドキュメントコメントを実際として機能的に捨てているという現場も多いでしょう。

その辺りに対して、ドキュメントとして入れたい物をソース外からドキュメントコメントXMLに出力できる様にするビルド時ツールとか色々絡めて、十分なドキュメントを書いてもコードファイルが汚れない、それを素早く見れて修正を入れたりとかを Web 上のツールとコード上の双方でできる様にするのを次のマイルストーンとして考えています。

お値段は?

インストールされるサーバにつき1か月300円をめどに設定しています。

販売サイトの方を準備中だったりしますが、 1ヵ月300円、3ヵ月900円、6ヵ月1600円、1年で3000円の4通りのラインナップの予定です。

販売方法としては PayPal でのクレジットカード決済で購入するとメールでライセンスファイルが送られてくるという形式、ライセンスファイルはサーバへ配置が必要です。

また、直接 kazuk.dll@kazuk.jp の方にメール頂ければ見積書、納品書等、会社関係で必要な物は出せる形ができます。

んでいつリリースなのよ

とりあえず、NuGet パッケージについては今月中には出します。販売サイトは月明け早々にも立ち上がり予定、実際のライセンス販売開始は来月10日からを予定しています。(このあたり、多少のずれはあるかもしれません)

NuGet でのパッケージングの注意事項諸々


NuGet で pack する時に失敗しそうな事を色々と見つけたので blog

web.config.transform が指定した通りには入らないっぽい

現象の発生する NuGet.exe

C:\Users\kazuk\Documents\DocOfCode\DocOfCode>..\.nuget\NuGet.exe
NuGet Version: 2.5.40416.9020

ASP.NET プロジェクトのディレクトリで nuget spec 叩いて nuspec をちょっと編集してパッケージを作れるようになりましたって状態で、web.config に関する変換を web.config.transform として作成

nuget pack を叩く

Successfully created package ‘C:\Users\kazuk\Documents\DocOfCode\DocOfCode\DocOfCode.1.0.0.33115.nupkg’.

んでNuget package explorer で中身見てみると自分が指定した web.config.transform じゃなくて、web.config の内容が入ってる。 Exclude で web.config 指定してもダメっぽい。

image

Nuget package explorer で狙った格好の web.config.transform を入れなおさないと現状だめっぽい。

web.config の中にセキュリティ的にヤバい事書いてると nuget 経由で漏れそうな気がするので注意、超注意

NuGet pack –IncludeReferencedProjects を不用意に使うと危険

なんでか知らんけど、依存プロジェクトに含まれる出力ディレクトリにコピーのついてないコンテンツまで nuget パッケージに入れられちゃう。

nuget pack –IncludeReferencedProjects を使ってパッケージ

Successfully created package ‘C:\Users\kazuk\Documents\DocOfCode\DocOfCode\DocOfCode.1.0.0.33115.nupkg’.

CreateRasKey.txt は依存プロジェクトのコンテンツなんだけど、パッケージに入っちゃう。

image

クラスライブラリプロジェクトの中に txt で作り中のメモとか置いて出力ディレクトリにコピーしてないから大丈夫だと思ってるとダダ漏れになる。(RSA秘密鍵とかそういうのをうっかりコンテンツで置いてて漏れそうになった罠)

ビルドオプションをちゃんと None にしないとダメよと。

まとめ

便利な物だけど、ファイルが表に出ていく物である以上は慎重に使ってあげないと、セキュリティ的にヤバいので、中身はちゃんと確認しましょう。

Microsoft Code Digger をさっそくハックした


昨夜リリースされたばかりの Microsoft Code Digger をさっそくハックしてみました。

明け方の段階ではつかえねーコレだったのですが、ハックによってそこそこ使えるようになった感じです。

何ができる物ですか?

簡単に言えば Pex の低機能版です。一メソッドを選択し、コンテキストメニューから Generate Inputs / Outputs Table を行うとPexでの動作パスの列挙および、その動作パスに入るパラメータ値、そのパラメータでの呼び出し結果がリストアップされます。

    public class Class1
    {
        public int Test( int x,int y)
        {
            checked
            {
                return x/y;
            }
        }
    }

というTestAddを Generate Inputs/Outputs すると以下のように表示されます。

image

UI上ではそれだけです。これ以上の何もできません。

結果が気に入らなければコードを直せば良い、気に入ったならそのコードで良いんでしょ。別にすることないよねって鼻くそをホジってる感じです。

何ができない物ですか?

Code Digger 単体ではこのコードが将来に渡って同一の結果を返し続けるように保障する事はできません。

この一覧を元に単体テストを作って、ビルドサーバでそれを実行するようにすればそれはきっと実現する事ができるでしょう。Pexにはそれは備わっていましたが Code Digger には含まれません。

実際の所として現状追認のテストコードが一杯できるだけで、Pexでのテストコード生成は決して便利とは言いきれなかったのですが、それにしてもバッサリ切ってしまわれるとちょっとアレです。

カッとなってハックした

というわけで、Code Digger の出力をちょっと眺めてみたらテストコード自体は生成しているという事が解ったので、それを元に C# での単体テストコードを再構成する T4 テンプレートを書いてみました。

現物ファイルは gist にあります。

https://gist.github.com/kazuk/5449781

ファイルをダウンロードしたうえで Code Digger と組み合わせて使ってみましょう。

ポータブルクラスライブラリと単体テストのプロジェクトを作ります。

image

デフォルト名でビシバシひどいですが、こんなもんです。

足し算では単調すぎるので、割り算でやってみましょう。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace PortableClassLibrary1
{
    public class Class1
    {
        public int Test( int x,int y)
        {
            checked
            {
                return x/y;
            }
        }
    }
}

というコードに対して

image

という結果が得られました。

さっきの gist から取ってきたttを単体テストプロジェクトに突っ込みます。

最初の <#@ assembly #>の行を

<#@ assembly name=”$(SolutionDir)\PortableClassLibrary1\bin\Debug\PortableClassLibrary1.dll”#>

と書き換えて保存します。

普通に C# ソースが吐かれますが、一部エラーとなっているはずで、TODOコメントがいくらか出ていると思います。

// info PexFrameworkDir = C:\Users\kazuk\AppData\Local\Microsoft\VisualStudio\11.0\Extensions\z2qe4t0q.wnk
// TODO: add reference Microsoft.Pex.Framework.dll to this Project. path shown previous line

TODOの二つ目が上記内容です。どこにインストールされるかはちょっと予想がつかないので、パスが表示されています。ここにある Microsoft.Pex.Framework.dll を参照設定してください。(ソースコードを共有している場合に人様が自分のAppData\Local を参照できないとかで困らないようにソリューション内の適当な場所にコピーする等気は使って下さいね。)

これでエラーは消えるはずです。

もう一つのTODOである名前空間まで調整すれば特にもうする事はありません。

テストは生成されていますので、実行してみましょう。

image

もともとCode Digger で失敗したよと表示されているテストは失敗するように生成されました。

テストをいじったのにT4 から再生成されては意味がないので、ソースコードをまっとうなファイル名を付け替えて保存すれば完了です。

最後に例外で失敗してる所とかをそれを望むなら PexRaisedExceptionのtypeof通りに ExpectedException で想定通りと言い聞かせればいいでしょう。

注意事項

複数の Code Digger の結果が残ってると一気に生成するので生成メソッドが重複する事があります。bin\Debug配下にreportsとして結果は出ていますので、不要な物は適宜削除するか、さっくりデバッグしたい時などは名前空間を変える等で重複をごまかしておけば良いんじゃないかな。

まとめ

普通に使うにはちょっと機能不足な気もするけど、機能が無いならハックすれば良いじゃないで何とかなってみました。

Pex は楽しいツールなんでうまく使って下さい。ではでは!ハッピーな開発を!

Windows 8 & RT でのサイドローディング


年末年始辺りから調べ初めて、一応これで確定かなと思える段階になりましたので記事おば。

サイドローディングって何ですか?

一般的に Windows 8 / RT ではアプリケーションはマイクロソフトの運営する Windows アプリストアから入手するようになっています。( Windows 8 のデスクトップ環境はこの限りではありません)

Windows アプリストアは全世界に向けて公開されている物なので、企業内利用を前提とするアプリケーション(いわゆるインハウスアプリケーション)の配布と展開には向きません。特に企業秘密なロジックやその他が外部に漏れないように管理したいという場合には向きません。

これにたいする回答がサイドローディングという事になり、Windowsアプリストアを経由せずにアプリケーションをインストールする事ができます。

サイドローディングが可能なクライアントOS

Windows 8 の場合には家庭向けの位置づけがされている無印エディションのみサイドローディングができません。

Windows 8 Enterprise の場合にはドメイン参加時点でサイドローディングが可能になります。

Windows 8 Pro ではOSに追加で Sideloading Activation Key を入手、インストールする事により Sideloading が可能になります。(ただし 一般の Retail 版 Windows Pro ではできません、ボリュームライセンスプログラムによって入手されたWindows 8 Pro が必要という事です。 参考情報1 )

Windows RT は Pro と同様に Sideloading Activation Key を入手、インストールする必要があります。

Sideloading Activation Key の入手

以下のいずれかのライセンスプログラムに加入していれば、ライセンスプログラムの特典として無償入手が可能です。

  • Select / Select Plus による Windows ソフトウェアアシュアランス
  • Windows を含む Enterprise Agreement / Enterprise Subscription Agreement
  • 教育組織では Windows を含む Enrollment of Education Solutions ないしは Campas/School Agreement

上記ライセンスプログラムに加入していない場合には、 Select / Select Plus から購入する事ができます。

製品名 「WinSdLdH 8 … 100Lic EntSideload」 …部にはライセンスプログラム固有なワードが入ります。

WinSdLdH EntSideload の Bing 検索結果

会社として付き合いのあるオープンライセンスのリセラーにこれで問い合わせれば見積もりくれるでしょうし、売ってくれるはずです。

最低でも 100 ライセンスのパックですので、数台の物にインストールするのは結構割に合わないと思います。

Side Loading Activation Key はマシン単位です、1ライセンスは1台にインストールでき、マシンと完全に結び付けされますので、マシンを廃棄その他した場合には消尽する物と考えてください。

ポリシーによるサイドローディングの許可

グループポリシーの「信頼できるすべてのアプリのインストールを許可する」を有効にします。

Sidelading Activation Key のインストール

コマンドロンプトで管理者権限で Slmgr を実行します。

image

/ipk オプションで Sideloading Activation Key の 25桁のプロダクトキーを入力してください。

サイドローディングアプリケーションの展開

手動インストールを行う場合 add-appxpackage PoweShell コマンドレットを使います。

Windows インストールイメージに付属させてアプリケーションを展開するには DISM コマンドの /Add-ProvisionedAppxPackage オプションを使うか、Add-AppxProvisionedPackage PoweShell コマンドレットを使います。

System Centerその他、Windows でアプリケーション展開を行う為の各種システムがサイドローディングに対応しているようです。(そちらは私は調べていません。)

サイドローディングされるアプリケーションの開発

サイドローディングされるアプリケーションは適切な署名がされている必要があります。(以下は自己署名証明書を利用する例です、企業レベルでCAを持っている場合、そのCAで証明書を発行する事が望ましいです)

コードサインニング証明書を作成します /eku オプションの 1.3.6.1.5.5.7.3.3 がコードサインニング証明書を生成する事の指定になっており 1.3.6.1.4.1.311.10.3.13 で証明書が無効になってもコードサインニング署名を有効にするためのオプションです。(これを指定していないと証明書が期限切れで無効になった時にアプリケーションを再署名する必要があります)

C:\Users\kazuk>MakeCert /n “CN=Kazuk” /r /h 0 /eku “1.3.6.1.5.5.7.3.3,1.3.6.1.4.1.311.10.3.13” /e “08/01/2013” /sv MyKey.pvk MyKey.cer
Succeeded

数回パスワードをどう設定するか聞いてきますのでパスワードを設定すると Succeeded 表示されファイルが作成されます。

Pvk2Pfx ユーティリティで pfx ファイルを作成します。

C:\Users\kazuk>Pvk2Pfx /pvk MyKey.pvk /pi 検閲削除 /spc MyKey.cer /pfx MyKey.pfx

/pi のパラメータは 証明書のパスワードです。 /po オプションで pfx を利用する際のパスワードを設定できます。

作成された MyKey.cer は展開されるマシンの証明書ストアに配置する必要があり、pfx はアプリケーションの開発に必要になりますので、pvk 含めてちゃんと保存、管理してください。

開発者はプロジェクトに pfx を配置するか証明書ストアに pfxをインポートします。

imageimage

ファイルを選択すると証明書のパスワードを要求されるので、これを入力すると署名が設定されます。

完全な証明書の表示を行うと、MakeCert 時に設定した日付までになっていますので、正しく署名がされる事が確認できます。

cer ファイルを展開先マシンの「信頼される発行元」の証明書ストアに登録する事で、このpfxで署名されたアプリケーションは展開先で信頼されます。(今回は自己署名証明書のため、ルート証明機関にも登録する必要があります)

サイドローディングされるアプリケーションで、Windows Runtime に存在しないAPIを利用する

ポータブルクラスライブラリでインターフェースを宣言し、それを実装する通常のクラスライブラリを作成してMEFでロードすればいけます。これを使うとLOBアプリケーションで SQL Server 等のRDBMSを利用する事も普通にできます。

 

参考情報

1. sideloading product activation key + Windows 8 : MSDN Forum

その他 MSDN や TechNet 見ろ

まとめ

個人事業主としてサイドローディングされるLOBアプリケーションの受注開発、ないしは開発プロジェクトに対しての技術支援等行っておりますので、ご相談ください。

Visual Studio で kindle 本をビルドする


ネタ的には msbuild と Visual Studio のカスタマイズネタでございます。

Kindle 本のソース

Kindle 本を書く上でのソースは、html と pdf, word 文書等が選べるようです。

細かい事はこっちを参照 Amazon.com: Kindle Direct Publishing: HelpType of Formats

んで、今回は Visual Studio の ASP.NET Web Application の csproj を魔改造して html から mobi 形式で kindle 本をビルドするという形にします。プロジェクトのドキュメントとか、ソリューション内に kindle 本のプロジェクト置けば電子書籍化できるという誰得な物ですね。

というわけで ASP.NET Web Application のプロジェクトを作ります。 MsBuildBook とか付けてますけど、こんな本が Amazon の Kindle ショップに並んでるはずがないよね!

目次を index.html として作ります。

imageimage

この目次はあくまでもコンテンツです、本の中身の目次だと思っても良いでしょう。そういう意味で好き勝手な事を書いて良いです。

目次情報ファイル ncx と opf の作成

とりあえず将来的には T4 とか msbuild カスタムタスクで吐かせるつもりでも一端手書きで書いておきます。

opf も書いておきましょう。

imageimage

ビルドツールの入手

Download KindleGen 2.8 から kindlegen を入手します。プロジェクト内に buildTools フォルダを作り exe を配置しました。

とりあえず opf を叩くとビルドされます。おめでとう。

ビルドされた mobi を kindle の doucments 以下に USB 接続で送り込むと実際に表示を確認する事ができます。

image  IMG_0040IMG_0041

表紙と目次をそれぞれ表示した所、ちゃんと表示できてますね。

目的は自動化だ!(いや、それ手段ですし

さて、手順は解ったという事で自動化していきましょう。

まず、 build そのものをプロジェクトのビルドでできるようにしましょう。

おもむろにプロジェクトをアンロードして 編集に入ります。とりあえず実行してたコマンドを Exec で叩きます。

  <Target Name="MobiBuild" AfterTargets="Build">
    <Exec Command="buildTools\kindlegen MSBuildBook.opf" 
          StdOutEncoding ="utf-8" 
          StdErrEncoding="utf-8"  />
  </Target>

AfterTargets で Build を指定しているので標準の build が動いた後でこのターゲットが実行されますね。

コマンドプロンプトで build したらちゃんと実行結果を得られました。プロジェクトを再読み込みし、リビルドすると、はいできたー。

imageimage

opf 書くのだるいよね

うん、だるいね。本体のHTMLをどんどん書いていけば出来上がるのが理想だね。

csproj には html の一覧あるし、これを元に出したいね。というわけで opf 作成の msbuild のカスタムタスクを書く。

using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Xml.Linq; using Microsoft.Build.Framework; using Microsoft.Build.Utilities; namespace Build.Utilities { public class GenerateOpf : Task { [Required] public ITaskItem Metadata { get; set; } [Required] public ITaskItem[] Contents { get; set; } [Required] public string OutputFile { get; set; } public override bool Execute() { var metadata = XDocument.Load(Metadata.ItemSpec); var doc = new XDocument( new XElement( "package", new XAttribute("unique-identifier", "uid"), CreateMetadataElement(metadata), CreateManifestElement(Contents), new XElement("spine", new XAttribute("toc", "toc")), new XElement("guide") )); doc.Save(OutputFile, SaveOptions.OmitDuplicateNamespaces); return true; } private static XElement CreateManifestElement(IEnumerable<ITaskItem> contents) { var manifestElement = new XElement("manifest"); manifestElement.Add( new XElement( "item", new XAttribute("id", "toc"), new XAttribute("media-type", "application/x-dtbncx+xml"), new XAttribute("href", "toc.ncx"))); foreach (var item in contents.Where( i => Path.GetExtension(i.ItemSpec) == ".html")) { var itemSpec = item.ItemSpec; Debug.Assert(itemSpec != null, "itemSpec != null"); var idValue = Path.GetFileNameWithoutExtension(itemSpec); manifestElement.Add( new XElement( "item", new XAttribute("id", idValue), new XAttribute("media-type", "text/x-oeb1-document"), new XAttribute("href", itemSpec))); } return manifestElement; } private static XElement CreateMetadataElement( XDocument metadata) { return new XElement( "metadata", CreateDcMetadataElement(metadata), CreateXMetadataElement() ); } private static XElement CreateXMetadataElement() { return new XElement( "x-metadata", new XElement( "output", new XAttribute("encoding", "utf-8"), new XAttribute("content-type", "text/x-oeb1-document")), new XElement( "EmbeddedCover", new XText("images/Cover.jpg")) ); } private static XElement CreateDcMetadataElement( XDocument metadata) { XNamespace dc = "http://purl.org/metadata/dublin_core"; XNamespace obe = "http://openebook.org/namespaces/oeb-package/1.0/"; var dcMetadataElement = new XElement( "dc-metadata", new XAttribute(XNamespace.Xmlns + "dc", dc.NamespaceName), new XAttribute(XNamespace.Xmlns + "oebpackage", obe.NamespaceName) ); foreach (var element in metadata.Element("dc-metadata").Elements()) { dcMetadataElement.Add(element); } return dcMetadataElement; } } }

これを csproj に組み込むには以下のように。

  <UsingTask 
    TaskName="GenerateOpf" 
    TaskFactory="CodeTaskFactory" 
    AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v4.0.dll">
    <ParameterGroup>
      <Metadata ParameterType="Microsoft.Build.Framework.ITaskItem"
            Required="true" />
      <Contents ParameterType="Microsoft.Build.Framework.ITaskItem[]" 
            Required="true" />
      <OutputFile ParameterType="System.String" Required="true" />
    </ParameterGroup>
    <Task>
      <Reference Include="System.Xml" />
      <Reference Include="System.Xml.Linq" />
      <Code Type="Class" Language="cs"
          Source="..\Build.Utilities\GenerateOpf.cs" />
    </Task>
  </UsingTask>
  <Target Name="OpfGenerate" BeforeTargets="Build">
    <GenerateOpf 
         Metadata="Metadata.xml" 
         Contents="@(Content)" 
         OutputFile="MSBuildBook.opf" />
  </Target>

dublin core なメタデータだけ Metadata.xml に書けば、こんな opf が吐かれる。

<?xml version="1.0" encoding="utf-8"?>
<package unique-identifier="uid">
  <metadata>
    <dc-metadata xmlns:dc="http://purl.org/metadata/dublin_core" xmlns:oebpackage="http://openebook.org/namespaces/oeb-package/1.0/">
      <dc:Title>msbuild をこねる本</dc:Title>
      <dc:Language>en-us</dc:Language>
      <dc:Creator>kazuk</dc:Creator>
      <dc:Description>msbuildをこねてビルドの自動化とかを色々カスタマイズする本です</dc:Description>
      <dc:Date>26/03/2013</dc:Date>
    </dc-metadata>
    <x-metadata>
      <output encoding="utf-8" content-type="text/x-oeb1-document" />
      <EmbeddedCover>images/Cover.jpg</EmbeddedCover>
    </x-metadata>
  </metadata>
  <manifest>
    <item id="toc" media-type="application/x-dtbncx+xml" href="toc.ncx" />
    <item id="index" media-type="text/x-oeb1-document" href="index.html" />
    <item id="MSBuildProjects" media-type="text/x-oeb1-document" href="MSBuildProjects.html" />
    <item id="VSAndMSBuild" media-type="text/x-oeb1-document" href="VSAndMSBuild.html" />
  </manifest>
  <spine toc="toc" />
  <guide />
</package>

html の列挙とかは csproj にある Content のリストからやってるだけだから Web アプリケーションプロジェクトに HTML ページを突っ込んで行けば自動的に opf に組み込まれるので手間がかからない。

ncx も吐いてやろうか!

似たような方法を取れば ncx も吐けます。目次の順序とかは各HTMLからキー要素をなんか抽出してあげるとかすれば良いので手間は似たようなもんでしょう。

まとめ

今日のところはこんな感じ、普通に VS でHTMLを書いてビルドすれば kindle で読める mobi を生成するプロジェクトを作る事ができました。

多分 VS Express でも同じ事はできるはずなんで、無料のExpress でHTMLシコシコ書けば普通に kindle 本を書くのはできそうです。画像とかそういうのを使ったときにどうなるとか、その辺解ったら続編を書くかもしれません。

こんな事はだれもやらねーよかもしれませんけど、VS に markdown から HTML への変換のカスタムツールとか仕込めば、markdown とかでジャカジャカ書いたものを電子書籍にするのも簡単かもしれませんね。

まとめではないこと

自分が本書いて amazon の direct publishing 出したら誰か買いますか?>買うわけないよね!

NuGet パッケージの作成とローカルリポジトリへの発行


Gistしましたって事でお知らせ。

https://gist.github.com/kazuk/5089069

何をするものですか?

ビルドすると NuGet パッケージを作り、ローカルリポジトリに発行します。

使い方

  1. ソリューションを右クリックし、「NuGetパッケージの復元の有効化」を行います。(又は NuGet.exe をソリューション配下、 .nuget ディレクトリに置いてください)
  2. ソリューションにGistから取ったファイルを突っ込んでください。
  3. csproj の末尾で Import してください
  4. 必要に応じて NuGetRepository を PropertyGroup 定義してください(定義しないと \\nugetrepos.local\NuGetRepos にパッケージを発行します)
  5. プロジェクトに nuspec を加え、ビルドアクションに NuSpec を指定します。

nuspec 作るってどうやって?

csproj のある場所で NuGet.exe spec すればいいんじゃないかな?

そのままパッケージしようとすると author とか色々設定されてないよって言われるはずだけど、文句言われた所直せばいいと思うよ。

csproj の末尾でImportって?

プロジェクトを右クリックして「プロジェクトのアンロード」、もう一回右クリックで csproj の編集すればいいよ。

ファイル末尾の </Project> の前でローカルリポジトリの場所と targets ファイル置いた場所によって設定してね。

  <PropertyGroup>
    <NuGetRepository>\\FileServer.local\NuGetRepos</NuGetRepository>
  </PropertyGroup>
  <Import Project="..\Build.Utilities\CustomBuild.targets" />

発行って Copy してるだけに見えるけど

ファイルシステムフォルダをローカルリポジトリとして使ってるならコピーだけでいいんだよ。

NuGet.org とかに出す前に色々確認して欲しいからローカルにしか出さないよ。

Visual Studio 2012 の新しいDSL Tools


Visual Studio 2012 の新しい DSL Tools を色々試したので、メモなど。

DSL Tools とは

DSL(Domain Specific Language) ドメイン特化言語を扱う為の Visual Studio 拡張を作る為の物。 DSL Tools はVisual Studio 2005 からできたもので、VS2010移行では Visual Studio Visualization & Modeling SDK に統合されている。

最新の Visual Studio Visualization & Modeling SDK のダウンロード URL は以下のとおり。

http://www.microsoft.com/en-us/download/details.aspx?id=30680

Visual Studio 2010 での Visualization & Modeling SDK との違い

ぶっちゃけあまり変わってない。

WPF デザイナと、WinForms デザイナの選択ができるのも一緒、いわゆるダイアグラムデザイナコンポーネントの類( Box を線で結ぶような物 )は GDI+ でしか提供されていないのも変わらない。 Win Forms と WPF は Alternative ではなく相互にコンポーネントの乗せあいをしながら補完しあう物という筋は Visual Studio 内で当たり前のように行われていてその通りの考え方で Visualization & Modeling SDK も実装されている。

WPF デザイナを選んだ時に生成される UI が単なる表形式 View でぶっちゃけショボイのも変わってない。

そして、待望の WinForms Designer の生成オプションが追加(だと思う、VS2010 版DslToolsの比較対象機をアップグレードしちゃったのでもう解らない)、 Visual Studio のデザイナコンポーネントに依存しない Pure な Win Froms なデザインビューを作れるようになりました。生成物は WPF 版デザイナと変わらない単なるグリッドビューだったりして、コレ追加した意味わかんない系。

image

纏めると、MinimalLanguage が旧来からの GDI+ でのダイアグラムデザイナを実装する物。

Minimal WinForms Designer は WPF 版デザイナ(単なる表形式ビュー)と全く同一構造の Windows Forms 版、 Minimal WPF Desinger は VS2010 からある WPF 版(単なる表形式ビュー)

WinForms 版は BindingSource をうまく使う事でいわゆるMVVM的なデータバインディング一辺倒なつくりになってますね。

imageimage

WPF も WinForms もユーザーコントロールをデザイナサーフェースにできるという事は一緒という事で、その手段でのAPI差異の吸収以外には DslPackage に違いはありません。Dsl 側は全く一緒じゃないかな。

Windows Workflow のデザイナがリホスティング可能だったりしてデザイナコンポーネントをVS依存せずにとかできるんじゃない?とか思ってたりしたんですけど、そこにまつわる変更は無いもよう。 WPF/WinForms の何にもないUIから Windows Workflowのチームがシコシコと再発名したか VS のデザイナコンポーネントから相当量のコードを分岐したってことですか。

良くなったこと

http://msdn.microsoft.com/ja-jp/library/bb126259.aspx 機械翻訳だけど、ちゃんとメニューがつながってる!画期的!(以前は言語を英語に切り替えないといけなかったはず)

DSL Details の表示が壊れていくのが無くなった気がする。

ModelBus 接続が可能になったようだ。

まとまらない

まとめようにもまとまらない。メモだから。

Visual Studio 2012 でのパフォーマンスプロファイリング


どーも、どーも、どーもです。

Visual Studio Advent Calender 2012 が中々枠が埋まり切らないという悲鳴が上がってたので、参加しましたです。

というわけで、表題通りパフォーマンスプロファイリングについて書かせてもらいます。

Visual Studio でのパフォーマンスプロファイリング機能は Visual Studio 2010 までは Premium 以上で有効、Visual Studio 2012 では Professional 以降で有効という事で、Visual Studio の上位エディション機能がやっと普通のエディションで使えるようになったという事になります。

というわけで、プロファイリングによってなんかしらプログラムのボトルネックが検出できるかという事で緩く募集したら msgpack-cli をプロファイリングしてみてほしいという事で試してみました。

https://twitter.com/kazuk/status/282008544600023040

Visual Studio でのパフォーマンスプロファイリングの開始方法

テストプロジェクトがあれば、テストの実行中にプロファイリングを行う事ができます。「テスト」メニュー「テストのプロファイル」ただし、プロファイリングがストアアプリのプロファイリングにまだ対応していないので msgpack-cli に対して即座に試す事はできませんでした。実際問題としてパフォーマンス問題を抱えたところをテストとして作りこむとCIサーバとかでスローテストになって邪魔になるのでお勧めしませんです。

image

コンソールアプリケーションを含む一般的な実行可能なものであればプロファイルは可能ですので、今回はテストの中で[Explicit]で除外されてる物から TestStringMedium を選び、コンソールアプリケーションに同等物をこさえてみました。

現物ソースはこちら。

https://gist.github.com/4357661

最初オリジナルのテストを数1000回実行するようにしたのですが、結果的にテスト側での StringBuilder での文字列構築がボトルネックとなったので、一回構築した文字列に1万回のシリアライズ、デシリアライズを行う様にしてみました。

このコンソールアプリケーションをスタートアッププロジェクトに指定して、パフォーマンスプロファイラを起動します。

「分析」メニューから「パフォーマンスウィザードの起動」でプロファイリング方法などの設定を行いながらプロファイリングを開始します。

imageimage

初期状態として「CPUサンプリング」がプロファイリングの方法として選択されています。このプロファイリングでは一定時間毎に実行スレッドを止めスタックトレースを取って何を実行しているかを記録する方法が使われます。なので相当に実行時間のかかる処理以外はプロファイリングできませんし、ほとんど実行時間を使わない部分については結果に現れません。

性能のボトルネックがどこなのかを把握するのに最も適したプロファイリング方法になります。次にプロファイル対象プロジェクトの選択になります。自分で用意したプロジェクトを指定して次へ進みます。

imageimage

完了時にプロファイルを開始するを指定していればパフォーマンステストが開始されます。

image

相当しつこく実行するようにしているのでプログラムは中々終わりません、定常実行状態になって1分ちょいでも実行すれば十分なサンプルが集まりますのでコンソールアプリケーションの実行ウィンドウを閉じて終了させます。

分析していますの表示後に以下のような分析結果が表示されます。

image

最初に表示されているのは CPU 使用率のグラフで、このテストの間 1 Core をほぼ占有してプログラムは動作していた事になります。次にホットパスとしてサンプリング結果が示していた関数が最も多く実行していた関数が表示されています。

92.4% のCPU時間が TestStringMedium で消費されているのでプロファイリングとしてはターゲットをちゃんと実行している事になります。TestString は実際に Pack/Unpack を行っていますが、実際にはPackの方が 59% を占有、Unpackは8%弱しか使っていない事が解ります。

imageimage

デシリアライズの性能改善が可能であるかという話なので、少ない側ですがUnpack に降りていきましょう。

imageimageimageimageimageimageimageimage

単純に呼び出し先が mscorlib とかマングリングされたネイティブメソッドになるまで降りた結果としては上記の流れになります。

8メソッドにわたって降りて行きましたが最終的には new byte[] と Stream.Read に処理時間が使われている事がこれでわかります。ここの時間消費を削るにはどんな方法があるでしょうか。 new byte[] を削るにはバッファ管理を入れて同一の長さのバッファを再利用する等の方策もあったりしますけど、上位の構造を大きくいじらない限りには無理でしょう。Stream.Read の処理時間を削る方法は多分無いと思います。メモリストリームからの読み出しですから単純にバイト列のコピーに時間を取られているはずです。

実際のところとして new byte[] は 0初期化を含んでいます、0で初期化したうえで Stream.Read で内容をすべて上書きするのはちょっと無駄と言えば無駄です、しかしこれをプログラミング的に避ける事はできません。

さて Stream からバイト列を読む方法にはもう一つあり BinaryReader.ReadBytes があります。これを使った場合どうなるでしょう。

image

結果的には若干のコスト増になってしまいました、BinaryReader を new しているところで 0.3%の増加が最も大きく響いています、before / after で見ると new byte[] と Stream.Read  で 8% だった物が BinaryReader.ReadBytes の呼び出しで 8.1% と若干の増加も見られます。失敗と見ていいでしょう。 mscorlib に対しては NGen で結構厳しく最適化かけているという噂もなかったりしますけど、 BinaryReader.ReadBytes にはその効果は及んでいないと見て良いでしょう。

imageimage

実際 BinaryReader.ReadBytes の IL を眺めてみても Stream.Read で上書きされる事が明らかな配列の初期化を省略するような確保方法は行われていませんから順当な結果です。

それでも自分は変質的なスピード狂だったりする

Stream.Read には改善の余地はなくとも、バッファの確保と0初期化を避けるためにできる事はいくらかあったりします。

というわけでバッファの管理と再利用を実装してバッファを使いまわしてあげましょう。

人様のライブラリに勝手に API を追加しちゃいます。 MessagePackObject に Release メソッドを追加

        public void Release()
        {
            if (this._handleOrTypeCode is MessagePackString)
            {
                var packString = this._handleOrTypeCode as MessagePackString;
                packString.Release();
            }

        }

MessagePackString に Release と Alloc を追加してバッファを再利用できるようにします。

        static Dictionary<int, Stack<byte[]>> _buffers = new Dictionary<int, Stack<byte[]>>();

        public void Release()
        {
            Stack<byte[]> bufferStack;
            if (_buffers.TryGetValue(this._encoded.Length,out bufferStack))
            {
                bufferStack.Push(this._encoded);
            }
            else
            {
                _buffers.Add(this._encoded.Length, new Stack<byte[]>( new[] { this._encoded }));
            }
        }

        public static byte[] Allocate(int length)
        {
            Stack<byte[]> bufferStack;
            return _buffers.TryGetValue(length, out bufferStack) 
                ? bufferStack.Pop() 
                : new byte[length];
        }

テストコード側から Release を呼ぶようにして、バッファの再利用を促すのと同時に読み込みコードで Allocate によってバッファを確保するようにしてプロファイルした結果は以下。

image

単純比較はできないかもしれませんが、3割強の性能改善が実現できました。(まぁ、バッファの管理系はシングルスレッドだから動いてるレベルの実装なのでマルチスレッドに対応するともっと性能は下がってしまうかもしれません。)

まとめ

無理やりチューニングすれば早くできるところは多少なりともあったりしますが API 変わってしまうとそれを使っている所は作り直しになってしまいます。だから早いうちから API の利用者が増えないうちに、常にプロファイリングを取り続けてチューニングしましょう。パフォーマンス問題がAPI変更に波及すると出来上がってからの性能改善、チューニングはまず無理です。

まぁ、アプリケーションの枝葉末端はアプリケーションへの性能影響は殆ど無いのも事実ですので、アプリケーションへの性能影響の無い末端はチューニングする必要もありませんので、このコードがシステムの性能を支えている物なのかどうなのか、そこを把握するためにもプロファイリングは行ってくださいね。

今回は CPU サンプリングによる CPU 時間を元にチューニングをしましたが、他のプロファイリング方法も重要といえば重要です。システムがメモリ枯渇に陥っているなど GC が頻繁に活動して性能が下がっている等状況に応じて使い分けていきましょう。