Orleans之Hello World


接觸Orleans 有一段時間了,之前也翻譯了一系列官網文檔,今天我們就來一個實際的例子,來看看到底如何用這個東西來開發項目,當然經典的也是醉人的,我們就從HelloWorld開始吧。

通過前面的知識准備我們知道Orleans 項目需要n個服務端(就是silohost),n個客戶端(就是調用方),然后就是提供的actors(在Orleans 中成為grain),廢話少說。

首先建立一個解決方案,叫做OrleansSamples

然后,增加一個模塊解決方案,叫做HelloWorlds,在解決方案下增加兩個類庫Sample.Interfaces,Sample.Implements,其中Sample.Implements引用Sample.Interfaces,

這兩個項目中引用Orleans的核心庫,你可以手動一個一個引用進來,但還是老老實實的用nuget吧。

nuget的引用兩種方式一種,通過圖形化的方式,另一種通過命令的方式,命令:Install-Package Microsoft.Orleans.Core (注:在這里可以找到所需的包http://dotnet.github.io/orleans/NuGets)

記得引用完后如果在nuget里有更新就更新一下,對於新版本,可能里面有些庫會沒有進來,否則就會報錯,反正我是這么做,做完這一切,項目結構如下:

在Sample.Interfaces中增加一個接口IUserService,並且繼承接口IGrainWithIntegerKey(關於這個接口有姊妹接口,關於這些接口后續會陸續講到)

代碼如下:

namespace Sample.Interfaces
{
  public interface IUserService:IGrainWithIntegerKey
  {
    Task<bool> Exist(string mobileNumber);
  }
}

在Sample.Implements項目中增加實現類UserService,並且繼承Grain(Grain這個基類同時也提供了相應的泛型實現Grain<>,關於他們的不同點,以及功能,后續會講到),且實現IUserService接口

代碼如下:

namespace Sample.Implements
{
  public class UserService : Grain, IUserService
  {
    public Task<bool> Exist(string mobileNumber)
    {
      return Task.FromResult<bool>(mobileNumber=="18612478956");
    }
  }
}

好了到此為止,我們已經開發好actor雖然簡單,接下來我們接着增加服務啟動寄宿項(關於寄宿項,可以是控制台、windows服務、winfrom、asp.net ),這里我們采用控制台,下面我們創建一個服務控制台應用程序(Server)

引用上面創建兩個項目:Sample.Implements、Sample.Interfaces。(注:其實這兩個項目不一定要引用進來,只要在生成項目的目錄下存在他們的編譯好的dll即可,silo用來自動加載啟動這個他們)

引用orleans項目中服務端的類庫(使用nuget命令:Install-Package Microsoft.Orleans.Server

項目結構如下:

代碼如下:

namespace Server
{
  class Program
  {
    static void Main(string[] args)
    {
      using (var host = new SiloHost("Default"))
      {
        host.InitializeOrleansSilo();
        host.StartOrleansSilo();
        Console.WriteLine("啟動成功!");
        Console.ReadLine();
        host.StopOrleansSilo();
      }
    }
  }
}

 

好一切准備就緒,我們F5吧,

當你看到這得時候是不是覺得成功了,真的成功了嗎,不一定吧!

哦對了怎么沒看到日志呢,好我們在項目目錄下看看日志:

果然有日志文件,一看文件名稱,直接告訴我們發生錯誤了,好讓我們打開看看吧。

從發生的異常看出,好像少了一個配置文件,在orleans 服務啟動時,需要一個配置文件,這個配置文件可以是OrleansConfiguration.xml或者orleans.config或者orleans.config.xml

好知道原因了,知道該怎么做了吧,在server根目錄下創建一個xml文件OrleansConfiguration.xml,將該文件的屬性“復制到輸出目錄”值更改為"如果較新則復制"

該文件中填充配置內容,如下(詳細配置請看配置一節,此處不解釋)

<?xml version="1.0" encoding="utf-8" ?>
<OrleansConfiguration xmlns="urn:orleans">
<Globals>
<StorageProviders>
<Provider Type="Orleans.Storage.MemoryStorage" Name="MemoryStore" />
<Provider Type="Orleans.Storage.MemoryStorage" Name="Default" />
<!--<Provider Type="Orleans.Storage.AzureTableStorage" Name="AzureStore"/>-->
</StorageProviders>
<SeedNode Address="localhost" Port="22222"/>
<Messaging ResponseTimeout="30s"/>
</Globals>
<Defaults>
<Networking Address="localhost" Port="22222"/>
<ProxyingGateway Address="localhost" Port="40000" />
<Tracing DefaultTraceLevel="Info" TraceToConsole="false" TraceToFile="{0}-{1}.log" PropagateActivityId="false" BulkMessageLimit="1000">
<TraceLevelOverride LogPrefix="Application" TraceLevel="Info" />
<!--
<TraceLevelOverride LogPrefix="Runtime.Dispatcher" TraceLevel="Verbose" />
<TraceLevelOverride LogPrefix="AssemblyLoader.Silo" TraceLevel="Warning" />
-->
</Tracing>
<Statistics MetricsTableWriteInterval="30s" PerfCounterWriteInterval="30s" LogWriteInterval="300s" WriteLogStatisticsToTable="true" StatisticsCollectionLevel="Info"/>
</Defaults>
</OrleansConfiguration>
View Code

 

再次啟動F5,當看到啟動成功的輸出時,我們再次看看生成的日志:

這次發現比之前生成的東西多了,但是當我們繼續往下瀏覽的時候發現有個異常:

Exc level 0: System.IO.FileNotFoundException: 未能加載文件或程序集“Microsoft.Extensions.DependencyInjection.Abstractions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60”或它的某一個依賴項。系統找不到指定的文件。
在 Orleans.Runtime.Startup.ConfigureStartupBuilder.ConfigureStartup(String startupTypeName)
在 Orleans.Runtime.Startup.ConfigureStartupBuilder.Orleans.Runtime.Startup.IStartupBuilder.ConfigureStartup(String startupTypeName)
在 Orleans.Runtime.Silo..ctor(String name, SiloType siloType, ClusterConfiguration config, ILocalDataStore keyStore)

原來是少了程序集:Microsoft.Extensions.DependencyInjection

知道原因了,我們通過nuget來引用這個類庫,引用成功,再次運行,然后查看日志,異常消失,但是有個問題,每次打開日志文件要看,是否有錯誤,或者一些關於服務的監控內容,這樣是不是很麻煩,其實我們可以更改一下配置信息,讓它輸出到控制台,這樣在開發過程中就方便多了,可以時時看到動態信息,如下:

打開OrleansConfiguration.xml 文件找到<Tracing DefaultTraceLevel="Info" TraceToConsole="false" TraceToFile="{0}-{1}.log" 這個節點,將TraceToConsole的值更改為true保存,再次運行,如下:

好了一切都完美了,接下來我們在繼續開發客戶端。

 

在解決方案下創建一個控制台應用程序Client,引用客戶端相關類庫:Install-Package Microsoft.Orleans.Client

引用項目:Sample.Interfaces

代碼如下:

namespace Client
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Threading.Thread.Sleep(15000);
            GrainClient.Initialize();

            while (true)
            {
                Console.WriteLine("請輸入用戶手機號:");
                var mobileNumber = Console.ReadLine();
                //這里由於我們采用的grain繼承的是IGrainWithIntegerKey ,所以我們采用調用數值類型的key=10來創建這個grain,
                //可能有人會問key是干嘛的,他是唯一標識這個grain的,當你指定一個key的時候,Orleans 會創建一個,它首先到
                //你的存儲介質中找(如果你配置了的話,默認采用內存存儲,這種方式適合開發期,生產環境需要保持狀態的,所以需要配置到能持久化存儲的地方去,比如sqlserver等)
                //如果找到了就直接返回,如果沒找到就根據你指定的這個key然后創建一個,這個就是grain的激活,具體詳細的,可以看官方問的關於Grain一章。
                var userService = GrainClient.GrainFactory.GetGrain<IUserService>(10);
                //C#的一種新的表達式語法,這樣就方便多了,省的我們拼接字符串。
                Console.WriteLine($"用戶{mobileNumber},{(userService.Exist(mobileNumber).Result?"已經存在":"不存在")}");
            }

        }
    }
}
View Code

 

