Kentico Xperience xplorations:AでXperienceを使用すること.ネットコアワーカーサービス


In this post we'll be exploring how to integrate Kentico Xperience 13 with a .NET Core Worker Service to tail log the Xperience Event Log to a console window 💻.


Xperience + ASP .ネットコア


Kentico Xperience ASPに大きな統合を提供します.ネットコア.
The Kentico.Xperience.AspNetCore.WebApp nugetパッケージはこれらの統合ポイントを提供します.
すべてのXperienceのサービスをASP . NETで登録できます.ネットコアdependency injection 呼び出しによる容器services.AddKentico(); :
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddKentico();

        // ... Other DI registration
    }

    // ...
}
Xperienceのページビルダー機能を呼び出すことで有効にすることができますapp.UseKentico(...) そしてそれを介してルーティングを管理しているendpoint routing コールによるミドルウェア統合endpoints.Kentico().MapRoutes(); :
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // ...
    }

    public void Configure(
        IApplicationBuilder app, 
        IWebHostEnvironment env)
    {
        // ... earlier middleware

        app.UseKentico(features =>
        {
            features.UsePreview();
            features.UsePageBuilder();
        });

        // ... more middleware

        app.UseEndpoints(endpoints =>
        {
            endpoints.Kentico().MapRoutes();
        });
    }
}
しかし、私たちがxperienceを使いたいならば、どうですか.この設定のすべてなしでネットコア🤔? ASP全体を構成して実行することなく、それを使用したいなら、どうでしょうか.NETコアWebアプリケーション😕?
幸いにも我々は限られていないし、私たちも.NET Core console application 😮.
ASPに比べて逆方向にアプリケーションの複雑さの振り子を振っているようですが、コンソールアプリケーションを使用するのは何の問題もありません.NETコアWebアプリケーション.
aで定義された値を使いたい場合appsettings.json ? ログインまたは依存性の注入が必要な場合アプリケーションの寿命管理は素晴らしいです!どうやってそれを得るのですか?
多分、我々はまだASPのように連続的に動くアプリケーションが欲しいです.ネットコアのアプリが、すべての' web 'ものなし.
エー.ネットコアWorker Service この幸せな中間のグラウンドに座って、ASPから好きなインフラストラクチャをくれます.Webアプリケーションフレームワークの部分を必要としないネットコア👍.

私たちの最初の停止:新しい作成。ネットコアサービス


Visual Studioには、新しいプロジェクトダイアログで作業者サービスを作成するためのテンプレートが用意されています

このテンプレートは私たちに始めるために必要な基礎を与えます.
新しいプロジェクトを作成した後、ソリューションエクスプローラーでファイルの一覧が表示されます

このほとんどは、ASPと非常によく似ています.NETコアプロジェクト.行方不明のファイルの中のキーはStartup.cs その代わりにWorker.cs ファイルが、まだ持っているappsettings.json 設定の指定💪🏾!
我々が開くならばProgram.cs , 我々は、我々の通知Main() メソッドはASPと同じです.NETコアアプリケーション
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    // ...
}
ASPの違い.NETコアアプリケーションとワーカーサービスアプリケーションがホスト構成にあります.の間ASP .ネットコア用途.ConfigureWebHostDefaults(...) , ここでは、我々の依存性注入を構成するためにまっすぐにジャンプします.ConfigureServices(...) , はStartup.cs :
public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureServices((hostContext, services) =>
        {
            services.AddHostedService<Worker>();
        });
これはProgram.cs 我々が構成し、アプリケーションを起動する必要があるすべてが含まれています😎.
だからどこで実際に我々のアプリの意味のある仕事をするコードですか?それは全部ですWorker.cs ファイル!

より深く掘る:労働者


開放Worker.cs 我々は、1から継承する単一のクラスを見ることができますBackgroundService :
public class Worker : BackgroundService
{
    private readonly ILogger<Worker> _logger;

    public Worker(ILogger<Worker> logger)
    {
        _logger = logger;
    }

    // ..
}
The Worker クラスは、BackgroundService 基底クラスExecuteAsync(CancellationToken stoppingToken) :
protected override async Task ExecuteAsync(
    CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        _logger.LogInformation(
           "Worker running at: {time}", 
           DateTimeOffset.Now);

        await Task.Delay(1000, stoppingToken);
    }
}
このメソッドは、while (...) ループは、典型的にどのように実装されて表示されます.
労働者だけのサービスであるので、彼らの処理はASPと違って彼らにプッシュされるデータによって始められません.HTTPリクエストを送信するときに処理を開始するNETコアアプリケーション.
代わりに、労働者は他のソースからデータを引き出し、データが見つかった場合のみ処理を実行し、そのデータについての条件を満たす🧐.
労働者がデータが利用可能であるかどうかわからないので、サービスが止められるまで、それはループで走ります.

