Indicates the timestamp when this job started.
public string JobStartedTimestamp { get; set; }
The timestamp when this job has started. The default value is null.
This property is a string that contains the timestamp in UTC using "yyyy-MM-ddTHH:mm:ss" format. Use DateTime.Parse to parse it and DateTime.ToLocalTime to convert it to a local time string.
using Leadtools;using Leadtools.Codecs;using Leadtools.Document.Writer;using Leadtools.Svg;using LeadtoolsExamples.Common;using Leadtools.Document;using Leadtools.Caching;using Leadtools.Annotations.Engine;using Leadtools.Ocr;using Leadtools.Document.Converter;using Leadtools.Annotations.Rendering;// This is Server.exe, gets a StatusJobData as JSON from the command line and run itclass Server{public static void Main(string[] args){Console.WriteLine("Server running the job");StatusJobData jobData = null;// The command line contain the path to a StatusJobData saved as JSON, load itstring jsonFile = args[0];using (var stream = File.OpenRead(jsonFile)){var jsonSerializer = new DataContractJsonSerializer(typeof(StatusJobData));jobData = jsonSerializer.ReadObject(stream) as StatusJobData;}// Run itusing (var runner = new StatusJobDataRunner()){runner.Prepare(jobData);runner.Run();}}// This is Client.execlass Client{public static void Main(string[] args){// We will be converting this TIFF file to PDFstring imageUrl = "https://demo.leadtools.com/images/tiff/ocr.tif";// Download the final document to this filestring outputFile = @"c:\temp\output.pdf";// Setup the cacheFileCache cache = new FileCache();// This should be changed to a network location if the service and client are not on the same machine// Or use something like the Redis cache that supports access from multiple processes and machinescache.CacheDirectory = @"c:\temp\cache";string documentId = LoadDocumentIntoCache(cache, imageUrl);// Setup the StatusJobData we will use for conversionvar jobData = SetupJobData(cache, documentId);// We are ready, save the statusJobData as a JSON file and call the servicestring tempFile = null;using (var ms = new MemoryStream()){var jsonSerializer = new DataContractJsonSerializer(typeof(StatusJobData));jsonSerializer.WriteObject(ms, jobData);// Save it to a temp filestring json = Encoding.UTF8.GetString(ms.ToArray());tempFile = Path.GetTempFileName();File.WriteAllText(tempFile, json);}// We are ready, call the Server to perform the conversion and monitor the status of the jobProcess.Start("Server.exe", tempFile);bool isDone = false;StatusJobData statusJobData = null;while (!isDone){// We could abort at any time by calling this// StatusJobDataRunner.AbortJob(cache, jobData.UserToken, jobData.JobToken);// Get the status of the jobstatusJobData = StatusJobDataRunner.QueryJobStatus(cache, jobData.UserToken, jobData.JobToken);if (statusJobData != null){// Print the status messageConsole.WriteLine("Status {0} IsCompleted {1} Abort {2} started at {3} jobStatus at {4} query at {5} - {6}",statusJobData.JobStatus, statusJobData.IsCompleted, statusJobData.Abort,ToLocalTime(statusJobData.JobStartedTimestamp),ToLocalTime(statusJobData.JobStatusTimestamp),ToLocalTime(statusJobData.QueryJobStatusTimestamp),statusJobData.JobStatusMessage);if (statusJobData.IsCompleted){Console.WriteLine("Completed");// The job has been completed, check the error messages (if any)var errorMessages = statusJobData.ErrorMessages;if (errorMessages != null && errorMessages.Length > 0){foreach (var errorMessage in errorMessages)Console.WriteLine("{0}", errorMessage);}}isDone = statusJobData.IsCompleted;}else{Console.WriteLine("Did not start yet");}// Breathe for a little bitThread.Sleep(100);}// Delete the jobStatusJobDataRunner.DeleteJob(cache, jobData.UserToken, jobData.JobToken);// If successful, download the documentif (statusJobData.JobStatus != DocumentConverterJobStatus.Aborted){Console.WriteLine("Downloading the document");using (var stream = File.Create(outputFile)){var downloadDocumentOptions = new DownloadDocumentOptions();downloadDocumentOptions.Cache = cache;downloadDocumentOptions.DocumentId = statusJobData.OutputDocumentUri.ToString();downloadDocumentOptions.Offset = 0;downloadDocumentOptions.Length = -1;downloadDocumentOptions.Stream = stream;DocumentFactory.DownloadDocument(downloadDocumentOptions);}}File.Delete(tempFile);// Finally, delete the document from the cache since we finished itvar deleteFromCacheOptions = new LoadFromCacheOptions();deleteFromCacheOptions.Cache = cache;deleteFromCacheOptions.DocumentId = documentId;DocumentFactory.DeleteFromCache(deleteFromCacheOptions);// Show the final documentif (statusJobData.JobStatus != DocumentConverterJobStatus.Aborted){Process.Start(outputFile);}}private static string LoadDocumentIntoCache(ObjectCache cache, string url){// Load the document and save it to the cachevar loadDocumentOptions = new LoadDocumentOptions();loadDocumentOptions.Cache = cache;Console.WriteLine("Client loading and saving document into the cache");string documentId;using (LEADDocument document = DocumentFactory.LoadFromUri(new Uri(url), loadDocumentOptions)){// Store the document ID to use it laterdocumentId = document.DocumentId;// Make sure the document persist on the cache after we dispose itdocument.AutoSaveToCache = false;document.AutoDeleteFromCache = false;document.SaveToCache();}return documentId;}private static StatusJobData SetupJobData(ObjectCache cache, string documentId){var jobData = new StatusJobData();//// Status section//// First, we need a unique job token, create it from a new GUIDjobData.JobToken = Guid.NewGuid().ToString().Replace("-", "");// Next, we need a user token (ID)jobData.UserToken = "TestUser";// We will use the same cache for all operations, so set it once// We will use the cache ability to save its configuration and a policy as a simple string// And since we are using a configuration, we do not need the other cache objectsjobData.StatusCacheConfiguration = cache.GetConfigurationString();jobData.StatusCachePolicy = new CacheItemPolicy().ToParsableString();jobData.StatusCache = null;jobData.StatusCacheItemPolicy = null;// If we have any user data, set it here, let us set a simple stringjobData.UserData = "MyUserData";// The following members:// JobStatus, JobStatusPageNumber, JobStatusMessage, IsCompleted, Abort, JobStartedTimestamp, JobCompletedTimestamp, JobStatusTimestamp, QueryJobStatusTimestamp and ErrorMessages// Are used when querying the job, so no need to set them here//// Options section//// For the document converter, we will create one and use its options// To use the default options or if the settings are set on the server, then leave this to null.using (var documentConverter = new DocumentConverter()){documentConverter.Options.EnableSvgConversion = true;documentConverter.Options.JobErrorMode = DocumentConverterJobErrorMode.Continue;// Save the options as a simple stringjobData.DocumentConverterOptions = documentConverter.Options.SaveToString();// Do not use the objectjobData.DocumentConverter = null;}// Similar for the document writer options, if nothing is required// To use the default options or if the settings are set on the server, then leave this to null.var documentWriter = new DocumentWriter();var pdfOptions = documentWriter.GetOptions(DocumentFormat.Pdf) as PdfDocumentOptions;pdfOptions.ImageOverText = true;pdfOptions.DocumentType = PdfDocumentType.PdfA;documentWriter.SetOptions(DocumentFormat.Pdf, pdfOptions);using (var ms = new MemoryStream()){documentWriter.SaveOptions(ms);jobData.DocumentWriterOptions = Encoding.UTF8.GetString(ms.ToArray());}// And the OCR options to use// To use the default options or if the settings are set on the server, then leave this to null.using (var ocrEngine = OcrEngineManager.CreateEngine(OcrEngineType.LEAD)){ocrEngine.Startup(null, null, null, null);using (var ms = new MemoryStream()){var ocrWriteXmlOptions = new OcrWriteXmlOptions();ocrWriteXmlOptions.Formatted = false;ocrEngine.SettingManager.Save(ms, ocrWriteXmlOptions);// Set the OCR engine name and settingsjobData.OcrEngineName = ocrEngine.EngineType.ToString();jobData.OcrEngineSettings = Encoding.UTF8.GetString(ms.ToArray());}}//// Input section//// We will use the same cache, so no need to set the input cache, just the document ID// Leaving InputCacheConfiguration and InputCache as nulljobData.InputCacheConfiguration = null;jobData.InputCache = null;jobData.InputDocumentId = documentId;// We will convert all pages, so leave the default values for InputDocumentFirstPageNumber and InputDocumentLastPageNumberjobData.InputDocumentFirstPageNumber = 0;jobData.InputDocumentLastPageNumber = 0;//// Output section//// We will use the same cache, so no need to set the output cache or any of its policies, just the document IDjobData.OutputCacheConfiguration = null;jobData.OutputCachePolicy = null;jobData.OutputCache = null;jobData.OutputCacheItemPolicy = null;// For the output document, we could pass the OutputDocumentId if we want to specify the ID of the output document or leave it null to let the service create onejobData.OutputDocumentId = null;// OutputDocumentUri is for output, so leave it for now// We can set a name for the document, or leave it null to use the default (will be the name part of the input URL)jobData.OutputDocumentName = null;//// Conversion options//jobData.DocumentFormat = DocumentFormat.Pdf;jobData.RasterImageFormat = RasterImageFormat.Unknown;jobData.RasterImageBitsPerPixel = 24;jobData.JobName = "MyJob"; // OptionaljobData.AnnotationsMode = DocumentConverterAnnotationsMode.None;return jobData;}private static string ToLocalTime(string timestamp){if (string.IsNullOrEmpty(timestamp))return "not set";var date = DateTime.Parse(timestamp);date = date.ToLocalTime();return date.ToString("T");}}