在client項目下記得要創建配置文件,文件名稱叫做ClientConfiguration.xml

內容如下:

<?xml version="1.0" encoding="utf-8" ?>
<ClientConfiguration xmlns="urn:orleans">
  <Gateway Address="localhost" Port="40000"/>
  <!-- To turn tracing off, set DefaultTraceLevel="Off" and have no overrides.
    For the trace log file name, {0} is replaced by "Client" and {1} is the current time. -->
  <Tracing DefaultTraceLevel="Info" TraceToConsole="false" TraceToFile="{0}-{1}.log" BulkMessageLimit="1000">
    <TraceLevelOverride LogPrefix="Runtime" TraceLevel="Info" />
    <TraceLevelOverride LogPrefix="Application" TraceLevel="Info" />
    <TraceLevelOverride LogPrefix="AssemblyLoader" TraceLevel="Warning" />
  </Tracing>
  <Statistics MetricsTableWriteInterval="300s" PerfCounterWriteInterval="30s" LogWriteInterval="300s" WriteLogStatisticsToTable="true" StatisticsCollectionLevel="Info"/>
  <Messaging ResponseTimeout="30s" ClientSenderBuckets="8192" MaxResendCount="0"/>
</ClientConfiguration>
View Code

注:要記得更改文件屬性哦

 