我々の旅を続ける:ケチノス


我々は労働者のサービスアプリケーションを構成するものを調査した今、Kentico Xperienceを統合しよう!

ヌード依存


我々は、追加する必要がありますKentico.Xperience.Libraries NuGet package 我々に.csproj ファイルには、私たちのワーカーサービスのXperienceのAPIのすべてにアクセスできます.
<ItemGroup>
    <!-- ... other packages -->

    <!-- Xperience 13 is still in beta at the time
         of this blog post -->
    <PackageReference 
        Include="Kentico.Xperience.Libraries" 
        Version="13.0.0-b7472.17674" />
</ItemGroup>

構成


また、アプリケーションの設定にデータベース情報を追加する必要がありますappsettings.json 接続文字列を指定します.
{
  "Logging": {
    // ...
  },
  "ConnectionStrings": {
    "CMSConnectionString": "..."
  },
}
アプリケーションは、これから構成を読むためにすでにセットアップされますjson しかし、xperienceはそれについて知りませんので、必要な設定が見つかるように指示する必要があります.
我々は、我々を開きますProgram.cs そして、.ConfigureServices() コール
Host.CreateDefaultBuilder(args)
    .ConfigureServices((hostContext, services) =>
    {
        services.AddHostedService<Worker>();

        Service.Use<IConfiguration>(
            () => hostContext.Configuration);
    });
この呼び出しはService.Use() 定義された接続文字列のように、重要な設定を見つけるためにXperienceの内部インフラストラクチャ😲.
では.ネットコアhosted service , hostContext.Configuration 標準構成ソースからのすべての構成を含みます.
例えば、hostContext.Configuration.GetConnectionString("CMSConnectionString"); を返しますappsettings.json 接続文字列.
今、我々は間の設定ギャップを橋渡ししました.ネットコアとXperience、我々は労働者に移動することができます👍🏽!

初期設定


という理由だけで.NETコアアプリケーションが起動し、実行されませんXperienceの内部を意味している実行している.
Xperienceを明示的に初期化する必要があります.幸運にも、これは1つの呼び出しで行うことができますBackgroundService 我々が我々の中で乗り越えることができる我々Worker クラス
public override Task StartAsync(CancellationToken cancellationToken)
{
    CMSApplication.Init();

    return base.StartAsync(cancellationToken);
}
StartAsync アプリケーションが起動時と終了時に一度だけ実行されるis ready to execute the Worker .
これはXperienceを初期化するのに最適な場所ですCMSApplication.Init(); 😃.
我々が構成して、初期化したので、我々は若干の仕事をする準備ができています!

目的地:XPERFenceイベントログ用のテールロガーの作成


このポストの冒頭では、xperienceイベントログのテールロガーを構築するつもりです.我々は基本的なxperience +ワーカーサーバーの統合を設定しているので、我々は今すぐ始めることができます.

コンソールログの追加


まず、ホストの設定を更新する必要がありますProgram.cs コンソールログを含めるdisable the default application startup logs :
Host.CreateDefaultBuilder(args)
    .ConfigureLogging(logging =>
    {
        // Adds console output for logs
        logging.AddConsole();
    })
    .ConfigureServices((hostContext, services) =>
    {
        // Disables the startup logs
        services.Configure<ConsoleLifetimeOptions>(opts => 
            opts.SuppressStatusMessages = true);

        services.AddHostedService<Worker>();

        Service.Use<IConfiguration>(
            () => hostContext.Configuration);
    });
今、我々は戻ることができますWorker.cs とログの尾をコーディングを開始します.

労働者の更新


我々は、2つのプライベートメンバーを定義しますWorker クラス
private int latestLogId = 0;

