Azure Mobile Apps 用 ASP.NET Framework SDK の使用方法

このトピックでは、Azure App Service Mobile Apps の主要なシナリオで .NET バックエンド サーバー SDK を使用する方法について説明します。 Azure Mobile Apps SDK を使用すると、ASP.NET アプリケーションからモバイル クライアントを操作することができます。

警告

この記事では、v4.2.0 ライブラリ バージョンの情報について説明しています。これは v5.0.0 ライブラリによって置き換えられています。 最新の情報については、最新バージョンの記事を参照してください。

Azure Mobile Apps ASP.NET Framework バックエンドを作成する

Visual Studio 2019 を使用して、ASP.NET Framework アプリを作成できます。

  • [ASP.NET Web アプリケーション (.NET Framework)] テンプレートを選択します。 このテンプレートの検索時に問題が発生した場合は、[C#][すべてのプラットフォーム][Web] を選択します。
  • アプリケーションの名前と場所を選択してから、[Web API] プロジェクト テンプレートを選択します。 アプリケーションの基本サービスの正しいコレクションがインストールされます。

SDK をダウンロードして初期化する

SDK は NuGet.org で入手でき、Azure Mobile Apps を使い始めるために必要な基本機能が提供されます。 パッケージをインストールするには:

  1. プロジェクトを右クリックし、[NuGet パッケージの管理] を選択します。
  2. [参照] タブの検索ボックスに「Microsoft.Azure.Mobile.Server」と入力し、Enter キーを押します。
  3. Microsoft.Azure.Mobile.Server.Quickstart パッケージを選択します。
  4. [インストール] をクリックします。
  5. 指示に従って、インストールを完了します。

Microsoft.Owin.Host.SystemWeb をインストールするプロセスも繰り返します。

Note

Newtonsoft.JSONSystem.IdentityModel.Jwt などの依存関係として使用されるパッケージは更新しないでください。 多くの場合、これらのパッケージの API は変更されており、ASP.NET Framework 用 Azure Mobile Apps との互換性がなくなっています。

サーバー プロジェクトの初期化

Azure Mobile Apps サーバー プロジェクトは、他の ASP.NET Framework プロジェクトと同じように、OWIN Startup クラスを組み込むことによって初期化します。 OWIN Startup クラスを追加するには:

  1. プロジェクトを右クリックし、[追加]>[新しい項目] の順に選択します。

  2. [Web]>[全般] を選択し、[OWIN Startup クラス] テンプレートを選択します。

  3. スタートアップ名として、名前「Startup.cs」を入力します。

  4. Startup.cs ファイルの内容は次のコードのようになります。

    using Microsoft.Azure.Mobile.Server.Config;
    using Microsoft.Owin;
    using Owin;
    using System.Web.Http;
    
    [assembly: OwinStartup(typeof(WebApplication1.Startup))]
    namespace WebApplication1
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                HttpConfiguration config = new HttpConfiguration();
                new MobileAppConfiguration()
                    // no added features
                    .ApplyTo(config);
                app.UseWebApi(config);
            }
        }
    }
    

    OwinStartup、名前空間、およびクラス名は、プロジェクトによって異なります。 具体的には、Configuration() メソッドの内容を置き換え、必要に応じて using ディレクティブを調整する必要があります。

個別の機能を有効化するには、ApplyTo を呼び出す前に、MobileAppConfiguration オブジェクトに対して拡張機能メソッドを呼び出す必要があります。 たとえば、次のコードでは、初期化中に [MobileAppController] 属性が設定されているすべての API コントローラーに既定のルートを追加します。

new MobileAppConfiguration()
    .MapApiControllers()
    .ApplyTo(config);

次のセットアップでは、Entity Framework を使用してテーブル コントローラーと API コントローラーの両方が SQL サービスにアクセスでき、これは "正常" な使用法と見なされます。

