Quantcast
Channel: かずきのBlog@hatena
Viewing all articles
Browse latest Browse all 1387

SignalR を Windows Mixed Reality で使いたい

$
0
0

SignalR は簡単に言うと WebSocket とかをいい感じに隠してくれてサーバーからクライアント(Webやネイティブアプリなど)に対して処理を実行することが出来るライブラリです。

最近は ASP.NET Core でも使えるようになってるんですね。私が前にやってたときは ASP.NET でやってました。

こっちが ASP.NET Core で

docs.microsoft.com

こっちがクラシカルな ASP.NET のほうですね

docs.microsoft.com

便利なんです

Web 系の技術をベースに実装されたリモートプロシージャーコールのライブラリなので非常に便利なんですよね。 サーバーからクライアントに一斉に指示をばらまいたりとかなんとか。ということで Windows Mixed Reality でも使いたい!!ってことで試してみました。

よく見てないんですが ASP.NET Core SignalR って ASP.NET Core 2.1 Preview に依存してるんですかね?

docs.microsoft.com

.NET core 2.1.0 Preview 1 SDK以降
Visual Studio 2017 15.6 またはそれ以降のバージョン、 ASP.NET および web 開発ワークロード
npm

まだプレビューならとりあえず今回は古き良きほうで試してみたいと思います。

サーバーサイドの準備

ではサーバーを用意しましょう。 ASP.NET MVC の空のプロジェクトをさくっと作ります。

そして NuGet から SignalR のライブラリを追加しましょう。Microsoft.AspNet.SingalR ですね。

SingalR 2.x 系は Owin 使ってるんですかね?ということで NuGet でインストールしたら表示される readme に従って Startup クラスを作ります。

OWIN Startup クラスというテンプレートが Visual Studio にあるので、それを使ってさくっと作りましょう。 MapSignalR を呼びます(自分がしてたころは MapHub とかいうメソッドだった気がする)

using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(SignalRServer.Startup))]

