しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

Windows Azure モバイルサービスの .NET バックエンドの仕組みを簡単に調べてみた

もうだいぶ前になりますが、Windows Azure モバイルサービスで Node.js 以外にもプレビューですが .NET を使った API 開発が行えるようになりました。このアップデートに関しては既に @kamebuchi こと抱かれたい男 No.1 や @miso_soup3 がまとめてくれているので参照してください。

Azure ExpressRouteとかいろいろUpdate « ブチザッキ

Windows Azure モバイルサービスで ASP.NET Web API を試す ~とりあえずサンプル実行~ - miso_soup3

.NET バックエンドの追加により ASP.NET Web API で開発できるようになって大歓喜ですね。

実はまったく .NET バックエンドどころかモバイルサービスを使っていなかったのですが、@miso_soup3 から聞いたところによると .NET バックエンドは割と良く分からない仕組みで動いているらしいので、ランタイム周りを中心に調べてみました。

まずはテスト用にモバイルサービスを作ります。バックエンドは当たり前ですが .NET を選択してください。

f:id:shiba-yan:20140325214720p:plain

適当に中身を埋めて進めていくとモバイルサービスが作成されるので、クイックスタートからサンプルコードをダウンロードしてきます。

f:id:shiba-yan:20140325215347p:plain

展開すると Visual Studio のソリューションが入っているので、ビルドしてデプロイするだけで Web API がモバイルサービスで使えて幸せなんですが、コードを見てみるとデフォルトの設定との違いが見えてきます。

public static class WebApiConfig
{
    public static void Register()
    {
        // Use this class to set configuration options for your mobile service
        ConfigOptions options = new ConfigOptions();

        // Use this class to set WebAPI configuration options
        HttpConfiguration config = ServiceConfig.Initialize(new ConfigBuilder(options));

        // To display errors in the browser during developemnt, uncomment the following
        // line. Comment it out again when you deploy your service for production use.
        // config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
        
        Database.SetInitializer(new shiba_yanInitializer());
    }
}

ConfigOptions や ServiceConfig はモバイルサービス固有のクラスで、いい感じに Web API をモバイルサービス上で動かす設定を自動的に作ってくれるみたいですね。

しかし、ローカルでは WebApiConfig というクラス名を変更しても動作するのに、デプロイするとエラーになってしまう現象があるらしいです。

デプロイした時に、ログには次のように表示されます。"Found bootstrapper 'WebApiConfig'."と。

ためしに「WebApiConfig.cs」のクラス名を適当な名前に変更してデプロイすると、失敗します。

Windows Azure モバイルサービスで ASP.NET Web API を試す ~とりあえずサンプル実行~ - miso_soup3

普通に考えると Global.asax.cs の Application_Start で WebApiConfig.Register メソッドを呼び出しているので、別にクラス名に依存はしない気がします。このあたり挙動が気になったので Kudu を使ってどんなふうにホストされるのか調べました。

モバイルサービスはほぼ仕組みが Web サイトと同じなので Kudu が普通に使えます。既にこのブログでも紹介したので参考にしてください。

Windows Azure モバイルサービスでも Kudu がバックエンドで使われているという話 - しばやん雑記

さて、とりあえず Kudu にはログインできると思うので wwwroot 以下をまず調べてみましょう。

f:id:shiba-yan:20140325220204p:plain

予想に反して空っぽでしたね。冷静に考えると Web 発行でごっそり削除される可能性もあるので、wwwroot に予めファイルを置いておくのは難しいですね。

なので、次はいつも通り applicationHost.config を調べていくわけですが、サイト設定に非常に怪しい記述を発見しました。

<site name="mobile$shiba-yan" id="1437513528">
  <bindings>
    <binding protocol="http" bindingInformation="*:80:shiba-yan.azure-mobile.net" />
    <binding protocol="https" bindingInformation="*:443:shiba-yan.azure-mobile.net" />
  </bindings>
  <traceFailedRequestsLogging enabled="false" customActionsEnabled="true" directory="D:\home\LogFiles" />
  <detailedErrorLogging enabled="false" directory="D:\home\LogFiles\DetailedErrors" />
  <logFile logSiteId="false" />
  <application path="/" applicationPool="mobile$shiba-yan">
    <virtualDirectory path="/" physicalPath="D:\Program Files (x86)\SiteExtensions\MobileServicesDotNet\1.0.216" />
  </application>
</site>

あらら、モバイルサービスの .NET バックエンドの場合はドキュメントルートが wwwroot ではなくて、Program Files (x86) 以下にある Site Extension になっていました。つまり shiba-yan.azure-mobile.net にアクセスすると MobileServicesDotNet という Site Extensions が実行されるわけです。

さらにこの Site Extensions の中身を見ていきます。

f:id:shiba-yan:20140325220845p:plain

パッと見は普通の ASP.NET アプリケーションと同じようなファイル構成になっていますね。これがモバイルサービスの実体となるアプリケーションのようです。

Web.config を調べてみると、appSettings に以下のような記述を見つけました。

<appSettings>
  <!-- This setting must remain, so the site extension points to the correct bin -->
  <add key="MS_ApplicationRoot" value="%HOME%\site\wwwroot"/>
</appSettings>

なるほど、このアプリケーションは実際にユーザーコードがデプロイされたディレクトリを知っているので、実際にロードして実行することが出来るみたいです。

さらに Global.asax を調べてみると、コード自体はコンパイルされていて存在しないですが、HttpApplication として実行されるクラス名と名前空間を知ることが出来ました。

<%@ Application Codebehind="Global.asax.cs" Inherits="Microsoft.WindowsAzure.Mobile.Service.MvcApplication" Language="C#" %>

どう見てもユーザーコードが実行されるようには出来ていないので、実際にはブートストラップとして動作するアプリケーションを作ったのでしょうね。

その証拠というか、興味深いライブラリを bin ディレクトリ内で発見しました。

f:id:shiba-yan:20140325221457p:plain

ちなみに Microsoft.WindowsAzure.Mobile.Service.WebHost.dll というライブラリは、ダウンロードしたサンプルコードには全く含まれていないので、実際にモバイルサービスでホストする専用のライブラリでしょう。

とりあえずまとめておくと、何故 WebApiConfig クラスの名前を変更したら動作しなかったかですが、ブートストラッパーが起動時にデプロイされた DLL を wwwroot 以下から読み込んで実行する時に、リフレクションを使って「WebApiConfig」というクラス名を決め打ちで検索しているからだと推測できます。

f:id:shiba-yan:20140325223119p:plain

ちなみにモバイルサービスのコアとなっている Site Extensions ですが、何故か Web サイトにも普通に含まれているので、少し工夫すれば日本でもモバイルサービスとして動かすことが出来るかもしれませんね。*1

モバイルサービスは既存の仕組み、技術を組み合わせて作られているので、参考になるし面白いですね。

*1:モバイルサービスは日本データセンターにもデプロイされるらしいので少し待った方が良いですが