miso_soup3 Blog

主に ASP.NET 関連について書いています。

Microsoft Azure モバイルサービスで .NET Backend SignalR を試す

Microsoft Azure モバイルサービスの .NET Backend(プレビュー) が SignalR に対応しました。モバイル開発にリアルタイム要素をプラスできます。これで ASP.NET Web API と SignalR の双方に対応となりました。

機能

.NET Backend の SignalR では以下のことができるみたいです。

  • .NET Backend ASP.NET Web API と同じように、
    • 認証属性[RequiresAuthorization(AuthorizationLevel.User)]が使える。
    • Dependency Injection は Autofac を使用
  • ASP.NET Web API の API コントローラーやスケジュール定義クラスから SignalR の Hub にアクセス可能。(ApiService に登録されている。)
  • スケールアウト

ということで試してみましたので手順を記載します。クライアント側はストアアプリで。やってみての感想ですが、スケジューラーから SignalR の Hub にアクセスできるのは面白いなと思いました。

目次
  • プロビジョニングとサンプルコードの入手
  • サーバー側 : SignalR Hub の登録
    • NuGet パッケージの追加と更新
    • SignalR の設定
    • Hub を追加
    • スケジューラーから Hub へアクセスする
    • モバイルサービスへ発行
  • クライアント側 : SignalR Hub への接続
    • NuGet パッケージの追加
    • モバイルサービスへの接続
    • SignalR Hub への接続
  • 実行

プロビジョニングとサンプルコードの入手

Windows Azure モバイルサービスで ASP.NET Web API を試す ~とりあえずサンプル実行~ - miso_soup3 の「1.プロビジョニングとサンプルコードの入手」と同じ手順を行い、プロジェクトを用意します。(サンプルコードは現在、ASP.NET Web API と ストアアプリで、SignalR 関連のコードはありません。)

サーバー側 : SignalR Hub の登録

NuGet パッケージの追加と更新

サーバー側のプロジェクト「**Service」で以下の NuGet パッケージの更新と追加を行います。

SignalR の設定

「App_Start」フォルダにある「WebApiConfig.cs」にコード「SignalRExtensionConfig.Initialize();」を追加します。

using System.Collections.Generic;
using System.Data.Entity;
using System.Web.Http;
using Microsoft.WindowsAzure.Mobile.Service;
using hiroboService.DataObjects;
using hiroboService.Models;
using Microsoft.WindowsAzure.Mobile.Service.Config;