namespace SignalRServer
{
    publicclass Startup
    {
        publicvoid Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

確か、このスタートアップクラスは Microsoft.Owin.Host.SystemWeb とかが入ってないと動かなかった気がするので何か動かないなぁって人はチェックしてみましょう。

では、Hubを作りましょう。今回はクライアントに対して Cube を出せ!ってサーバーから命令するようなのを作りたいなぁと思ったのでそういうハブを1つ作りました。

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace SignalRServer.Hubs
{
    [HubName("createCubeHub")]
    publicclass CreateCubeHub : Hub
    {
        publicvoid CreateCube()
        {
            Clients.All.create("Cube");
        }
    }
}

今回は Clients.All を使ってつないでる人全員に命令を投げてます。特定のグループに対して送るとか制御もできるので実際には、グループを作って特定の人達に指示を投げるみたいなのになるんでしょうね。

あとは、この Hub をたたく Web 画面を作ります。 HomeController とかを作って View を適用に用意しましょう。 SignalR 関連の JavaScript を jquery のあとに読み込む必要があるので追加します。 とりあえず、普通に Visual Studio にお願いして各種 View を作っていたら _Layout.cshtml というのが出来てるはずなので、そこの jquery を読み込んでる src タグの下らへんに2つの script タグを追加します。

あと、スクリプトが全部読み込まれた後に自前のスクリプトを読み込むためのセクションも追加するために @RenderSectionも追加しておきます。

<scriptsrc="~/Scripts/jquery-1.10.2.min.js"></script><scriptsrc="~/Scripts/bootstrap.min.js"></script><!-- ここから追加するやつ --><scripttype="text/javascript"src="~/Scripts/jquery.signalR-2.2.3.min.js"></script><scriptsrc="~/signalr/hubs"></script>
    @RenderSection("script")
    <!-- ここまで追加するやつ -->

重要なのは jquery の後に signalr 系のものを読み込むことなので、_Layout.cshtml を使ってない場合には Index.cshtml とかに全部まとめて書いても OK です。

View の中で以下のような感じで SignalR の Hub の CreateCube メソッドを叩く処理を書きます。

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2><buttonid="createCubeButton">Create cube</button>

@section script {
    <scripttype="text/javascript">        $(function(){            $.connection.hub.start().done(function(){                $('#createCubeButton').click(invokeCreateCube);});});function invokeCreateCube(){            $.connection.createCubeHub.server.createCube();}</script>
}

これだけでサーバーの CreateCube メソッドを呼べるのはお手軽ですね。サーバーの CreateCube ではクライアントの create メソッドを叩いてるって感じのコード書いてるので、これで Web 画面からクライアントの create メソッドを叩く下準備が出来ました。

一応ここらへんで、CreateCubeHub クラスの CreateCube メソッドにブレークポイントをはって実行して画面のボタンを押すとブレークポイントで止まるかというのを確認しておくとあとがスムーズだと思います。

デプロイ!

では Windows MR デバイスからアクセスできるところ(ローカルのネットワーク内でもお手持ちのクラウドサーバー上でもなんでも)に、上記のアプリをデプロイそてきましょう。次はいよいよ Windows MR 側の話になります。

Windows MR 側

ついに Windows MR 側の世界に来ました。長かった。 Unity で適当にプロジェクトを作ります。

各種設定がめんどくさいので MRTK を入れて MRTK のメニューからプロジェクトとシーンの設定をしてしまいましょう。 注意点はインターネットにつなぐので Capability で Internet Client にチェックを入れておきます。

そして、シーンに空のゲームオブジェクトを1つ作って SignalRManager とかいう名前で作りましょう。 そして、SignalRManager とかいう名前で C# のスクリプトを作成して先ほど作成した SignalRManager というスクリプトにアタッチしておきます。

準備ができたので、UWPのプロジェクトを Unity からビルドして出力しましょう。 出力先でゴリゴリコードを書くので Unity C# Project にはチェックを入れておくのを忘れずに。

f:id:okazuki:20180426115524p:plain

出力したプロジェクトを Visual Studio で開いたら Microsoft.AspNet.SignalR.Client を NuGet から出力されたプロジェクトに対して追加します。

ここらへんは新規に Visual Studio のプロジェクト吐き出したらまたやらないといけないので、何らかの簡略化の仕組みは本番では取り入れておくといいと思います。以下のような感じで。

以下のは、私のやったゴリゴリ project.json をビルドプロセスのあとに書き換えるアプローチ。

blog.okazuki.jp

以下のは、インストールする NuGet ライブラリをインストールする PowerShell のスクリプトを用意しておいて、再作成後は一発それを叩けば OK な状態にしておくアプローチ

[http://yotiky.hatenablog.com/entry/2018/04/26/HoloLensNuGetUWP向けのLibrary_を利用したい:embed:cite]

とりあえず今回は手動で追加します。

追加したら SignalRManager.cs を以下のようにしましょう。単純につないで SignalR から何か呼ばれたらものを作るといった感じにしています。

using UnityEngine;
using System;
using System.Threading;

#if UNITY_UWPusing Microsoft.AspNet.SignalR.Client;
#endifpublicclass SignalRManager : MonoBehaviour
{
#if UNITY_UWPprivate HubConnection _connection;
    private SynchronizationContext _unityThreadContext;


    privatevoid Start()
    {
        // Unity のメインスレッドの SynchronizationContext をとっておく
        _unityThreadContext = SynchronizationContext.Current;
        InitializeConnection();
    }


    privatevoid InitializeConnection()
    {
        // SignalR を配備した先の URL (例は Azure 上の Web app に配備した場合)
        _connection = new HubConnection("http://<your site name>.azurewebsites.net/");
        var createCubeProxy = _connection.CreateHubProxy("createCubeHub");
        createCubeProxy.On<string>("create", Create);
        _connection.Start().ContinueWith(x =>
        {
            UnityEngine.Debug.Log(x.Exception?.Message ?? "Connected");
        });
    }

    privatevoid Create(string name)
    {
        // Unity のメインスレッド上で処理しないとまずいと思うので
        _unityThreadContext.Post(_ =>
        {
            PrimitiveType type;
            if (!Enum.TryParse<PrimitiveType>(name, out type))
            {
                UnityEngine.Debug.LogWarning($"{name} is not defined.");
                return;
            }
            var obj = GameObject.CreatePrimitive(type);
            obj.transform.position = Camera.main.transform.position + Camera.main.transform.forward * 3;
            UnityEngine.Debug.Log($"{name} created at {obj.transform.position}");
        }, null);
    }
#endif
}

これで完成です。実行すると以下のようになります。

https://github.com/runceel/WinMRSignalR/blob/master/movie.gif?raw=true

まとめ

すなおに NuGet 使いたい欲が高まりますね。


Viewing all articles
Browse latest Browse all 1387

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>