new MobileAppConfiguration()
    .AddMobileAppHomeController()
    .MapApiControllers()
    .AddTables(
        new MobileAppTableConfiguration()
            .MapTableControllers()
            .AddEntityFramework()
    )
    .MapLegacyCrossDomainController()
    .ApplyTo(config);

使用する拡張メソッドは次のとおりです。

  • AddMobileAppHomeController() は、既定の Azure Mobile Apps ホーム ページを提供します。
  • MapApiControllers() は、[MobileAppController] 属性で修飾された WebAPI コントローラーのカスタム API 機能を提供します。
  • AddTables() は、テーブル コントローラーへの /tables エンドポイントのマッピングを提供します。
  • AddTablesWithEntityFramework() は、Entity Framework ベースのコントローラーを使用して /tables エンドポイントをマッピングするための簡単な方法です。
  • MapLegacyCrossDomainController() は、ローカル開発のための標準 CORS ヘッダーを提供します。

SDK 拡張機能

次の NuGet ベースの拡張機能パッケージでは、アプリケーションで使用可能な各種モバイル機能が提供されます。 拡張機能の有効化は、初期化中に MobileAppConfiguration オブジェクトを使用して行います。

  • Microsoft.Azure.Mobile.Server.Quickstart Mobile Apps の基本的なセットアップをサポートします。 構成に追加するには、初期化中に UseDefaultConfiguration 拡張機能メソッドを呼び出します。 この拡張機能には、Notifications、Authentication、Entity、Tables、Cross-domain、および Home パッケージが含まれています。
  • Microsoft.Azure.Mobile.Server.Home Web サイトのルートに、 このモバイル アプリが実行される既定のページ を実装します。 構成に追加するには、 AddMobileAppHomeController 拡張メソッドを呼び出します。
  • Microsoft.Azure.Mobile.Server.Tables データ処理のためのクラスが含まれており、データ パイプラインを設定します。 構成に追加するには、 AddTables 拡張メソッドを呼び出します。
  • Microsoft.Azure.Mobile.Server.Entity Entity Framework で SQL Database のデータにアクセスできるようにします。 構成に追加するには、 AddTablesWithEntityFramework 拡張メソッドを呼び出します。
  • Microsoft.Azure.Mobile.Server.Authentication 認証を有効にし、トークンの検証に使用する OWIN ミドルウェアを設定します。 構成に追加するには、AddAppServiceAuthentication 拡張メソッドと IAppBuilder.UseAppServiceAuthentication 拡張メソッドを呼び出します。
  • Microsoft.Azure.Mobile.Server.Notifications プッシュ通知を有効にし、プッシュ登録エンドポイントを定義します。 構成に追加するには、 AddPushNotifications 拡張メソッドを呼び出します。
  • Microsoft.Azure.Mobile.Server.CrossDomain モバイル アプリから従来の Web ブラウザーにデータを提供するコントローラーを作成します。 構成に追加するには、 MapLegacyCrossDomainController 拡張メソッドを呼び出します。
  • Microsoft.Azure.Mobile.Server.Login カスタム認証シナリオで使用される静的メソッドである AppServiceLoginHandler.CreateToken() メソッドを提供します。

サーバー プロジェクトを発行する

このセクションでは、Visual Studio から .NET バックエンド プロジェクトを発行する方法を示します。 アプリケーションを発行する方法は他にもあります。 詳細については、Azure App Service のドキュメントを参照してください。

  1. Visual Studio でプロジェクトをリビルドして、NuGet パッケージを復元します。
  2. ソリューション エクスプローラーで目的のプロジェクトを右クリックし、 [発行]をクリックします。
  3. このプロジェクトを発行したことがない場合は、発行を構成します。
    • ターゲットに [Azure] を選択します。
    • 特定のターゲットに [Azure App Service (Windows)] を選択します。
    • デプロイ先の App Service インスタンスを選択します。 ない場合は、[+] を使用して作成します。
    • [完了] をクリックします。
  4. SQL データベースをリンクしたことがない場合は、SQL Database の横にある [構成] をクリックします。
    • Azure SQL Database を選択します。
    • データベースを選択します。 ない場合、または別のデータベースを使用する場合は、[+] をクリックして新しいデータベースとサーバーを作成します。
    • データベース接続文字列名として、「MS_TableConnectionString」と入力します。 表示されるボックスに、ユーザー名とパスワードを入力します。
    • [完了] をクリックします。
  5. [発行] をクリックします。

