Take the following steps to create a worker assembly for the Distributed Computing (Job Processor) SDK. Assume the Job Processor is to convert images from any supported format to PDF using one of the LEADTOOLS Imaging SDKs. This tutorial is meant to be used in conjunction with another tutorial (Adding Jobs to the Job Processor), which demonstrates how to add jobs to the Job Processor with a custom job type. This tutorial creates the worker assembly capable of actually processing these jobs. For the sake of simplicity, assume the client and worker are on the same machine.
Start Visual Studio
Choose File->New->Project from the menu
In the New Project dialog box, choose either "Visual C# Projects" or "VB Projects" in the Projects Type List, and choose "Class Library" from the Templates List.
Type the project name as "JobProcessorCreatingWorkersTutorial" in the Project Name field, and then click OK. If desired, type a new location for your project or select a directory using the Browse button, and then click OK.
Change the project build configuration to x86. If this configuration does not exist, add it by performing the following steps:
Open the configuration manager.
Under 'Platform', choose 'New'.
Choose 'x86' for 'New Platform' and click 'OK'.
In the "Solution Explorer" window, right-click the "References" folder, and select "Add Reference..." from the context menu. In the "Add Reference" dialog box, select the ".NET" tab and browse to the "<LEADTOOLS_INSTALLDIR>\Bin\DotNet or DotNet4\Win32" folder, and select the following DLLs:
Switch to Class1 code view (Double-click Class1.cs in the solution explorer) and add the following lines at the beginning of the file after any Imports or using statements if they exist.
Imports Leadtools.JobProcessor.JobImports System.IOImports System.Xml.SerializationImports LeadtoolsImports Leadtools.CodecsImports System.Threading
using Leadtools.JobProcessor.Job;using System.IO;using System.Xml.Serialization;using Leadtools;using Leadtools.Codecs;using System.Threading;
Public Class MyCustomWorker : Inherits JobBaseEnd Class
public class MyCustomWorker : JobBase{}
Public Sub New(ByVal job As IJob)MyBase.New(job)'If using a licensed copy, add your license information below.Dim MY_LICENSE_FILE As String = "d:\temp\TestLic.lic"Dim MY_DEVELOPER_KEY As String = "xyz123abc"RasterSupport.SetLicense(MY_LICENSE_FILE, MY_DEVELOPER_KEY);End Sub'This method will be used to store the conversion settings (source and target file in this simple demo).'The settings were serialized when the client submitted the job. Now, the worker assembly will deserialize it to obtain the settings.Public Structure JobMetadataPublic SourceFile As StringPublic TargetFile As StringPublic Sub New(ByVal _sourceFile As String, ByVal _targetFile As String)SourceFile = _sourceFileTargetFile = _targetFileEnd SubEnd StructurePrivate jobID As String = String.EmptyPrivate loadProgress As Integer = 0Private saveProgress As Integer = 0'Deserialize the JobMetadataPublic Function DeserializeFromString(ByVal serializedString As String) As JobMetadataDim serializedBytes As Byte() = Encoding.Unicode.GetBytes(serializedString)Using ms As MemoryStream = New MemoryStream(serializedBytes)Dim xmlSerializer As XmlSerializer = New XmlSerializer(GetType(JobMetadata))Return CType(xmlSerializer.Deserialize(ms), JobMetadata)End UsingEnd FunctionPublic Overrides Sub OnJobReceived(ByVal id As String, ByVal userToken As String, ByVal jobMetadata As String, ByVal jobType As String, ByVal progressRate As Integer)TryjobID = idloadProgress = 0saveProgress = 0' Determine whether the job information and job metadata is validIf String.IsNullOrEmpty(jobMetadata) ThenSetFailureStatus(id, CInt(RasterExceptionCode.InvalidParameter), Leadtools.RasterException.GetCodeMessage(RasterExceptionCode.InvalidParameter), Nothing)ReturnEnd If'Deserialize the jobMetadata in order to get the conversion settingsDim conversionSettings As JobMetadata = DeserializeFromString(jobMetadata)Using updateStatusTimer As Timer = New Timer(New TimerCallback(AddressOf UpdateStatusProc), Nothing, 0, progressRate * 1000)Using codecs As RasterCodecs = New RasterCodecs()codecs.Options.Save.RetrieveDataFromImage = trueAddHandler codecs.LoadImage, AddressOf Of CodecsLoadImageEventArgsAddHandler codecs.SaveImage, AddressOf Of CodecsSaveImageEventArgsUsing img As RasterImage = codecs.Load(conversionSettings.SourceFile)codecs.Save(img, conversionSettings.TargetFile, Leadtools.RasterImageFormat.RasPdfLzw, 0)SetCompletedStatus(id, jobMetadata)End UsingEnd UsingEnd UsingCatch ex As ExceptionSetFailureStatus(id, 0, ex.Message, Nothing)End TryEnd SubPrivate Sub codecs_SaveImage(ByVal sender As Object, ByVal e As CodecsSaveImageEventArgs)'Update the save progresssaveProgress = e.TotalPercentEnd SubPrivate Sub codecs_LoadImage(ByVal sender As Object, ByVal e As CodecsLoadImageEventArgs)'Update the load progressloadProgress = e.TotalPercentEnd SubPrivate Sub UpdateStatusProc(ByVal stateInfo As Object)Try' Always report status when the report status interval elapses: otherwise,' the windows service will assume the job has hung and kill the process.'The load and save progress are separate, so we must combine them as 1Dim totalProgress As Integer = (loadProgress / 2) + (saveProgress / 2)UpdatePercentage(jobID, totalProgress, String.Empty)Catch ex As ExceptionSetFailureStatus(jobID, 0, ex.Message, Nothing)End TryEnd Sub
public MyCustomWorker(IJob job): base(job){//If using a licensed copy, add your license information below.string MY_LICENSE_FILE = "d:\\temp\\TestLic.lic";string MY_DEVELOPER_KEY = "xyz123abc";RasterSupport.SetLicense(MY_LICENSE_FILE, MY_DEVELOPER_KEY);}//This method will be used to store the conversion settings (source and target file in this simple demo).//The settings were serialized when the client submitted the job. Now, the worker assembly will deserialize it to obtain the settings.public struct JobMetadata{public string SourceFile;public string TargetFile;public JobMetadata(string _sourceFile, string _targetFile){SourceFile = _sourceFile;TargetFile = _targetFile;}}string jobID = String.Empty;int loadProgress = 0;int saveProgress = 0;//Deserialize the JobMetadatapublic JobMetadata DeserializeFromString(string serializedString){byte[] serializedBytes = Encoding.Unicode.GetBytes(serializedString);using (MemoryStream ms = new MemoryStream(serializedBytes)){XmlSerializer xmlSerializer = new XmlSerializer(typeof(JobMetadata));return (JobMetadata)xmlSerializer.Deserialize(ms);}}public override void OnJobReceived(string id, string userToken, string jobMetadata, string jobType, int progressRate){try{jobID = id;loadProgress = 0;saveProgress = 0;// Check if we have valid job information and job metadataif (String.IsNullOrEmpty(jobMetadata)){SetFailureStatus(id, (int)RasterExceptionCode.InvalidParameter, Leadtools.RasterException.GetCodeMessage(RasterExceptionCode.InvalidParameter), null);return;}//Deserialize the jobMetadata to get the conversion settingsJobMetadata conversionSettings = DeserializeFromString(jobMetadata);using (Timer updateStatusTimer = new Timer(new TimerCallback(UpdateStatusProc), null, 0, progressRate * 1000)){using (RasterCodecs codecs = new RasterCodecs()){codecs.Options.Save.RetrieveDataFromImage = true;codecs.LoadImage += new EventHandler<CodecsLoadImageEventArgs>(codecs_LoadImage);codecs.SaveImage += new EventHandler<CodecsSaveImageEventArgs>(codecs_SaveImage);using (RasterImage img = codecs.Load(conversionSettings.SourceFile)){codecs.Save(img, conversionSettings.TargetFile, Leadtools.RasterImageFormat.RasPdfLzw, 0);SetCompletedStatus(id, jobMetadata);}}}}catch (Exception ex){SetFailureStatus(id, 0, ex.Message, null);}}void codecs_SaveImage(object sender, CodecsSaveImageEventArgs e){//Update the save progresssaveProgress = e.TotalPercent;}void codecs_LoadImage(object sender, CodecsLoadImageEventArgs e){//Update the load progressloadProgress = e.TotalPercent;}private void UpdateStatusProc(Object stateInfo){try{// Always report status when the report status interval elapses: otherwise,// the windows service will assume the job has hung and kill the process.//The load and save progress are separate, so we must combine them as 1int totalProgress = (loadProgress / 2) + (saveProgress / 2);UpdatePercentage(jobID, totalProgress, String.Empty);}catch (Exception ex){SetFailureStatus(jobID, 0, ex.Message, null);}}
The Workers.config file for the WorkerService WCF Service needs to be updated to handle this type of job. Perform the following steps to update the file.
Open Workers.xml in the App_Data directory of the WorkerService WCF Service.
Add the new job type under the machine that will be the worker (see below). In Adding Jobs to the Job Processor, we used a custom job type of 'ConvertToPDF' so we need to use that same job type here.
<Workers> <Worker Name="MachineName" NewJobCheckPeriod="2"> <JobTypes> <JobType Name="ConvertToPDF" MaxNumberOfJobs="5" CpuThreshold="80" UseCpuThreshold="false" ProgressRate="10" AssumeHangAfter="60" Attempts="3"/> </JobTypes> </Worker> </Workers>
Now we need to update the windows service configuration file on the worker (app.config) with the new job type, and add some information about our new assembly (see below for example). Perform the following steps to update the file.
Open the windows service configuration file on the worker (app.config).
Update the 'JobType' to 'ConvertToPDF'.
Update the 'UserDllPath' so that it points to the location of your customer worker assembly.
Update the 'UserClassTypeName' to the name of the namespace and class in your worker assembly that will do the work (JobProcessorCreatingWorkersTutorial.MyCustomWorker).
<userSettings> <Leadtools.JobProcessor.WorkerService.Properties.Settings> <setting name="UserClassTypeName" serializeAs="String"> <value>JobProcessorCreatingWorkersTutorial.MyCustomWorker</value> </setting> <setting name="JobType" serializeAs="String"> <value>ConvertToPDF</value> </setting> <setting name="WorkerLayerPath" serializeAs="String"> <value>Path to Leadtools.JobProcessor.Workerlayer.exe</value> </setting> <setting name="UserDllPath" serializeAs="String"> <value>Path to your worker assembly</value> </setting> </Leadtools.JobProcessor.WorkerService.Properties.Settings> </userSettings>
The worker assembly is now ready to process jobs. If you have not already done so, add jobs to the Job Processor using the project you created in Adding Jobs to the Job Processor. After jobs are added, start the windows service on the worker so that it can begin processing jobs.
NOTE: If you encounter an "Invalid File Format" or "Feature Not Supported" exception, refer to the Invalid File Format/Feature Not Supported topic.
LEADTOOLS Job Processor Settings Understanding The LEADTOOLS Job Processor Database Creating Job Processor Worker Assemblies Deploying LEADTOOLS Distributed Computing (JobProcessor) Applications Unlocking Special LEAD Features