一切准備就緒,下來讓改一下啟動方式為多項目啟動,然后就F5等待飛吧!

終於看到勝利的果實了,哈哈!接下來我們接着說說另外一種開發方式以及發布方式。

 

上面的這種開發方式為了說明開發的那些具體步驟,需要引用那些類庫,以及客戶端如何去調用,步驟比較麻煩,尤其是服務端的開發、引用類庫,也沒有相應的單元測試,接下來我們看看另外一種服務端的開發方式。

跟上面的大體步驟一樣

1.創建接口類庫

2.創建實現類庫

3.開發測試服務寄宿程序

在開始之前首先要確認一下你是否安裝了Orleans的vs模版插件,如果安裝了那么如下圖:

如果沒有安裝,趕緊去下載一個吧地址在:http://dotnet.github.io/orleans/NuGets

找到這一節,如下圖:

點開里面有你想要的插件,然后安裝重啟vs

1.創建接口類庫

2.創建實現類庫

 

 

3.創建服務寄宿程序

 

服務創建完之后,發現下面有自動生成的一個類OrleansHostWrapper,並且在Program下自動生成了很多代碼,代碼的大體意思就是,將服務端啟動程序的邏輯封裝在OrleansHostWrapper,然后啟動是單獨創建一個應用程序域,增加一些測試例子代碼,方便多了吧,我們不需要寫任何服務端的服務啟動代碼,在實際開發過程中我們只需要關心業務模塊

即接口創建,接口實現,方便多了吧。

將相應的代碼貼入進去,還記得上面出現的那個異常嗎,記得要將Microsoft.Extensions.DependencyInjection類庫引用進來哦,F5吧。

一切如預期所料,成功!

接下來我們創建一個單元測試程序庫,方便服務端的程序單元測試Sample.Test

引用項目Sample.Implements、Sample.Interfaces

引用Orleans測試包 PM> Install-Package Microsoft.Orleans.TestingHost



我們創建一個測試類就叫UserServiceTest,繼承自Orleans 測試庫TestingSiloHost
 [ClassCleanup]
        public static void ClassCleanup()
        {
            // Optional. 
            // By default, the next test class which uses TestignSiloHost will
            // cause a fresh Orleans silo environment to be created.
            StopAllSilosIfRunning();
        }
View Code

測試代碼如下:

namespace Sample.Test
{
    [TestClass]
    public class UserServiceTest: TestingSiloHost
    {
        [ClassCleanup]
        public static void ClassCleanup()
        {
            // Optional. 
            // By default, the next test class which uses TestignSiloHost will
            // cause a fresh Orleans silo environment to be created.
            StopAllSilosIfRunning();
        }

        [TestMethod]
        public async void TestExist()
        {
            var grain = GrainFactory.GetGrain<IUserService>(10);
            bool bo = await grain.Exist("18612478956");
            Assert.IsTrue(bo);
        }
    }
}
View Code

