> ## Documentation Index
> Fetch the complete documentation index at: https://docs.abbyy.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Azure Cloud Service での実行

> Worker ロール プロジェクトと ABBYY ライセンスサーバーに接続するオンライン ライセンスを使用して、ABBYY FineReader Engine 12 for Windows を Azure Cloud Service にデプロイします。

このセクションでは、FRE 12 for Windows アプリケーションを Azure Cloud Service にデプロイする方法を説明します。例として、Azure Storage アカウント内のコンテナーでファイルを処理する Worker を取り上げます。

このシナリオを実装するには、\*.abbyy.com のライセンスサーバーに接続する [オンライン ライセンス](/ja/fine-reader/engine/licensing/online-licensing) を使用します。

<Note>
  ABBYY Licensing Service で同時に使用できるオンライン ライセンスは 1 つだけです。
</Note>

アプリケーションを Cloud Service にデプロイするには、いくつかの手順があります。

1. [前提条件](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#prerequisites) に従って、オンライン ライセンス、ローカル マシン、およびクラウド インスタンスを準備する
2. アプリケーションをデプロイする前に [準備手順](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparatorysteps) を実行する
3. [アプリケーションを Cloud Service にデプロイする](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#deployingabbyyfinereaderengineincloudservice)

文書処理で ABBYY FineReader Engine のメソッドを使用する方法を示した [コード サンプル](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#scripts) を参照してください。

<div id="prerequisites">
  ## 前提条件
</div>

<div id="online-license">
  ### オンライン ライセンス
</div>

オンライン ライセンスを使用するには、営業担当者から次の情報を受け取る必要があります。

* [Customer Project ID](/ja/fine-reader/engine/api-reference/functions/initializeengine-function#customerprojectid)
* オンライン ライセンス トークン ファイル
* ライセンス トークン ファイルのパスワード

ABBYY Licensing Service がインストールされている環境でオンライン ライセンスを使用するには、次の条件を満たしている必要があります。

* 有効なインターネット接続
* ポート 443 (HTTPS) で \*.abbyy.com への接続が許可されていること
* 認証局の GoDaddy ルート証明書 (この証明書は、信頼されたルート証明機関の証明書ストアのローカル マシン ストアにインストールされている必要があります。証明書の詳細については、GoDaddy の[ウェブサイト](http://www.godaddy.com/)を参照してください。)

<div id="local-machine">
  ### ローカル マシン
</div>

Cloud Service を作成する前に、以下の仕様に従ってローカル マシンを準備してください。

* Visual Studio 2019 と、Azure 向けアプリケーション開発用モジュール ([Visual Studio の Azure 機能](http://visualstudio.microsoft.com/vs/features/azure/)を確認するか、Visual Studio Installer を使用してこれらのモジュールをダウンロードしてください)
* デバッグを容易にするための Cloud Service エミュレーターおよびストレージ ([こちら](https://docs.microsoft.com/en-us/visualstudio/azure/vs-azure-tools-debug-cloud-services-virtual-machines?view=vs-2019)の情報を参照し、Visual Studio Installer 経由でダウンロードしてください)
* 単一の Worker role プロジェクトを含む Azure Cloud Service (拡張プレビュー) 用のテンプレート ソリューション ([こちら](https://docs.microsoft.com/en-us/visualstudio/azure/vs-azure-tools-debug-cloud-services-virtual-machines?view=vs-2019)の情報を参照)
* .NET Framework 4.7.2
* Azure SDK ([こちら](https://azure.microsoft.com/en-us/downloads/)からダウンロード)
* Azure Storage および Blob コンテナーを操作するための NuGet パッケージ - Azure.Storage.Blobs ([こちら](https://www.nuget.org/packages/Azure.Storage.Blobs/)からダウンロード)
* .NET Framework 4.7 用 ABBYY FineReader Engine wrapper (開発者向けインストール後、C:\ProgramData\ABBYY\SDK\12\FineReader Engine\Inc.NET interops フォルダー内)
* Blob コンテナーを操作するためにオーバーライドした [IFileWriter](/ja/fine-reader/engine/api-reference/supplementary-objects-and-methods/ifilewriter) インターフェイス (以下の[sample](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#ifilewriter)を参照)
* Azure Storage Explorer (任意 - [こちら](http://azure.microsoft.com/en-us/features/storage-explorer/)からダウンロード)

<div id="cloud-service-instance">
  ### Cloud Service インスタンス
</div>

Cloud Service インスタンスは、Azure で WorkerRole プロジェクトを格納するために使用します。このインスタンスは、次の仕様で構成します。

* Service の .NET Framework バージョン
* ABBYY FineReader Engine のデプロイに使用する PowerShell
* Azure SDK のアップロードに使用する NuGet 2.8.5.201 以降
* PowerShell を使用して Azure Storage アカウントを操作するための Azure SDK

<div id="preparatory-steps">
  ## 事前準備
</div>

事前準備はローカルマシンで行います。これらの手順を完了すると、アプリケーションのデプロイを開始するために必要な設定とファイルをすべて用意できます。

1. ABBYY FineReader Engine ライブラリと Licensing Service を含む 2 つのアーカイブ (たとえば、LibraryPackage.zip と LSPackage.zip) を作成します。FREngineDistribution.csv ファイルを使用すると、ファイル一覧を自動的に作成できます。ABBYY FineReader Engine と ライセンスサーバー には同じパッケージのものを使用してください。そうしないと、互換性は保証されません。
2. Azure Storage アカウント (この記事では frestorage) を作成します。必要な手順はすべて [Azure](http://docs.microsoft.com/en-us/azure/?product=featured) の Web サイトに記載されています。
3. frestorage 内に 3 つの Blob コンテナーを作成します。

* fre-lib - ABBYY FineReader Engine のファイル用
* fre-input - 入力ファイル用
* fre-output - 処理結果用

4. LibraryPackage.zip と LSPackage.zip を、最も使いやすい方法 (.NET、Powershell、Python スクリプト、または Azure Storage Explorer / Azure Portal アプリケーションの使用) で fre-lib コンテナーにアップロードします。

例として、構成済み環境で作業するために WorkerRole プロジェクトを使用します。必要な構成ファイル (.csdef と Cloud.cscfg) は、プロジェクトの作成後に自動的に生成されます。

<div id="deploying-abbyy-finereader-engine-to-cloud-service">
  ## Cloud Service への ABBYY FineReader Engine のデプロイ
</div>

新しい WorkerRole プロジェクトに ABBYY FineReader Engine をデプロイするには、次の手順を実行します。

1. 必要に応じて Cloud.cscfg のパラメーターを指定します。
2. .csdef ファイルのパラメーターを指定します。

* (任意) WorkerRole の設定
* (任意) 仮想マシンのサイズ
* (必須) ロールのローカル ストレージ (LocalStorage セクション。この資料では、LocalStorage1 という名前のストレージを使用) 。ABBYY FineReader Engine パッケージを正しくデプロイできるよう、少なくとも 3 GB に設定します。
* (必須) ロールの起動順序 ([コード サンプル](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#scripts) セクションのコード サンプルと設定を使用)

3. fre-input コンテナー内のファイルを処理し、処理結果を fre-output コンテナーに出力するように WorkerRole プロジェクトを実装します。

* Cloud Service を動作可能な状態に準備するための OnStart メソッド。このメソッドは、Engine を初期化し、TLS プロトコルを設定するために使用します。
* fre-input コンテナーから取得したファイルを繰り返し処理するための RunAsync メソッド。このメソッドは、fre-input コンテナー内のファイルを検出し、メモリ内で処理した後、fre-output コンテナーに配置します ([Processor.cs](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#processor.cs)、[IFileWriter.cs](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#ifilewriter)、[Config.cs](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#config) を参照) 。
* Cloud Service の動作を終了するための OnStop メソッド。このメソッドは、Engine の初期化を解除するために使用します。

<div id="code-samples">
  ## コード サンプル
</div>

このセクションには、ロールの起動順序と ABBYY FineReader Engine の設定に使用するコード サンプルが含まれています。

* CleanUpOnStart - 以前のバージョンの ABBYY FineReader Engine を削除し、更新手順を簡略化します (下記の [CleanUpOnStart.cmd](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#cleanuponstart.cmd) ファイルおよび [CleanUpOnStart.ps1](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#cleanuponstart.ps1) ファイルの内容を参照) 。
* PreparePoShModules - PowerShell で Azure Storage を操作するために必要な SDK をダウンロードします (下記の [PreparePoShModules.cmd](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#prepareposhmodules.cmd) ファイルおよび [PreparePoShModules.ps1](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparemodules.ps1) ファイルの内容を参照) 。
* PrepareLibrary - fre-lib コンテナーから ABBYY FineReader Engine ライブラリを取得し、ローカル ストレージに展開します (下記の [PrepareLibrary.cmd](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparelibrary.cmd) ファイルおよび [PrepareLibrary.ps1](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparelibrary.ps1) ファイルの内容を参照) 。
* PrepareLS - fre-lib コンテナーから Licensing Service を取得し、展開して起動します (下記の [PrepareLS.cmd](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparels.cmd) ファイルおよび [PrepareLS.ps1](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparels.ps1) ファイルの内容を参照) 。

上記のスクリプトは、アプリケーションを起動する前に、示された順序どおりに正確に実行する必要があります。スクリプトの実行順序をカスタマイズするには、次の属性を指定します。

* taskType="simple" - タスクは同期的に、1 回に 1 つずつ実行されます。
* executionContext="elevated" - スタートアップ スクリプトを管理者権限で実行します (アプリケーションのインストールと LicensingService.exe の実行に必要です)

その結果、Cloud Service で管理可能なフォルダーが作成されます。このフォルダーは、上記のスクリプトで ABBYY FineReader Engine を配置し、さらに [サンプル](/ja/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#processingsample) で使用する FREngine.dll をロードするために使用されます。

<Accordion title="CleanUpOnStart.cmd">
  ```
  rem   以前の ABBYY FineReader Engine および Licensing Service パッケージをクリーンアップするスクリプト
  echo Cleaning up before launching service >> ".\CleanUpOnStart.log" 2>&1
  PowerShell -ExecutionPolicy Unrestricted .\StartupScripts\CleanUpOnStart.ps1 >> ".\CleanUpOnStart.log" 2>&1
  echo Cleaning up beafore launching service. >> ".\CleanUpOnStart.log" 2>&1
   
  exit /B %errorlevel%
  ```
</Accordion>

<Accordion title="CleanUpOnStart.ps1">
  ```
  Write-Host "CleanUpOnStart.ps1 が開始されました...";
  # ローカル ストレージへのパス（ServiceDefinition.csdef を参照）
  $local_storage_name = "LocalStorage1";
  [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.WindowsAzure.ServiceRuntime");
  $local_storage_path = ([Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::GetLocalResource($local_storage_name)).RootPath.TrimEnd('\\');
  # Licensing Service のプロセスが実行中の場合は停止
  $processes = Get-Process;
  foreach( $process in $processes ) {
      if( $process.Name -eq "LicesingService" ) {
          Stop-Process $process;
      }
  }
   
  # fre_packages フォルダーを削除して再作成
  $destination_path = Join-Path -Path $local_storage_path -ChildPath 'fre_packages';
  if( Test-Path -Path $destination_path ) {
      Remove-Item $destination_path -Recurse -Force;
  }
  New-Item -ItemType Directory -Path $destination_path;
  # Input フォルダーを削除して再作成
  $destination_path = Join-Path -Path $local_storage_path -ChildPath 'Input';
  if( Test-Path -Path $destination_path ) {
      Remove-Item $destination_path -Recurse -Force;
  }
  New-Item -ItemType Directory -Path $destination_path;
  # Results フォルダーを削除して再作成
  $destination_path = Join-Path -Path $local_storage_path -ChildPath 'Results';
  if( Test-Path -Path $destination_path ) {
      Remove-Item $destination_path -Recurse -Force;
  }
  New-Item -ItemType Directory -Path $destination_path;
  Write-Host ("リソース フォルダーをクリーンアップしました。");
  ```
</Accordion>

<Accordion title="PreparePoShModules.cmd">
  ```
  rem   ストレージ アカウントに接続し、ABBYY FineReader Engine および Licensing Service のパッケージをダウンロードできるようにモジュールを準備するスクリプト
   
  echo PoSh モジュールを準備しています >> ".\PreparePoShModules.log" 2>&1
  PowerShell -ExecutionPolicy Unrestricted .\StartupScripts\PreparePoShModules.ps1 >> ".\PreparePoShModules.log" 2>&1
  echo PoSh モジュールの準備が完了しました。 >> ".\PreparePoShModules.log" 2>&1
   
  exit /B %errorlevel%
  ```
</Accordion>

<Accordion title="PreparePoShModules.ps1">
  ```bash theme={null}
  # モジュールをインストール
  Write-Host "PreparePoShModules.ps1 が開始されました...";
  # Azure モジュールのダウンロードに必要な NuGet プロバイダーをインストール
  Write-Host "NuGet パッケージ プロバイダーをインストールしています...";
  Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force;
   
  # BLOB を操作するための Azure Storage モジュールをインストール
  Write-Host "Az.Storage モジュールをインストールしています...";
  Install-Module -Name Az.Storage -Scope CurrentUser -Repository PSGallery -Force -AllowClobber;
  Write-Host ("PoSh モジュールの準備が完了しました。");
  ```
</Accordion>

<Accordion title="PrepareLibrary.cmd">
  ```
  rem   ABBYY FineReader Engine パッケージを準備するスクリプト
  echo ライブラリを準備しています >> ".\PrepareLibrary.log" 2>&1
  PowerShell -ExecutionPolicy Unrestricted .\StartupScripts\PrepareLibrary.ps1 >> ".\PrepareLibrary.log" 2>&1
  echo ライブラリの準備が完了しました。 >> ".\PrepareLibrary.log" 2>&1
  exit /B %errorlevel%
  ```
</Accordion>

<Accordion title="PrepareLibrary.ps1">
  ```
  Write-Host "PrepareLibrary.ps1 started...";
  # ABBYY FineReader Engine および Licensing Service のパッケージを含むコンテナー
  $container_name = 'fre-lib';
  # ストレージ アカウントの接続文字列 
  $connection_string = "<connection_string_to_frestorage>";
  Write-Host "Configuration";
  Write-Host ("Container name: " + $container_name);
  Write-Host ("Connection string: " + $storage_account);
  # ストレージ オブジェクトに接続
  Write-Host ("Connecting to storage account...");
  $storage_account = New-AzStorageContext -ConnectionString $connection_string;
  # blob（実質的にはファイル）を取得
  Write-Host ("Getting blobs from container...");
  $fre_blobs = Get-AzStorageBlob -Container $container_name -Context $storage_account;
  # ローカル ストレージへのパス（ServiceDefinition.csdef を参照）
  $local_storage_name = "LocalStorage1";
  [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.WindowsAzure.ServiceRuntime");
  $local_storage_path = ([Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::GetLocalResource($local_storage_name)).RootPath.TrimEnd('\\');
  $destination_path = Join-Path -Path $local_storage_path -ChildPath 'fre_packages';
  # 必要な唯一の blob をダウンロード
  Write-Host ("Downloading FRE package from container...");
  foreach( $blob in $fre_blobs ) {
      Write-Host $blob.Name;
      if( $blob.Name -eq "LibraryPackage.zip" ) {
          Write-Host ("Downloading blob: " + $blob.Name + "to " + $destination_path);
          Get-AzStorageBlobContent -Container $container_name -Blob $blob.Name `
              -Destination (Join-Path -Path $destination_path -ChildPath $blob.Name) -Context $storage_account;
      } else {
          Write-Host ("Downloading blob " + $blob.Name + " was skipped.");
      }
  }
  # ダウンロードしたパッケージを展開（既存のライブラリは強制的に上書き）
  Write-Host ("Unzipping library package...");
  Expand-Archive -Path (Join-Path -Path $destination_path -ChildPath "LibraryPackage.zip") `
      -DestinationPath (Join-Path -Path $destination_path -ChildPath "LibraryPackage") -Force;
  Write-Host ("Library package was prepared.");
  ```
</Accordion>

<Accordion title="PrepareLS.cmd">
  ```
  rem   Licensing Service パッケージを準備し、LicensingService.exe を起動するスクリプト
  echo Preparing LS >> ".\PrepareLS.log" 2>&1
  PowerShell -ExecutionPolicy Unrestricted .\StartupScripts\PrepareLS.ps1 >> ".\PrepareLS.log" 2>&1
  echo LS was prepared. >> ".\PrepareLS.log" 2>&1
  exit /B %errorlevel%
  ```
</Accordion>

<Accordion title="PrepareLS.ps1">
  ```
  Write-Host "PrepareLS.ps1 started...";
  # ABBYY FineReader Engine と Licensing Service のパッケージを含むコンテナー
  $container_name = 'fre-lib';
  # ストレージ アカウントの接続文字列
  $connection_string = "<connection_string_to_frestorage>";
  Write-Host "Configuration";
  Write-Host ("Container name: " + $container_name);
  Write-Host ("Connection string: " + $storage_account);
  # ストレージ オブジェクトに接続
  Write-Host ("Connecting to storage account...");
  $storage_account = New-AzStorageContext -ConnectionString $connection_string;
  # Blob（実質的にはファイル）を取得
  Write-Host ("Getting blobs from container...");
  $fre_blobs = Get-AzStorageBlob -Container $container_name -Context $storage_account;
  # ローカル ストレージへのパス（ServiceDefinition.csdef を参照）
  $local_storage_name = "LocalStorage1";
  [System.Reflection.Assembly]::LoadWithPartialName("Microsoft.WindowsAzure.ServiceRuntime");
  $local_storage_path = ([Microsoft.WindowsAzure.ServiceRuntime.RoleEnvironment]::GetLocalResource($local_storage_name)).RootPath.TrimEnd('\\');
  $destination_path = Join-Path -Path $local_storage_path -ChildPath 'fre_packages'; 
  # Licensing Service パッケージをダウンロード
  Write-Host ("Downloading Licensing Service package from container...");
  foreach( $blob in $fre_blobs ) {
      Write-Host $blob.Name;
      if( $blob.Name -eq "LSPackage.zip" ) {
          Write-Host ("Downloading blob: " + $blob.Name + "to " + $destination_path);
          Get-AzStorageBlobContent -Container $container_name -Blob $blob.Name `
              -Destination (Join-Path -Path $destination_path -ChildPath $blob.Name) -Context $storage_account;
      } else {
          Write-Host ("Downloading blob " + $blob.Name + " was skipped.");
      }
  }
  # ダウンロードしたパッケージを展開
  Write-Host ("Unzipping library package...");
  Expand-Archive -Path (Join-Path -Path $destination_path -ChildPath "LSPackage.zip") `
      -DestinationPath (Join-Path -Path $destination_path -ChildPath "LSPackage") -Force;
  # ライセンス用のフォルダーを作成
  $program_data_path = [System.Environment]::ExpandEnvironmentVariables("%programdata%");
  $path = Join-Path -Path $program_data_path -ChildPath "ABBYY\SDK\12\Licenses";
  New-Item -ItemType Directory -Path $path -Force;
  # スタンドアロンとして Licensing Service を起動
  Write-Host ("Starting Licensing Service...");
   
  $licensing_service_app = Join-Path -Path $destination_path -ChildPath "LSPackage\LicensingService.exe";
  Start-Process -FilePath $licesing_service_app -ArgumentList "/standalone";
  Write-Host ("LS package was prepared and LS was started.");
  ```
</Accordion>

<Accordion title="IFileWriter インターフェイスの実装">
  ```csharp theme={null}
  namespace WorkerRole1.Engine
  {
      public class FileWriter : FREngine.IFileWriter, IDisposable
      {
          public FileWriter(string _resultBlobName, string _fileExtension)
          {
              resultBlobName = _resultBlobName;
              fileExtension = _fileExtension;
          }
          public void Open(string fileName, ref int bufferSize)
          {
              stream = new MemoryStream();
          }
          public void Write(byte[] data)
          {
              stream.Write(data, 0, data.Length);
          }
          public void Close() 
          {
              // <OutputContainerName> 内の新しい Blob への接続を作成
              // 処理結果はそこに保存される
              BlobClient resultBlobClient = new BlobClient(Config.ConnectionString, Config.OutputContainerName,
                  resultBlobName + fileExtension);
              // 既存のファイルを上書き
              resultBlobClient.DeleteIfExists();
              // 先頭からファイルを書き込めるよう、位置を 0 に設定
              stream.Position = 0;
              resultBlobClient.Upload(stream);
   
              stream.Close();
          }
          public void Dispose()
          {
              // データ書き込み後にアクセスできるよう、破棄時にメモリ ストリームを閉じる
              stream.Close();
          }
          private string resultBlobName;
          private string fileExtension;
          private MemoryStream stream;
      }
  }
  ```
</Accordion>

<Accordion title="ABBYY FineReader Engine を使用したファイル処理のサンプル">
  ```csharp theme={null}
  namespace WorkerRole1
  {
      public class WorkerRole : RoleEntryPoint
      {
          private readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
          private readonly ManualResetEvent runCompleteEvent = new ManualResetEvent(false);
          Processor processor = new Processor();
   
          public override void Run()
          {
              Trace.TraceInformation("WorkerRole1 is running");
   
              try
              {
                  this.RunAsync(this.cancellationTokenSource.Token).Wait();
              }
              finally
              {
                  this.runCompleteEvent.Set();
              }
          }
          public override bool OnStart()
          {
              // 同時接続の最大数を設定します
              ServicePointManager.DefaultConnectionLimit = 12;
   
              // ストレージ アカウントに接続できるように TLS 1.2 を設定します
              System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
   
              // 構成変更の処理について詳しくは、
              // https://go.microsoft.com/fwlink/?LinkId=166357 の MSDN トピックを参照してください
   
              bool result = base.OnStart();
              Trace.TraceInformation("WorkerRole1 has been started");
   
              processor.LoadEngine();
              return result;
          }
   
          public override void OnStop()
          {
              processor.UnloadEngine();
              Trace.TraceInformation("WorkerRole1 is stopping");
              this.cancellationTokenSource.Cancel();
              this.runCompleteEvent.WaitOne();
              base.OnStop();
              Trace.TraceInformation("WorkerRole1 has stopped");
          }
   
          private async Task RunAsync(CancellationToken cancellationToken)
          {
              // TODO: 次のコードを独自のロジックに置き換えてください
              while (!cancellationToken.IsCancellationRequested)
              {
                  Trace.TraceInformation("Working");
   
                  try
                  {
                      // コンテナを作成し、コンテナ クライアント オブジェクトを返します
                      BlobContainerClient inputContainerClient = new BlobContainerClient(Config.ConnectionString, Config.InputContainerName);
                      foreach (BlobItem blobItem in inputContainerClient.GetBlobs())
                      {
                          Trace.TraceInformation("\t" + blobItem.Name);
                          BlobClient blobClient = new BlobClient(Config.ConnectionString, Config.InputContainerName, blobItem.Name);
   
                          Trace.TraceInformation("\t Downloading blob to memory: " + blobItem.Name);
                          MemoryStream memoryStream = new MemoryStream();
                          blobClient.DownloadTo(memoryStream);
                          Trace.TraceInformation("\t Processing in FRE: " + blobItem.Name);
                          string resultBlobName = processor.ProcessImage(memoryStream, blobItem.Name);
                          Trace.TraceInformation("\t Result blob name in output container: " + resultBlobName);
                          Trace.TraceInformation("\t Deleting from input container: " + blobItem.Name);
                          blobClient.Delete();
                      }
                  }
                  catch (Exception error)
                  {
                      Trace.TraceInformation("error: " + error.Message);
                  }
   
                  await Task.Delay(1000);
              }
          }
      }
  }
  ```
</Accordion>

<Accordion title="Processor.cs">
  ```csharp theme={null}
  namespace WorkerRole1
  {
      class Processor : IDisposable
      {
          EngineLoader engineLoader = null;
          private void displayMessage(string text)
          {
              File.AppendAllText(".\\FRE.log", text + "\n");
              Trace.TraceInformation("\t" + text );
          }        
          private void loadProfile()
          {
              engineLoader.Engine.LoadPredefinedProfile("DocumentConversion_Accuracy");
          }        
          private void setupFREngine()
          {
              displayMessage("Loading predefined profile...");
              loadProfile();
          }
          public void LoadEngine()
          {
              try {
                  if (engineLoader == null)
                  {
                      // Hello サンプルと同じ EngineLoader
                      engineLoader = new EngineLoader();
                  }
                  setupFREngine();
              }
              catch (Exception error)
              {
                  displayMessage("error: " + error.Message);
              }
          }
          public void UnloadEngine()
          {
              try
              {
                  if (engineLoader != null)
                  {
                      engineLoader.Dispose();
                      engineLoader = null;
                  }
              }
              catch (Exception error)
              {
                  displayMessage("error: " + error.Message);
              }
          }
   
          public string ProcessImage( MemoryStream inputMemoryStream, string inputBlobName )
          {
              FRDocument document = engineLoader.Engine.CreateFRDocument();
              string resultBlobName = "";
              try
              {
                 document.PageFlushingPolicy = FREngine.PageFlushingPolicyEnum.PFP_KeepInMemory;
   
                  // 画像ファイルをドキュメントに追加
                  displayMessage("Loading image...");
                  IntPtr handle = Marshal.AllocHGlobal(inputMemoryStream.GetBuffer().Length);
                  Marshal.Copy(inputMemoryStream.GetBuffer(), 0, handle, inputMemoryStream.GetBuffer().Length);
                  document.AddImageFileFromMemory(handle.ToInt64(), null, null);
   
                  // ドキュメントを認識
                  displayMessage("Recognizing...");
                  document.Process(null);
   
                  // 結果を保存
                  displayMessage("Saving results...");
                  // 'balanced' シナリオを使用して結果を PDF に保存
                  // FREngine.PDFExportParams pdfParams = engineLoader.Engine.CreatePDFExportParams();
                  // pdfParams.Scenario = FREngine.PDFExportScenarioEnum.PES_Balanced;
   
                  WorkerRole1.Engine.FileWriter fileWriter = new WorkerRole1.Engine.FileWriter(inputBlobName, ".pdf");
                  resultBlobName = inputBlobName + ".pdf";
                  document.ExportToMemory(fileWriter, FREngine.FileExportFormatEnum.FEF_PDF, null);
   
              }
              catch (Exception error)
              {
                  displayMessage("error: " + error.Message);
              }
              finally
              {
                  // ドキュメントを閉じる
                  document.Close();
              }
   
              return resultBlobName;
          }
   
          public void Dispose()
          {
              UnloadEngine();
          }
      }
  }
  ```
</Accordion>

<Accordion title="Config.cs">
  ```
  class Config
  {
      // ServiceDefinition.csdef で定義されているローカル ストレージ
      private static string LocalStorageName = "LocalStorage1";
      // ブロブ コンテナーへの接続文字列
      public static readonly string ConnectionString = "<connection_string_to_frestorage>";
      // ストレージ内の入力コンテナー名と出力コンテナー名
      public static readonly string InputContainerName = "fre-input";
      public static readonly string OutputContainerName = "fre-output";
   
      // ABBYY FineReader Engine の Customer Project ID を返す
      public static String GetCustomerProjectId()
      {
          return "<Your_Customer_Project_ID>";
      }
   
      // ライセンス トークン名を返す
      public static String GetLicenseTokenName()
      {
          return "<Token_number>.ABBYY.ActivationToken";
      }
   
      // ライセンス パスワードを返す
      public static String GetLicensePassword()
      {
          return "<Your_Online_License_token_password>";
      }
      // Engine のパスを返す
      public static String GetEngineFolder()
      {
          string engineSubfolder = "fre_packages\\LibraryPackage\\Bin64";
          string engineDllFolder = Path.Combine(RoleEnvironment.GetLocalResource(LocalStorageName).RootPath, engineSubfolder);
          return engineDllFolder;
      }
  }
  ```
</Accordion>
