> ## 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.

# Ejecución en Azure Cloud Service

> Despliegue ABBYY FineReader Engine 12 para Windows en Azure Cloud Service con un proyecto de rol Worker y una licencia en línea que se conecta a los servidores de licencias de ABBYY.

Esta sección proporciona instrucciones sobre cómo desplegar una aplicación FRE 12 para Windows en Azure Cloud Service. Como ejemplo, se muestra un Worker que procesa archivos mediante un contenedor en una cuenta de Azure Storage.

Para implementar este escenario, se utiliza una [licencia en línea](/es/fine-reader/engine/licensing/online-licensing) que se conecta al servidor de licencias de \*.abbyy.com.

<Note>
  El servicio de licencias de ABBYY solo puede funcionar con una licencia en línea al mismo tiempo.
</Note>

Desplegar su aplicación en Cloud Service incluye varios pasos:

1. Configurar su licencia en línea, el equipo local y la instancia en la nube siguiendo los [requisitos previos](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#prerequisites)
2. Realizar [los pasos preparatorios](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparatorysteps) antes de desplegar su aplicación
3. [Desplegar su aplicación en Cloud Service](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#deployingabbyyfinereaderengineincloudservice)

Consulte los [ejemplos de código](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#scripts) que muestran cómo usar los métodos de ABBYY FineReader Engine para el procesamiento de documentos.

<div id="prerequisites">
  ## Requisitos previos
</div>

<div id="online-license">
  ### Licencia en línea
</div>

Para usar una licencia en línea, debe recibir la siguiente información del equipo de ventas:

* su [Customer Project ID](/es/fine-reader/engine/api-reference/functions/initializeengine-function#customerprojectid)
* un archivo de token de licencia para la licencia en línea
* la contraseña del archivo de token de licencia

Debe cumplir las siguientes condiciones para usar una licencia en línea en cualquier lugar donde esté instalado el servicio de licencias de ABBYY:

* Conexión activa a Internet
* Conexiones permitidas a \*.abbyy.com por el puerto 443 (HTTPS)
* Certificado raíz de GoDaddy para la entidad de certificación (Debe estar instalado en el almacén de certificados Trusted Root Certification Authorities de la versión del equipo local. Consulte la información detallada sobre el certificado en el [sitio web](http://www.godaddy.com/) de GoDaddy).

<div id="local-machine">
  ### Equipo local
</div>

Antes de crear su Cloud Service, use la siguiente especificación para preparar su equipo local:

* Visual Studio 2019 y sus módulos para desarrollar aplicaciones para Azure (consulte [Funcionalidades de Azure en Visual Studio](http://visualstudio.microsoft.com/vs/features/azure/) o use Visual Studio Installer para descargar dichos módulos)
* Emuladores de Cloud Service y almacenamiento para facilitar la depuración (consulte la información [aquí](https://docs.microsoft.com/en-us/visualstudio/azure/vs-azure-tools-debug-cloud-services-virtual-machines?view=vs-2019) y descárguelos mediante Visual Studio Installer)
* Solución de plantilla para Azure Cloud Service (versión preliminar extendida) con un único proyecto de rol Worker (consulte la información [aquí](https://docs.microsoft.com/en-us/visualstudio/azure/vs-azure-tools-debug-cloud-services-virtual-machines?view=vs-2019))
* .NET Framework 4.7.2
* SDK de Azure (descárguelo [aquí](https://azure.microsoft.com/en-us/downloads/))
* Paquete NuGet para trabajar con Azure Storage y contenedores Blob: Azure.Storage.Blobs (descárguelo [aquí](https://www.nuget.org/packages/Azure.Storage.Blobs/))
* Wrapper de ABBYY FineReader Engine para .NET Framework 4.7 (en la carpeta C:\ProgramData\ABBYY\SDK\12\FineReader Engine\Inc.NET interops tras una instalación Developer)
* Interfaz [IFileWriter](/es/fine-reader/engine/api-reference/supplementary-objects-and-methods/ifilewriter) con implementación personalizada para trabajar con contenedores Blob (consulte el [ejemplo](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#ifilewriter) a continuación)
* Azure Storage Explorer (opcional; descárguelo [aquí](http://azure.microsoft.com/en-us/features/storage-explorer/))

<div id="cloud-service-instance">
  ### Instancia de Cloud Service
</div>

La instancia de Cloud Service se utiliza para almacenar su proyecto WorkerRole en Azure. Use la siguiente especificación para configurar esta instancia:

* versión de .NET Framework de su servicio
* PowerShell para implementar ABBYY FineReader Engine
* NuGet 2.8.5.201 o superior para cargar el SDK de Azure
* SDK de Azure para trabajar con una cuenta de Azure Storage mediante PowerShell

<div id="preparatory-steps">
  ## Pasos preparatorios
</div>

Los pasos preparatorios deben realizarse en su equipo local. Al completar estos pasos, preparará toda la configuración y los archivos necesarios para comenzar el despliegue de su aplicación:

1. Cree dos archivos comprimidos con ABBYY FineReader Engine Library y el servicio de licencias (por ejemplo, LibraryPackage.zip y LSPackage.zip). Puede generar la lista de archivos automáticamente con ayuda del archivo FREngineDistribution.csv. Use ABBYY FineReader Engine y el servidor de licencias del mismo paquete; de lo contrario, no se garantiza la compatibilidad.
2. Cree la cuenta de Azure Storage (frestorage en este artículo). Puede encontrar todas las instrucciones necesarias en el sitio web de [Azure](http://docs.microsoft.com/en-us/azure/?product=featured).
3. Cree tres contenedores de blobs dentro de frestorage:

* fre-lib - para los archivos de ABBYY FineReader Engine
* fre-input - para los archivos de entrada
* fre-output - para los resultados del procesamiento

4. Cargue LibraryPackage.zip y LSPackage.zip en el contenedor fre-lib de la forma que le resulte más conveniente (mediante .NET, PowerShell, un script de Python o las aplicaciones Azure Storage Explorer/Azure Portal).

Como ejemplo, se utiliza un proyecto WorkerRole para trabajar en un entorno configurado. Todos los archivos de configuración necesarios (.csdef y Cloud.cscfg) se generan automáticamente después de crear su proyecto.

<div id="deploying-abbyy-finereader-engine-to-cloud-service">
  ## Implementación de ABBYY FineReader Engine en Cloud Service
</div>

Para implementar ABBYY FineReader Engine en su nuevo proyecto de WorkerRole:

1. Especifique los parámetros de Cloud.cscfg según sea necesario.
2. Especifique los parámetros del archivo .csdef:

* (opcional) la configuración de su WorkerRole
* (opcional) el tamaño de su máquina virtual
* (obligatorio) el almacenamiento local de su rol (sección LocalStorage; en este artículo, el almacenamiento denominado LocalStorage1). Configúrelo con al menos 3 GB para garantizar que el paquete de ABBYY FineReader Engine se implemente correctamente.
* (obligatorio) el orden de inicio de su rol (use los ejemplos de código y la configuración de la sección [code samples](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#scripts))

3. Implemente su proyecto de WorkerRole para procesar archivos del contenedor fre-input y publicar los resultados del procesamiento en el contenedor fre-output:

* el método OnStart para preparar su Cloud Service para su funcionamiento. Este método se utiliza para inicializar el Engine y configurar el protocolo TLS.
* el método RunAsync para procesar cíclicamente los archivos tomados del contenedor fre-input. Este método detecta los archivos del contenedor fre-input, los procesa en memoria y los coloca en el contenedor fre-output (consulte [Processor.cs](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#processor.cs), [IFileWriter.cs](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#ifilewriter) y [Config.cs](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#config)).
* el método OnStop para finalizar la ejecución de Cloud Service. Este método se utiliza para desinicializar el Engine.

<div id="code-samples">
  ## Ejemplos de código
</div>

Esta sección incluye ejemplos de código que se utilizan para configurar el orden de inicio de los roles y los ajustes de ABBYY FineReader Engine:

* CleanUpOnStart - elimina la versión anterior de ABBYY FineReader Engine y simplifica el procedimiento de actualización (consulte su contenido en los archivos [CleanUpOnStart.cmd](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#cleanuponstart.cmd) y [CleanUpOnStart.ps1](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#cleanuponstart.ps1) a continuación).
* PreparePoShModules - descarga el SDK necesario para que PowerShell funcione con Azure Storage (consulte su contenido en los archivos [PreparePoShModules.cmd](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#prepareposhmodules.cmd) y [PreparePoShModules.ps1](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparemodules.ps1) a continuación).
* PrepareLibrary - carga y descomprime la ABBYY FineReader Engine Library desde el contenedor fre-lib en el almacenamiento local (consulte su contenido en los archivos [PrepareLibrary.cmd](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparelibrary.cmd) y [PrepareLibrary.ps1](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparelibrary.ps1) a continuación).
* PrepareLS - carga, descomprime e inicia el servicio de licencias desde el contenedor fre-lib (consulte su contenido en los archivos [PrepareLS.cmd](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparels.cmd) y [PrepareLS.ps1](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#preparels.ps1) a continuación).

Es necesario que los scripts indicados anteriormente se ejecuten exactamente en el orden propuesto, antes de iniciar la aplicación. Para personalizar el orden de ejecución de los scripts, especifique los siguientes atributos:

* taskType="simple" - las tareas se ejecutan de forma síncrona, una por una.
* executionContext="elevated" - ejecución de un script de inicio con derechos de administrador (necesario para poder instalar cualquier aplicación y ejecutar LicensingService.exe)

Como resultado, se creará una carpeta que Cloud Service podrá administrar. Esta carpeta se usa para cargar ABBYY FineReader Engine mediante los scripts indicados anteriormente y cargar FREngine.dll para su uso posterior en el [ejemplo](/es/fine-reader/engine/distribution/distribution-windows/running-abbyy-finereader-engine-inside-azure-services/running-in-azure-cloud-service#processingsample).

<Accordion title="CleanUpOnStart.cmd">
  ```
  rem   Script para limpiar los paquetes anteriores de ABBYY FineReader Engine y 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 started...";
  # ruta al almacenamiento local (consulte 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('\\');
  # detener el proceso del servicio de licencias si estaba en ejecución
  $processes = Get-Process;
  foreach( $process in $processes ) {
      if( $process.Name -eq "LicesingService" ) {
          Stop-Process $process;
      }
  }
   
  # limpiar y volver a crear la carpeta 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;
  # limpiar y volver a crear la carpeta 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;
  # limpiar y volver a crear la carpeta 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 ("Resource folder was cleaned up.");
  ```
</Accordion>

<Accordion title="PreparePoShModules.cmd">
  ```
  rem   Script para preparar los módulos necesarios para conectarse a la cuenta de almacenamiento y descargar los paquetes de ABBYY FineReader Engine y del servicio de licencias
   
  echo Preparing PoSh Modules >> ".\PreparePoShModules.log" 2>&1
  PowerShell -ExecutionPolicy Unrestricted .\StartupScripts\PreparePoShModules.ps1 >> ".\PreparePoShModules.log" 2>&1
  echo PoSh Modules wer prepared. >> ".\PreparePoShModules.log" 2>&1
   
  exit /B %errorlevel%
  ```
</Accordion>

<Accordion title="PreparePoShModules.ps1">
  ```bash theme={null}
  # instalar módulos
  Write-Host "PreparePoShModules.ps1 started...";
  # instalar el proveedor de paquetes NuGet para descargar módulos de Azure
  Write-Host "Installing NuGet package provider...";
  Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force;
   
  # instalar el módulo Az.Storage para trabajar con blobs
  Write-Host "Installing Az.Storage module...";
  Install-Module -Name Az.Storage -Scope CurrentUser -Repository PSGallery -Force -AllowClobber;
  Write-Host ("PoSh modules were prepared.");
  ```
</Accordion>

<Accordion title="PrepareLibrary.cmd">
  ```
  rem   Script para preparar el paquete de ABBYY FineReader Engine
  echo Preparing Library >> ".\PrepareLibrary.log" 2>&1
  PowerShell -ExecutionPolicy Unrestricted .\StartupScripts\PrepareLibrary.ps1 >> ".\PrepareLibrary.log" 2>&1
  echo Library was prepared. >> ".\PrepareLibrary.log" 2>&1
  exit /B %errorlevel%
  ```
</Accordion>

<Accordion title="PrepareLibrary.ps1">
  ```
  Write-Host "PrepareLibrary.ps1 started...";
  # contenedor con los paquetes de ABBYY FineReader Engine y del servicio de licencias
  $container_name = 'fre-lib';
  # cadena de conexión de la cuenta de almacenamiento 
  $connection_string = "<connection_string_to_frestorage>";
  Write-Host "Configuration";
  Write-Host ("Container name: " + $container_name);
  Write-Host ("Connection string: " + $storage_account);
  # conexión al objeto de almacenamiento
  Write-Host ("Connecting to storage account...");
  $storage_account = New-AzStorageContext -ConnectionString $connection_string;
  # obtención de blobs (básicamente, archivos)
  Write-Host ("Getting blobs from container...");
  $fre_blobs = Get-AzStorageBlob -Container $container_name -Context $storage_account;
  # ruta al almacenamiento local (consulte 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';
  # descarga del único blob necesario
  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.");
      }
  }
  # descompresión del paquete descargado (la biblioteca anterior se sobrescribirá a la fuerza)
  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   Script para preparar el paquete del servicio de licencias e iniciar 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...";
  # contenedor con los paquetes de ABBYY FineReader Engine y el servicio de licencias
  $container_name = 'fre-lib';
  # cadena de conexión de la cuenta de almacenamiento
  $connection_string = "<connection_string_to_frestorage>";
  Write-Host "Configuration";
  Write-Host ("Container name: " + $container_name);
  Write-Host ("Connection string: " + $storage_account);
  # conexión al objeto de almacenamiento
  Write-Host ("Connecting to storage account...");
  $storage_account = New-AzStorageContext -ConnectionString $connection_string;
  # obtención de blobs (básicamente archivos)
  Write-Host ("Getting blobs from container...");
  $fre_blobs = Get-AzStorageBlob -Container $container_name -Context $storage_account;
  # ruta al almacenamiento local (consulte 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'; 
  # descarga del paquete LS
  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.");
      }
  }
  # descompresión del paquete descargado
  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;
  # creación de carpetas para las licencias
  $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;
  # inicio del servicio de licencias en modo independiente
  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="Implementación de la interfaz 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() 
          {
              // Creación de la conexión a un nuevo blob en <OutputContainerName>
              // El resultado del procesamiento se almacenará allí
              BlobClient resultBlobClient = new BlobClient(Config.ConnectionString, Config.OutputContainerName,
                  resultBlobName + fileExtension);
              // Sobrescritura del archivo existente
              resultBlobClient.DeleteIfExists();
              // Posición establecida en 0 para escribir el archivo desde el principio
              stream.Position = 0;
              resultBlobClient.Upload(stream);
   
              stream.Close();
          }
          public void Dispose()
          {
              // Cierre del flujo de memoria al liberar el objeto para poder acceder a él tras escribir los datos
              stream.Close();
          }
          private string resultBlobName;
          private string fileExtension;
          private MemoryStream stream;
      }
  }
  ```
</Accordion>

<Accordion title="Ejemplo de procesamiento de archivos con 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()
          {
              // Establezca el número máximo de conexiones simultáneas
              ServicePointManager.DefaultConnectionLimit = 12;
   
              // Establezca TLS en 12 para poder conectarse a la cuenta de almacenamiento
              System.Net.ServicePointManager.SecurityProtocol = System.Net.SecurityProtocolType.Tls12;
   
              // Para obtener información sobre cómo administrar los cambios de configuración,
              // consulte el tema de MSDN en https://go.microsoft.com/fwlink/?LinkId=166357
   
              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: Reemplace lo siguiente por su propia lógica
              while (!cancellationToken.IsCancellationRequested)
              {
                  Trace.TraceInformation("Working");
   
                  try
                  {
                      // Cree el contenedor y devuelva un objeto cliente de contenedor
                      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("Cargando perfil predefinido...");
              loadProfile();
          }
          public void LoadEngine()
          {
              try {
                  if (engineLoader == null)
                  {
                      // El mismo EngineLoader que en el ejemplo Hello
                      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;
   
                  // Agregue el archivo de imagen al documento
                  displayMessage("Cargando imagen...");
                  IntPtr handle = Marshal.AllocHGlobal(inputMemoryStream.GetBuffer().Length);
                  Marshal.Copy(inputMemoryStream.GetBuffer(), 0, handle, inputMemoryStream.GetBuffer().Length);
                  document.AddImageFileFromMemory(handle.ToInt64(), null, null);
   
                  // Reconozca el documento
                  displayMessage("Reconociendo...");
                  document.Process(null);
   
                  // Guarde los resultados
                  displayMessage("Guardando resultados...");
                  // Guarde los resultados en PDF con el escenario 'balanced'
                  // 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
              {
                  // Cierre el documento
                  document.Close();
              }
   
              return resultBlobName;
          }
   
          public void Dispose()
          {
              UnloadEngine();
          }
      }
  }
  ```
</Accordion>

<Accordion title="Config.cs">
  ```
  class Config
  {
      // Almacenamiento local, tal como se define en ServiceDefinition.csdef
      private static string LocalStorageName = "LocalStorage1";
      // Cadena de conexión al contenedor de blobs
      public static readonly string ConnectionString = "<connection_string_to_frestorage>";
      // Nombres de los contenedores de entrada y salida en su almacenamiento
      public static readonly string InputContainerName = "fre-input";
      public static readonly string OutputContainerName = "fre-output";
   
      // Devuelve el Customer Project ID para ABBYY FineReader Engine
      public static String GetCustomerProjectId()
      {
          return "<Your_Customer_Project_ID>";
      }
   
      // Devuelve el nombre del token de licencia
      public static String GetLicenseTokenName()
      {
          return "<Token_number>.ABBYY.ActivationToken";
      }
   
      // Devuelve la contraseña de la licencia
      public static String GetLicensePassword()
      {
          return "<Your_Online_License_token_password>";
      }
      // Devuelve la ruta de la carpeta del motor
      public static String GetEngineFolder()
      {
          string engineSubfolder = "fre_packages\\LibraryPackage\\Bin64";
          string engineDllFolder = Path.Combine(RoleEnvironment.GetLocalResource(LocalStorageName).RootPath, engineSubfolder);
          return engineDllFolder;
      }
  }
  ```
</Accordion>