記得增加兩個配置文件,

ClientConfigurationForTesting.xml

<?xml version="1.0" encoding="utf-8" ?>
<ClientConfiguration xmlns="urn:orleans">
  <Gateway Address="localhost" Port="40000"/>
  <!-- To turn tracing off, set DefaultTraceLevel="Off" and have no overrides.
    For the trace log file name, {0} is replaced by "Client" and {1} is the current time. -->
  <Tracing DefaultTraceLevel="Info" TraceToConsole="false" TraceToFile="{0}-{1}.log" BulkMessageLimit="1000">
    <TraceLevelOverride LogPrefix="Runtime" TraceLevel="Info" />
    <TraceLevelOverride LogPrefix="Application" TraceLevel="Info" />
    <TraceLevelOverride LogPrefix="AssemblyLoader" TraceLevel="Warning" />
  </Tracing>
  <Statistics MetricsTableWriteInterval="300s" PerfCounterWriteInterval="30s" LogWriteInterval="300s" WriteLogStatisticsToTable="true" StatisticsCollectionLevel="Info"/>
  <Messaging ResponseTimeout="30s" ClientSenderBuckets="8192" MaxResendCount="0"/>
</ClientConfiguration>
View Code

OrleansConfigurationForTesting.xml

<?xml version="1.0" encoding="utf-8"?>
<OrleansConfiguration xmlns="urn:orleans">
  <Globals>
    <StorageProviders>
      <Provider Type="Orleans.Storage.MemoryStorage" Name="MemoryStore" />
      <Provider Type="Orleans.Storage.MemoryStorage" Name="Default" />
      <!--<Provider Type="Orleans.Storage.AzureTableStorage" Name="AzureStore"/>-->
    </StorageProviders>
    <SeedNode Address="localhost" Port="22222"/>
    <Messaging ResponseTimeout="30s"/>
  </Globals>
  <Defaults>
    <Networking Address="localhost" Port="22222"/>
    <ProxyingGateway Address="localhost" Port="40000" />
    <Tracing DefaultTraceLevel="Info" TraceToConsole="false" TraceToFile="{0}-{1}.log" PropagateActivityId="false" BulkMessageLimit="1000">
      <TraceLevelOverride LogPrefix="Application" TraceLevel="Info" />
      <!--
       <TraceLevelOverride LogPrefix="Runtime.Dispatcher" TraceLevel="Verbose" />
       <TraceLevelOverride LogPrefix="AssemblyLoader.Silo" TraceLevel="Warning" />
       -->
    </Tracing>
    <Statistics MetricsTableWriteInterval="30s" PerfCounterWriteInterval="30s" LogWriteInterval="300s" WriteLogStatisticsToTable="true" StatisticsCollectionLevel="Info"/>
  </Defaults>
</OrleansConfiguration>
View Code

更改xml文件屬性為:如果較新則復制

測試項目結構大體如下:

 

 

 

好,測試編寫完成,如何操作你懂得,這里就不廢話了。

 

 

 接下來說一下部署,部署吧,各有各的妙招,控制台、winform、windows服務等等,這里我說一個框架自帶的一個部署控制台怎么用

記得Orleans 里面有這么一個程序OrleansHost.exe,他是干什么用的呢,對了就是用來部署的。

我們來看看他的源碼,弄清楚他到底是做了一件什么事情

如下圖:

打開這個文件,可以發現這個文件跟上面我們通過模版創建的server中的文件OrleansHostWrapper很相似,對了,這個就是為了保持開發部署的一致性,所以這個就可以用來直接部署了

我們在server的Debug下找到相應的程序,將程序復制到某個盤符比如D:\demo下面

如下圖:

然后將配置文件拷貝進來OrleansConfiguration.xml

一切准備就緒,我們運行把,雙擊StartOrleans.cmd服務啟動

運行成功.
你會發現這個服務部署於我們的開發互不影響,當我們開發好一個grain的時候,直接編譯丟到這個部署目錄下,別的地方就可以訪問了,可以讓我們重點關注業務邏輯,而不需要關心那些復雜的配置或者服務的開啟關閉等等。

實例代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM