Show / Hide Table of Contents

    一旦我们实现了grain类型,我们就可以写一个客户端应用来说使用这个类型。

    下面的来自[SDK-ROOT]\Binaries\PresenceClient_ or _[SDK-ROOT]\Samples\References目录的Orleans DLL需要引入到客户端的应用工程中:

    • Orleans.dll
    • OrleansRuntimeInterfaces.dll

    几乎任何客户端都会用到grain的工厂类。 GetGrain()用来得到一个特定ID的grain引用。 就像之前所说的,grain不能够显式地创建和销毁。

    GrainClient.Initialize();
    
    // 硬编码了玩家ID
    Guid playerId = new Guid("{2349992C-860A-4EDA-9590-000000000006}");
    IPlayerGrain player = GrainClient.GrainFactory.GetGrain<IPlayerGrain>(playerId);
    
    IGameGrain game = player.CurrentGame.Result;
    var watcher = new GameObserver();
    var observer = GrainClient.GrainFactory.CreateObjectReference<IGameObserver>(watcher);
    await game.SubscribeForGameUpdates();
    

    如果这段代码用在控制台应用的主线程,你需要在game.SubscribeForGameUpdates()返回后调用Wait(),因为await不会组织 Main()函数返回,这样会使进程退出。

    阅读关键概念部分来获取更多Task执行调度和异常流的不同用法的细节。

    找到或者创建grain

    在通过调用GrainClient.Initialize()创建链接后,泛型工厂类中的静态方法可以用来获取一个grain的引用,例如GrainClient.GrainFactory.GetGrain<IPlayerGrain>()来获取PlayerGrain。grain接口作为类参数传递给GrainFactory.GetGrain<T>()。

    向grain发送消息

    客户端与grain的通信编程模型跟grain之间的通信编程模型一样。 client持有一个实现了grain接口IPlayerGrain的grain引用。 它调用那个grain引用或者其他继承自IGrain的grain接口的方法,并且这些方法有异步返回值Task/Task<T>。 当这些异步返回值求值得时候,客户端可以使用await关键字或者ContinueWith()方法来伫列被运行的延续体,或者使用Wait()方法阻塞当前线程。

    一个客户端与grain的通信和grain与grain的通信关键的不同是单线程执行模型。 grain被Orleans调度器线支撑单线程的,但是客户端可能是多线程的。 客户端库使用TPL线程池来管理延续提或者毁掉,并且客户端根据自身环境适用什么同步机制(锁、事件、TPL任务、等等)来自由决定使用什么方法管理它自己的并发。

    收到通知

    有些情况下简单的消息/响应模式是不够的,并且客户端需要收到异步通知。 例如,一个用户可能想要在他粉的某人发布新消息的时候收到通知。

    观察者是一个单向实现了IGrainObserver的单向异步接口,并且它的所有的方法都必须是void的。 grain通过像调用grain接口的方法一样调用观察者的方法来发送一个通知给观察者,不同是观察者方法没有返回值并且grain不会以来调用结果。 Orleans运行时将会确保单向传递通知的成功。 发布通知的grain应该提供API来添加或者删除观察者。

    想要订阅通知,客户端必须首先创建一个本地的实现了观察者接口的C#对象。 然后调用grain工厂的CreateObjectReference()将C#对象转换成一个grain引用,之后会被传递给通知grain上的订阅方法。

    这个模型也可以被其他的grain使用来接收异步通知。 不像客户端订阅的情况,订阅的grain只要实现观察者接口,并且把自身作为一个引用传递给自己(例如this.AsReference<IChirperViewer>)。

    举例

    这里是一个上面给出的客户端应用连接Orleans的扩展版本,找到玩家账号,订阅玩家所在的游戏的会话的更新,并且打印出通知,直到程序被手动关闭。

    namespace PlayerWatcher
    {
        class Program
        {
            /// <summary>
            /// Simulates a companion application that connects to the game
            /// that a particular player is currently part of, and subscribes
            /// to receive live notifications about its progress.
            /// </summary>
            static void Main(string[] args)
            {
                try
                {
                    GrainClient.Initialize();
    
                    // Hardcoded player ID
                    Guid playerId = new Guid("{2349992C-860A-4EDA-9590-000000000006}");
                    IPlayerGrain player = GrainClient.GrainFactory.GetGrain<IPlayerGrain>(playerId);
                    IGameGrain game = null;
    
                    while (game == null)
                    {
                        Console.WriteLine("Getting current game for player {0}...", playerId);
    
                        try
                        {
                            game = player.CurrentGame.Result;
                            if (game == null) // Wait until the player joins a game
                                Thread.Sleep(5000);
                        }
                        catch (Exception exc)
                        {
                            Console.WriteLine("Exception: ", exc.GetBaseException());
                        }
                    }
    
                    Console.WriteLine("Subscribing to updates for game {0}...", game.GetPrimaryKey());
    
                    // Subscribe for updates
                    var watcher = new GameObserver();
                    game.SubscribeForGameUpdates(GrainClient.GrainFactory.CreateObjectReference<IGameObserver>(watcher)).Wait();
    
                    // .Wait will block main thread so that the process doesn't exit.
                    // Updates arrive on thread pool threads.
                    Console.WriteLine("Subscribed successfully. Press <Enter> to stop.");
                    Console.ReadLine();
                }
                catch (Exception exc)
                {
                    Console.WriteLine("Unexpected Error: {0}", exc.GetBaseException());
                }
            }
    
            /// <summary>
            /// Observer class that implements the observer interface.
            /// Need to pass a grain reference to an instance of this class to subscribe for updates.
            /// </summary>
            private class GameObserver : IGameObserver
            {
                // Receive updates
                public void UpdateGameScore(string score)
                {
                    Console.WriteLine("New game score: {0}", score);
                }
            }
        }
    }
    

    Next

    运行一个应用

    • Improve this Doc
    Back to top Copyright © 2015-2016 Microsoft
    Generated by DocFX