Azure への発行には多少時間がかかります。 詳細については、Visual Studio のドキュメントを参照してください。

テーブル コントローラーを定義する

SQL テーブルをモバイル クライアントに公開するためのテーブル コントローラーを定義します。 テーブル コントローラーを構成するには、3 つの手順が必要です。

  1. データ転送オブジェクト (DTO) クラスを作成する。
  2. Mobile DbContext クラスにテーブル参照を構成する。
  3. テーブル コントローラーを作成する。

データ転送オブジェクト (DTO) は、 EntityDataから継承するプレーンな C# オブジェクトです。 次に例を示します。

public class TodoItem : EntityData
{
    public string Text { get; set; }
    public bool Complete {get; set;}
}

DTO を使用して、SQL データベース内にテーブルを定義します。 データベース エントリを作成するには、使用している DbContextDbSet<> プロパティを追加します。

public class MobileServiceContext : DbContext
{
    private const string connectionStringName = "Name=MS_TableConnectionString";

    public MobileServiceContext() : base(connectionStringName)
    {

    }

    public DbSet<TodoItem> TodoItems { get; set; }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Conventions.Add(
            new AttributeToColumnAnnotationConvention<TableColumnAttribute, string>(
                "ServiceColumnTable", (property, attributes) => attributes.Single().ColumnType.ToString()));
    }
}

最後に、新しいコントローラーを作成します。

  1. Controllers フォルダーを右クリックします。

  2. [Web API]>[Web API 2 コントローラー - 空] を選択します。

  3. コントローラーの名前を入力します。

  4. 新しいコントローラーの内容を次のコードに置き換えます。

    public class TodoItemController : TableController<TodoItem>
    {
        protected override void Initialize(HttpControllerContext controllerContext)
        {
            base.Initialize(controllerContext);
            ZUMOAPPNAMEContext context = new ZUMOAPPNAMEContext();
            DomainManager = new EntityDomainManager<TodoItem>(context, Request);
        }
    
        // GET tables/TodoItem
        public IQueryable<TodoItem> GetAllTodoItems()
        {
            return Query();
        }
    
        // GET tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
        public SingleResult<TodoItem> GetTodoItem(string id)
        {
            return Lookup(id);
        }
    
        // PATCH tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
        public Task<TodoItem> PatchTodoItem(string id, Delta<TodoItem> patch)
        {
            return UpdateAsync(id, patch);
        }
    
        // POST tables/TodoItem
        public async Task<IHttpActionResult> PostTodoItem(TodoItem item)
        {
            TodoItem current = await InsertAsync(item);
            return CreatedAtRoute("Tables", new { id = current.Id }, current);
        }
    
        // DELETE tables/TodoItem/48D68C86-6EA6-4C25-AA33-223FC9A27959
        public Task DeleteTodoItem(string id)
        {
            return DeleteAsync(id);
        }
    }
    

テーブルのページング サイズを調整する

既定では、Azure Mobile Apps は、要求ごとに 50 個のレコードを返します。 ページングにより、クライアントが長期間 UI スレッドまたはサーバーを占有することがなくなるため、優れたユーザー エクスペリエンスが保証されます。 テーブルのページング サイズを変更するには、サーバー側の "許可されているクエリ サイズ" とクライアント側のページ サイズを大きくします。サーバー側の "許可されているクエリ サイズ" は、EnableQuery 属性を使用して調整します。

[EnableQuery(PageSize = 500)]