namespace hiroboService
{
    public static class WebApiConfig
    {
        public static void Register()
        {
			// Initialize SignalR
			SignalRExtensionConfig.Initialize();
			// ...既存コード
Hub を追加

サーバー側のプロジェクト「**Service」に次のように Hub クラスを追加します。クライアント側から送信されてきた message を、サーバー側からクライアント側全員に送信します。

SignalR の Hub についてはこちらをどうぞ。
Hubs API Guide - Server (C#) : The Official Microsoft ASP.NET Site

using Microsoft.AspNet.SignalR;
using Microsoft.WindowsAzure.Mobile.Service;

namespace hiroboService.Hubs
{
	public class ChatHub : Hub
	{
		public ApiServices Services { get; set; }

		public void Send(string message)
		{
			Clients.All.hello("Hello from SignalR Chat Hub! message : " + message);
		}
	}
}

ApiService はインジェクションによりインスタンスが入るようになってます。

スケジューラーから Hub へアクセスする

スケジューラーを実行した時に、先ほど定義した SignalR の Hub にアクセスしクライアント側へメッセージを送信してみます。
(スケジューラーとは Microsoft Azure モバイルサービスの機能のスケジューラーのことです。)(ちなみに、Real-time with ASP.NET SignalR and Azure Mobile .NET Backend にあるサンプルコードでは API Controller から Hub へアクセスしています。ほぼ同じことをします。)

「ScheduledJobs」フォルダ内の「SampleJob.cs」で次のようにコードを追加します。

using System.Threading.Tasks;
using System.Web.Http;
using Microsoft.WindowsAzure.Mobile.Service;
using hiroboService.Hubs;
using Microsoft.AspNet.SignalR;

namespace hiroboService
{
    // A simple scheduled job which can be invoked manually by submitting an HTTP
    // POST request to the path "/jobs/sample".

    public class SampleJob : ScheduledJob
    {
        public ApiServices Services { get; set; }

        public override Task ExecuteAsync()
        {
            //signalR 
            IHubContext hubContext = Services.GetRealtime<ChatHub>();
            hubContext.Clients.All.hello("Hello from ScheduledJob!");

            Services.Log.Info("Hello from scheduled job!");
            return Task.FromResult(true);
        }
    }
}

Service プロパティを追加しましたが、こちらもインジェクションによりインスタンスが入るようになってます。

モバイルサービスへ発行

サーバー側は以上です。モバイルサービスへ発行します。手順は Windows Azure モバイルサービスで ASP.NET Web API を試す ~とりあえずサンプル実行~ - miso_soup3 の「4.デプロイする」に記載しています。(Visual Studio 2013 は Update 2 の適用が必要です。)

クライアント側 : SignalR Hub への接続

次はクライアント側、Windows ストアアプリのプロジェクトのコードを変更します。

NuGet パッケージの追加

次の NuGet パッケージを追加します。
(サーバー側のプロジェクトではなく、ストアアプリのプロジェクトでインストールするように注意)

モバイルサービスへの接続

「App.xaml.cs」の最初の方で、次のようにローカルではなく Microsoft Azure モバイルサービスの方へ接続するようコメントアウト&解除します。

    sealed partial class App : Application
    {
        // This MobileServiceClient has been configured to communicate with your local
        // test project for debugging purposes. Comment out this declaration and use the one
        // provided below when you are done developing and deploy your service to the cloud.
		//public static MobileServiceClient MobileService = new MobileServiceClient(
		//	"http://localhost:50003"
		//);

        // This MobileServiceClient has been configured to communicate with your Mobile Service's url
        // and application key. You're all set to start working with your Mobile Service!
		public static MobileServiceClient MobileService = new MobileServiceClient(
			"https://****.azure-mobile.net/",
			"****************************************"
		);
SignalR Hub への接続

「MainPage.xaml.cs」の MainPage クラスで次のように「hubConnection」変数を定義します。

using Microsoft.AspNet.SignalR.Client;

    public sealed partial class MainPage : Page
    {
        private MobileServiceCollection<TodoItem, TodoItem> items;
        private IMobileServiceTable<TodoItem> todoTable = App.MobileService.GetTable<TodoItem>();
        private HubConnection hubConnection;

同じクラスの「MainPage.xaml.cs」に次のように ConnectToSignalR() メソッドを追加します。

private async Task ConnectToSignalR()
{
	//接続
	hubConnection = new HubConnection(App.MobileService.ApplicationUri.AbsoluteUri);
	hubConnection.Headers["x-zumo-application"] = App.MobileService.ApplicationKey;

	IHubProxy proxy = hubConnection.CreateHubProxy("ChatHub");
	await hubConnection.Start();


	//"hello":サーバー側から送信されてきたとき
	proxy.On<string>("hello", async msg =>
	{
		await this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
			async () =>
			{
				var callbackDialog = new MessageDialog(msg);
				callbackDialog.Commands.Add(new UICommand("OK"));
				await callbackDialog.ShowAsync();
			});
	});

	//"Send" : サーバー側に送信する
	await proxy.Invoke<string>("Send", "Hello World!");			
}

.NET Backend 側の Signal Hub ではデフォルトで認証がかかっているので、ヘッダー「"x-zumo-application"」にアプリケーションキーを設定しています。

既存の OnNavigatedTo(..) メソッドで ConnectToSignalR(); を呼び出します。

protected override async void OnNavigatedTo(NavigationEventArgs e)
{
    RefreshTodoItems();
    await ConnectToSignalR();
}

ストアアプリ側は以上です。

実行

ストアアプリをローカルで実行します。
ダイアログが出て、SignalR Hub を呼び出したことがわかります。

f:id:miso_soup3:20140608160221p:plain

「OK」ボタンをクリックして、そのままアプリを起動しておきます。

モバイルサービスの管理ポータルから、スケジューラーを実行してみます。(SampleJob.cs で定義したスケジューラー)
「一度だけ実行する」をクリック。

f:id:miso_soup3:20140608000959p:plain

(スケジューラーを登録していない場合は、 Windows Azure モバイルサービスで ASP.NET Web API を試す ~とりあえずサンプル実行~ - miso_soup3 の「6.スケジューラーを試す」を参考に作成します。)

すると、ストアアプリ側で「Hello from ScheduledJob !」とダイアログが表示されるはずです。

f:id:miso_soup3:20140608001155p:plain


ダイアログではなくローカルのトースト通知でもでやってみました。

f:id:miso_soup3:20140608003532p:plain

トースト通知については以下のサイトを参考にしました。

Windowsストアアプリ:トーストのローカル通知 | 眠るシーラカンスと水底のプログラマー

Quickstart: Using the NotificationsExtensions library in your code (XAML) (Windows)