메인 콘텐츠로 건너뛰기
이 섹션에서는 Windows용 FRE 12 애플리케이션을 Azure Cloud Service에 배포하는 방법을 설명합니다. 예제로는 Azure Storage account의 컨테이너에 있는 파일을 처리하는 Worker를 소개합니다. 이 시나리오를 구현하려면 *.abbyy.com 라이선스 서버에 연결되는 온라인 라이선스를 사용합니다.
ABBYY Licensing Service는 한 번에 하나의 온라인 라이선스만 사용할 수 있습니다.
애플리케이션을 Cloud Service에 배포하려면 다음과 같은 여러 단계가 필요합니다:
  1. prerequisites에 따라 온라인 라이선스, 로컬 컴퓨터, 클라우드 인스턴스 준비하기
  2. 애플리케이션을 배포하기 전에 the preparatory steps 수행하기
  3. Cloud Service에 애플리케이션 배포하기
문서 처리에 ABBYY FineReader Engine 메서드를 사용하는 방법을 보여 주는 코드 샘플을 참조하세요.

사전 준비 사항

온라인 라이선스

온라인 라이선스를 사용하려면 영업 부서에서 다음 정보를 받아야 합니다.
  • Customer Project ID
  • 온라인 라이선스 토큰 파일
  • 라이선스 토큰 파일 비밀번호
ABBYY Licensing Service가 설치된 모든 환경에서 온라인 라이선스를 사용하려면 다음 조건을 충족해야 합니다.
  • 활성 인터넷 연결
  • 포트 443(HTTPS)을 통해 *.abbyy.com에 대한 연결이 허용되어야 함
  • 인증 기관용 GoDaddy 루트 인증서(반드시 로컬 컴퓨터의 신뢰할 수 있는 루트 인증 기관 인증서 저장소에 설치되어 있어야 합니다. 인증서에 대한 자세한 내용은 GoDaddy website를 참조하세요.)

로컬 컴퓨터

Cloud Service를 만들기 전에 다음 사양에 따라 로컬 컴퓨터를 준비합니다.
  • Visual Studio 2019 및 Azure용 애플리케이션 개발 모듈(Visual Studio의 Azure 기능을 확인하거나 Visual Studio Installer를 사용하여 해당 모듈 다운로드)
  • 손쉬운 디버깅을 위한 Cloud Service 에뮬레이터 및 스토리지(여기에서 자세한 정보 확인, Visual Studio Installer를 통해 다운로드)
  • 단일 Worker 역할 프로젝트가 포함된 Azure Cloud Service(extended preview)용 템플릿 솔루션(여기에서 자세한 정보 확인)
  • .NET Framework 4.7.2
  • Azure SDK(여기에서 다운로드)
  • Azure Storage 및 Blob 컨테이너 작업용 NuGet 패키지 - Azure.Storage.Blobs(여기에서 다운로드)
  • .NET Framework 4.7용 ABBYY FineReader Engine wrapper(Developer installation 후 C:\ProgramData\ABBYY\SDK\12\FineReader Engine\Inc.NET interops 폴더에 있음)
  • Blob 컨테이너 작업을 위해 재정의한 IFileWriter 인터페이스(sample 아래 참조)
  • Azure Storage Explorer(선택 사항 - 여기에서 다운로드)

Cloud Service 인스턴스

Cloud Service 인스턴스는 Azure에서 WorkerRole 프로젝트를 저장하는 데 사용됩니다. 이 인스턴스를 구성하려면 다음 사양을 사용하세요.
  • Service의 .NET Framework 버전
  • ABBYY FineReader Engine 배포를 위한 PowerShell
  • Azure SDK 업로드를 위한 NuGet 2.8.5.201 이상
  • PowerShell을 사용해 Azure Storage account로 작업하기 위한 Azure SDK

사전 준비 단계

사전 준비 단계는 로컬 컴퓨터에서 수행해야 합니다. 이 단계를 완료하면 애플리케이션 배포를 시작하는 데 필요한 모든 설정과 파일이 준비됩니다.
  1. ABBYY FineReader Engine 라이브러리와 Licensing Service용 아카이브 두 개를 만듭니다(예: LibraryPackage.zip 및 LSPackage.zip). FREngineDistribution.csv 파일을 사용하면 파일 목록을 자동으로 생성할 수 있습니다. ABBYY FineReader Engine과 라이선스 서버는 동일한 패키지의 것을 사용해야 합니다. 그렇지 않으면 호환성이 보장되지 않습니다.
  2. Azure Storage 계정(이 문서에서는 frestorage)을 만듭니다. 필요한 지침은 모두 Azure 웹사이트에서 확인할 수 있습니다.
  3. frestorage 안에 Blob 컨테이너 세 개를 만듭니다:
  • fre-lib - ABBYY FineReader Engine 파일용
  • fre-input - 입력 파일용
  • fre-output - 처리 결과용
  1. 가장 편한 방법(.NET, Powershell, Python 스크립트 또는 Azure Storage Explorer/Azure Portal 애플리케이션 사용)으로 LibraryPackage.zip 및 LSPackage.zip을 fre-lib 컨테이너에 업로드합니다.
예시로는 구성된 환경에서 작업하기 위해 WorkerRole 프로젝트를 사용합니다. 필요한 모든 구성 파일(.csdef 및 Cloud.cscfg)은 프로젝트를 생성하면 자동으로 만들어집니다.

Cloud Service에 ABBYY FineReader Engine 배포하기

새 WorkerRole 프로젝트에 ABBYY FineReader Engine을 배포하려면 다음과 같이 하십시오.
  1. 필요에 따라 Cloud.cscfg의 매개변수를 지정합니다.
  2. .csdef 파일의 매개변수를 지정합니다.
  • (선택 사항) WorkerRole 설정
  • (선택 사항) 가상 머신 크기
  • (필수) 역할의 로컬 저장소(LocalStorage 섹션 - 이 문서에서는 LocalStorage1이라는 이름의 저장소). ABBYY FineReader Engine 패키지가 올바르게 배포되도록 하려면 최소 3GB로 설정합니다.
  • (필수) 역할 시작 순서(코드 샘플 섹션의 코드 샘플 및 설정 사용)
  1. fre-input 컨테이너의 파일을 처리하고 처리 결과를 fre-output 컨테이너에 게시하도록 WorkerRole 프로젝트를 구현합니다.
  • Cloud Service가 작동할 수 있도록 준비하는 OnStart 메서드. 이 메서드는 엔진을 초기화하고 TLS 프로토콜을 설정하는 데 사용됩니다.
  • fre-input 컨테이너에서 가져온 파일을 주기적으로 처리하는 RunAsync 메서드. 이 메서드는 fre-input 컨테이너의 파일을 감지하고, 이를 메모리에서 처리한 다음 fre-output 컨테이너에 저장합니다(Processor.cs, IFileWriter.cs, Config.cs 참조).
  • Cloud Service 작업을 종료하는 OnStop 메서드. 이 메서드는 엔진을 종료하는 데 사용됩니다.

코드 샘플

이 섹션에는 역할 시작 순서와 ABBYY FineReader Engine 설정을 구성하는 데 사용되는 code samples가 포함되어 있습니다.
  • CleanUpOnStart - 이전 버전의 ABBYY FineReader Engine을 삭제하여 업데이트 절차를 단순화합니다(자세한 내용은 아래 CleanUpOnStart.cmdCleanUpOnStart.ps1 파일을 참조하세요).
  • PreparePoShModules - PowerShell이 Azure Storage와 함께 작동하는 데 필요한 SDK를 다운로드합니다(자세한 내용은 아래 PreparePoShModules.cmdPreparePoShModules.ps1 파일을 참조하세요).
  • PrepareLibrary - fre-lib 컨테이너에서 ABBYY FineReader Engine 라이브러리를 가져와 로컬 저장소에 압축을 풉니다(자세한 내용은 아래 PrepareLibrary.cmdPrepareLibrary.ps1 파일을 참조하세요).
  • PrepareLS - fre-lib 컨테이너에서 Licensing Service를 가져와 압축을 풀고 실행합니다(자세한 내용은 아래 PrepareLS.cmdPrepareLS.ps1 파일을 참조하세요).
위에 나열된 스크립트는 애플리케이션을 시작하기 전에 제안된 순서대로 정확히 실행해야 합니다. 스크립트 실행 순서를 사용자 지정하려면 다음 속성을 지정하세요.
  • taskType=“simple” - 작업이 한 번에 하나씩 동기적으로 실행됩니다.
  • executionContext=“elevated” - 관리자 권한으로 시작 스크립트를 실행합니다(애플리케이션 설치 및 LicensingService.exe 실행에 필요).
그 결과 Cloud Service가 관리할 수 있는 폴더가 생성됩니다. 이 폴더는 위에 나열된 스크립트가 ABBYY FineReader Engine을 업로드하고, 이후 샘플에서 사용할 FREngine.dll을 로드하는 데 사용됩니다.
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%
Write-Host "CleanUpOnStart.ps1 started...";
# 로컬 스토리지 경로(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 ("Resource folder was cleaned up.");
rem   스토리지 계정에 연결하고 ABBYY FineReader Engine 및 Licensing Service 패키지를 다운로드할 수 있도록 모듈을 준비하는 스크립트
 
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%
# 모듈 설치
Write-Host "PreparePoShModules.ps1 started...";
# Azure 모듈을 다운로드하기 위한 NuGet 공급자 설치
Write-Host "Installing NuGet package provider...";
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force;
 
# Blob 작업을 위한 Azure Storage 모듈 설치
Write-Host "Installing Az.Storage module...";
Install-Module -Name Az.Storage -Scope CurrentUser -Repository PSGallery -Force -AllowClobber;
Write-Host ("PoSh modules were prepared.");
rem   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%
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.");
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%
Write-Host "PrepareLS.ps1 started...";
# ABBYY FineReader Engine 및 Licensing Service 패키지가 포함된 container
$container_name = 'fre-lib';
# storage account 연결 문자열
$connection_string = "<connection_string_to_frestorage>";
Write-Host "Configuration";
Write-Host ("Container name: " + $container_name);
Write-Host ("Connection string: " + $storage_account);
# storage 객체에 연결
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;
# local storage 경로(see 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;
# standalone 모드로 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.");
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()
        {
            // 데이터가 기록된 후에도 액세스할 수 있도록 Dispose 시 memory stream 닫기
            stream.Close();
        }
        private string resultBlobName;
        private string fileExtension;
        private MemoryStream stream;
    }
}
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);
            }
        }
    }
}
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 sample에서와 동일한 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();
        }
    }
}
class Config
{
    // ServiceDefinition.csdef에 정의된 로컬 스토리지
    private static string LocalStorageName = "LocalStorage1";
    // blob container에 연결하는 연결 문자열
    public static readonly string ConnectionString = "<connection_string_to_frestorage>";
    // 스토리지의 입력 및 출력 container 이름
    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";
    }
 
    // 라이선스 password 반환
    public static String GetLicensePassword()
    {
        return "<Your_Online_License_token_password>";
    }
    // 엔진 경로 반환
    public static String GetEngineFolder()
    {
        string engineSubfolder = "fre_packages\\LibraryPackage\\Bin64";
        string engineDllFolder = Path.Combine(RoleEnvironment.GetLocalResource(LocalStorageName).RootPath, engineSubfolder);
        return engineDllFolder;
    }
}