PageSize が、クライアントから要求されるサイズ以上になるようにしてください。 クライアントのページ サイズを変更する方法の詳細については、特定のクライアントのハウツー ドキュメントを参照してください。

カスタム API コントローラーを定義する

カスタム API コントローラーは、エンドポイントを公開して、モバイル アプリのバックエンドに最も基本的な機能を提供します。 [MobileAppController] 属性を使用して、モバイル固有の API コント ローラーを登録できます。 MobileAppController 属性により、ルートが登録され、Mobile Apps JSON シリアライザーが設定されるほか、クライアント バージョン チェックがオンになります。

カスタム API コントローラーの内容は次のとおりです。

[MobileAppController]
public class CustomAPIController : ApiController
{
    // Content here
}

MobileAppController 属性を使用して構成したら、他の Web API と同じ方法でカスタム API を定義できます。

認証を操作する

Azure Mobile Apps は、App Service 認証/承認を使用してモバイル バックエンドをセキュリティで保護します。 このセクションでは、.NET バックエンド サーバー プロジェクトで以下の認証関連のタスクを実行する方法を説明します。

サーバー プロジェクトに認証を追加する

MobileAppConfiguration オブジェクトを拡張し、OWIN ミドルウェアを構成すると、サーバー プロジェクトに認証を追加することができます。

  1. Visual Studio で、 Microsoft.Azure.Mobile.Server.Authentication パッケージをインストールします。

  2. Startup.cs プロジェクト ファイルで、Configuration メソッドの先頭に次のコード行を追加します。

    app.UseAppServiceAuthentication(config);
    

    この OWIN ミドルウェア コンポーネントは、関連付けられている App Service ゲートウェイによって発行されたトークンを検証します。

  3. 認証が必要なすべてのコントローラーまたはメソッドに [Authorize] 属性を追加します。

アプリケーションにカスタム認証を使用する

重要

カスタム認証を有効にするには、まず、Azure Portal で App Service のプロバイダーを選択せずに App Service 認証を有効にする必要があります。 これにより、ホスト時に WEBSITE_AUTH_SIGNING_KEY 環境変数が有効になります。

App Service 認証/承認プロバイダーの中に使用したいものがない場合は、独自のログイン システムを実装できます。 認証トークンの生成に役立つ Microsoft.Azure.Mobile.Server.Login パッケージをインストールします。 ユーザー資格情報を検証するための独自のコードを指定します。 たとえば、データベース内のソルトを使用してハッシュ化されたパスワードと照合することができます。 次の例では、(他の場所に定義されている) isValidAssertion() メソッドがこれらの照合を実行します。

カスタム認証を公開するには、ApiController を作成し、register アクションと login アクションを公開します。 クライアントは、カスタム UI を使用してユーザーから情報を収集する必要があります。 その後、この情報は、標準の HTTP POST 呼び出しで API に送信されます。 サーバーでアサーションを検証したら、 AppServiceLoginHandler.CreateToken() メソッドを使用してトークンを発行します。 ApiController で [MobileAppController] 属性を使用することはできません

login アクションの例:

public IHttpActionResult Post([FromBody] JObject assertion)
{
    if (isValidAssertion(assertion)) // user-defined function, checks against a database
    {
        JwtSecurityToken token = AppServiceLoginHandler.CreateToken(new Claim[] { new Claim(JwtRegisteredClaimNames.Sub, assertion["username"]) },
            mySigningKey,
            myAppURL,
            myAppURL,
            TimeSpan.FromHours(24) );
        return Ok(new LoginResult()
        {
            AuthenticationToken = token.RawData,
            User = new LoginResultUser() { UserId = userName.ToString() }
        });
    }
    else // user assertion was not valid
    {
        return this.Request.CreateUnauthorizedResponse();
    }
}

前の例では、LoginResultLoginResultUser は、必要なプロパティを公開するシリアル化可能なオブジェクトです。 クライアントでは、ログインの応答が次の形式の JSON オブジェクトとして返されるものと想定されています。