private delegate void LogAction(string s, params object[] args);
The latestLogId 最新の追跡EventLogInfo 我々がコンソールにログオンしたので、我々は重複した情報で出力をスパムしません😉.LogAction 名前付き関数シグネチャは、ログコードを後で少しクリーナーにするためのものですILogger メソッドを使用します.
次は更新しましょうExecuteAsync 次のようにします.
protected override async Task ExecuteAsync(
    CancellationToken stoppingToken)
{
    while (!stoppingToken.IsCancellationRequested)
    {
        var eventLog = (await EventLogProvider
            .GetEvents()
            .OrderByDescending(
                nameof(EventLogInfo.EventID))
            .TopN(1)
            .GetEnumerableTypedResultAsync(
                cancellationToken: stoppingToken))
            .FirstOrDefault();

        LogEvent(eventLog);

        await Task.Delay(5000, stoppingToken);
    }
}
上記の、我々は素晴らしい新しいを使用しているasync Xperience 13でのクエリ🔥🔥🔥 そして、最近をつかんでEventLogInfo データベースから(それが存在するならば)5秒ごとに.

If you want to learn more about the new data access APIs in Kentico Xperience 13, check out my post Kentico Xperience 13 Beta 3 - New Data Access APIs.




さあピークに入りましょうLogEvent() 何が起こっているかを見てみてください.
private void LogEvent(EventLogInfo eventLog)
{
    if (eventLog is null || 
        eventLog.EventID == latestLogId)
    {
        return;
    }

    var action = GetAction(eventLog.EventType);

    action("Xperience Event {id} {type} {time} {source} {code} {description}",
        eventLog.EventID,
        eventLog.EventType,
        eventLog.EventTime,
        eventLog.Source,
        eventLog.EventCode,
        eventLog.EventDescription
    );

    latestLogId = eventLog.EventID;
}
まず、我々はeventLog でないnull (テーブルがちょうど切り詰められたのかもしれない🤷🏽‍♀️) そして、我々の質問によって返されるログレコードは、我々がちょうど表示したものではありません.
それから、我々は電話しますGetAction() 正しいものを選ぶILogger データベースで見つけたログのタイプに基づく方法.
一度アクションを参照するILogger メソッドをコールしたい場合は、eventLog データとログメッセージテンプレート.
最後に、我々はlatestLogId を返します.eventLog それで、我々は次のループで我々自身を繰り返しません.
コードの最後のビットはGetAction() を使用するメソッドC# 8 switch expression 🤓 正しいものを選ぶILogger メソッド:
private LogAction GetAction(string eventLogType) =>
    eventLogType switch
    {
        "W" => logger.LogWarning,
        "E" => logger.LogError,
        "I" => logger.LogInformation,
        _ => logger.LogInformation
    };
ペリエンスEventLogInfo レコード使用"W" , "E" , and "I" logの型を指定し、ILogger.Information 何らかの理由でマッチがない場合.

Xperienceイベントログをテイリング!


我々は最終的に終了し、今我々が達成したものを見ることができます.

コンソールでXperienceイベントログtailiingを示している1 MBのアニメーションGIF
上記の記録で、イベントログを生成するXperienceコンテンツ管理アプリケーションで、毎回、コンソールウィンドウに情報が表示されます.
また、便利に置かれるthrow new System.Exception("Kaboom 💣 💥 🔥 🧨"); インマイHomeController コンソールに表示されているエラーメッセージ(およびスタックトレース)のコンテンツ配信アプリケーションの結果、サイトのホームページを訪問しようとすると.
私のクールなemojis😏 don't display in the console !)

結論


このデモは楽しいですが、それはまた、我々はすべての外出し、生産環境に展開する可能性が高い何かではない!
最も重要なのは、Kentico Xperienceが統合をサポートすることです.私たちのソフトウェア開発ツールのベルトに追加できる別の強力なツールです💪🏿.
我々がこのポストで見なかった1つのものは、労働者サービスを走らせていましたinside an ASP.NET Core application . これは、バックグラウンドスレッドへの作業をオフにすることができるようになります.タスクがXperienceコンテンツ管理アプリケーションでどのようにスケジュールされているかに似ていますasync .

We could even use channels which are powerful abstractions of the classic publish/subscribe pattern 🧐.


興奮してる😄 Kentico Xperienceコミュニティが新しいテクノロジーのような労働者サービスを使用するために見つけるすべての創造的な方法のために、そして、このポストを読んだ後に、私はあなたがいることを望みます.
あなたがどのようにXperienceで労働者サービスを使うかもしれないかについての考えがありますか?コメントの下の共有アイデア!
...
いつものように、読書のおかげで🙏!
写真でJordan Madrid on Unsplash
我々は一緒にリストを一緒に入れてKentico's GitHub account 開発者リソースの.それをチェックアウトゴー!
追加のKenticoコンテンツを探しているなら、ここでKenticoタグをチェックアウトしてください.
.ltag__tag__id__5339 .アクションボタン
背景色:!重要
色:!重要
ボーダーカラー!重要

センカンケンティコ


または、