{
    "authenticationToken": "<token>",
    "user": {
        "userId": "<userId>"
    }
}

AppServiceLoginHandler.CreateToken() メソッドには、audience パラメーターと issuer パラメーターが含まれています。 どちらのパラメーターも、HTTPS スキームを使用してアプリケーション ルートの URL に設定します。 同様に、secretKey をアプリケーションの署名キーの値に設定する必要があります。 キーを生成してユーザーを偽装するために使用される可能性があるため、クライアントで署名キーを配布しないでください。 App Service でホストされているときに署名キーを取得するには、WEBSITE_AUTH_SIGNING_KEY 環境変数を参照します。 ローカル デバッグの実行で必要な場合は、「 認証に関するローカル デバッグ 」セクションの手順に従ってキーを取得し、アプリケーション設定として保存します。

また、発行されたトークンには、他の要求および有効期限を含めることもできます。 少なくとも、発行されたトークンには、サブジェクト (sub) 要求が含まれている必要があります。

認証ルートをオーバーロードすることにより、標準クライアント loginAsync() メソッドをサポートできます。 クライアントが client.loginAsync('custom'); を呼び出してログインする場合、ルートは /.auth/login/custom である必要があります。 カスタム認証コントローラーのルートは、 MapHttpRoute()を使用して設定できます。

config.Routes.MapHttpRoute("custom", ".auth/login/custom", new { controller = "CustomAuth" });

ヒント

loginAsync() アプローチを使用すると、後続のサービスのすべての呼び出しに認証トークンが添付されます。

認証されたユーザー情報を取得する

ユーザーが App Service によって認証されると、.NET バックエンド コードで、割り当てられたユーザー ID とその他の情報にアクセスできます。 このユーザー情報を使用して、バックエンドで承認の決定を行うことができます。 次のコードは、要求に関連付けられているユーザー ID を取得します。

// Get the SID of the current user.
var claimsPrincipal = this.User as ClaimsPrincipal;
string sid = claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier).Value;

SID はプロバイダー固有のユーザー ID から派生し、特定のユーザーとログイン プロバイダーに対して静的です。 無効な認証トークンの SID は null です。

App Service では、ログイン プロバイダーからの特定の要求を行うこともできます。 各 ID プロバイダーは、ID プロバイダー SDK を使用してさらに多くの情報を提供できます。 たとえば、友人の情報については Facebook Graph API を使用できます。 Azure Portal のプロバイダー ブレードで、要求された要求を指定できます。 要求によっては、ID プロバイダーの追加の構成が必要です。

次のコードは、GetAppServiceIdentityAsync 拡張メソッドを呼び出して、ログイン資格情報を取得します。この情報には、Facebook Graph API に対する要求を行うために必要なアクセス トークンが含まれています。

// Get the credentials for the logged-in user.
var credentials = await this.User.GetAppServiceIdentityAsync<FacebookCredentials>(this.Request);

if (credentials.Provider == "Facebook")
{
    // Create a query string with the Facebook access token.
    var fbRequestUrl = "https://graph.facebook.com/me/feed?access_token="
        + credentials.AccessToken;

    // Create an HttpClient request.
    var client = new System.Net.Http.HttpClient();

    // Request the current user info from Facebook.
    var resp = await client.GetAsync(fbRequestUrl);
    resp.EnsureSuccessStatusCode();

    // Do something here with the Facebook user information.
    var fbInfo = await resp.Content.ReadAsStringAsync();
}

GetAppServiceIdentityAsync 拡張メソッドを提供するには、System.Security.Principal の using ステートメントを追加します。

承認されたユーザーに対するデータ アクセスを制限する

前のセクションでは、認証されたユーザーのユーザー ID を取得する方法について説明しました。 この値に基づいて、データとその他のリソースへのアクセスを制限できます。 たとえば、UserId 列をテーブルに追加して、ユーザー ID によってクエリの結果をフィルター処理すると、承認されたユーザーだけにデータが返されるように簡単に制限できます。 次のコードは、SID が TodoItem テーブルの UserId 列の値と一致する場合にのみデータ行を返します。

// Get the SID of the current user.
var claimsPrincipal = this.User as ClaimsPrincipal;
string sid = claimsPrincipal.FindFirst(ClaimTypes.NameIdentifier).Value;

// Only return data rows that belong to the current user.
return Query().Where(t => t.UserId == sid);

Query() メソッドは、フィルター処理を行うために LINQ で操作できる IQueryable を返します。

.NET サーバー SDK のデバッグとトラブルシューティングを実行する

Azure App Service には、ASP.NET アプリケーションのデバッグとトラブルシューティングの方法が複数用意されています。

Logging

標準の ASP.NET トレース書き込みを使用して、App Service の診断ログを作成できます。 ログに書き込めるようにするには、Azure Mobile Apps バックエンドで診断を有効にする必要があります。

診断を有効にしてログに書き込むには、次の手順を実行します。

  1. アプリケーションのログ記録を有効にする (Windows)」の手順に従います。

  2. 次の using ステートメントをコード ファイルに追加します。

    using System.Web.Http.Tracing;
    
  3. .NET バックエンドから診断ログに書き込むために、次のようにトレース ライターを作成します。

    ITraceWriter traceWriter = this.Configuration.Services.GetTraceWriter();
    traceWriter.Info("Hello, World");
    
  4. サーバー プロジェクトを再発行し、Azure Mobile Apps バックエンドにアクセスして、ログ記録付きでコード パスを実行します。

  5. ログ ファイルにアクセスする」で説明されているように、ログをダウンロードして評価します。

認証に関するローカル デバッグ

クラウドに発行する前に変更をテストするために、ローカルでアプリケーションを実行できます。 ほとんどの Azure Mobile Apps バックエンドでは、Visual Studio で F5 キーを押します。 ただし、認証を使用している場合は追加の考慮事項がいくつかあります。

App Service Authentication/Authorization を使用してクラウド ベースのモバイル アプリを構成する必要があります。また、クライアントに代替ログイン ホストとしてクラウド エンドポイントを指定する必要があります。 必要な手順の詳細については、クライアント プラットフォームのドキュメントを参照してください。

モバイル バックエンドに Microsoft.Azure.Mobile.Server.Authentication がインストールされていることを確認します。 次に、MobileAppConfigurationHttpConfiguration に適用された後で、アプリケーションの OWIN Startup クラスに次のコードを追加します。

app.UseAppServiceAuthentication(new AppServiceAuthenticationOptions()
{
    SigningKey = ConfigurationManager.AppSettings["authSigningKey"],
    ValidAudiences = new[] { ConfigurationManager.AppSettings["authAudience"] },
    ValidIssuers = new[] { ConfigurationManager.AppSettings["authIssuer"] },
    TokenHandler = config.GetAppServiceTokenHandler()
});

前の例では、Web.config ファイル内のアプリケーション設定 authAudienceauthIssuer を、HTTPS スキームを使用して、それぞれアプリケーション ルートの URL に構成する必要があります。 同様に、authSigningKey をアプリケーションの署名キーの値に設定する必要があります。

署名キーを取得するには、次の手順を実行します。

  1. Azure ポータル
  2. [ツール]>[Kudu]>[移動] をクリックします。
  3. Kudu 管理サイトで、 [環境]をクリックします。
  4. WEBSITE_AUTH_SIGNING_KEY の値を見つけます。

ローカル アプリケーション構成で、authSigningKey パラメーターに署名キーを使用します。モバイル バックエンドには、現在、ローカルでの実行時にトークンを検証する機能が備わっています。このトークンは、クライアントによってクラウドベースのエンドポイントから取得されます。