Dear Team,
Below is my method for opening the document. When I am open the .pptx URL of size 188mb it takes 9-10 mins to open and .pdf of size 25mb takes 2-3 min to open. Can please identify where I am missing the logic to reduce the document opening time. Please suggest me best way to open the document at highest speed.
public async Task<IActionResult> OpenDocument(
string docpath = "",
string guid = "",
string watermark = "",
string UserName = "",
string Password = "",
string FileId = "")
{
var totalSw = System.Diagnostics.Stopwatch.StartNew();
string pathToFile = string.Empty;
string _annotations = string.Empty;
string psno = Request.Cookies["OneViewID"];
string tempFile = string.Empty;
System.Diagnostics.Debug.WriteLine("[DocOpen] ================= START =================");
try
{
// ── PATH RESOLUTION ───────────────────────────────────────────────
var pathSw = System.Diagnostics.Stopwatch.StartNew();
if (!string.IsNullOrEmpty(docpath))
{
try
{
pathToFile = Decrypt(CleanToDirty(docpath));
}
catch
{
pathToFile = docpath;
}
}
else
{
if (Request.Cookies["OneViewID"] == null)
{
return Json(new
{
success = false,
message = "Unauthorized"
});
}
var dbSw = System.Diagnostics.Stopwatch.StartNew();
var _fcshis = await _dbContext.FCSHIS
.FirstOrDefaultAsync(x => x.GUID == guid);
dbSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] FCSHIS Query: {dbSw.ElapsedMilliseconds}ms");
if (_fcshis == null)
{
return Json(new
{
success = false,
message = "Invalid guid."
});
}
if (DateTime.Now >
_fcshis.OpenDate.Value.AddMinutes(_fcshis.MaxMinAllowed.Value))
{
return Json(new
{
success = false,
message = "Time expired"
});
}
long documentId = Convert.ToInt64(_fcshis.DocumentId);
pathToFile = _fcshis.DocumentPath;
var annSw = System.Diagnostics.Stopwatch.StartNew();
_annotations = await _dbContext.FCSANN
.Where(x => x.PSNO == psno && x.DocumentId == documentId)
.Select(x => x.Annotations)
.FirstOrDefaultAsync() ?? string.Empty;
annSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Annotation Query: {annSw.ElapsedMilliseconds}ms");
}
pathSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Path Resolution: {pathSw.ElapsedMilliseconds}ms");
// ── FILE EXISTENCE ────────────────────────────────────────────────
bool isUrlPath =
pathToFile.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
pathToFile.StartsWith("https://", StringComparison.OrdinalIgnoreCase);
if (!isUrlPath && !System.IO.File.Exists(pathToFile))
{
Response.StatusCode = 404;
return Json(new
{
success = false,
message = $"File does not exist: {pathToFile}"
});
}
// ── FILE INFO ─────────────────────────────────────────────────────
var fileInfoSw = System.Diagnostics.Stopwatch.StartNew();
string fileExtension = Path.GetExtension(pathToFile).ToLower();
bool isLargeFile = false;
long fileSizeBytes = 0;
if (isUrlPath)
{
try
{
using var httpHead = new HttpClient();
httpHead.Timeout = TimeSpan.FromSeconds(15);
var headRequest = new HttpRequestMessage(HttpMethod.Head, pathToFile);
var headResponse = await httpHead.SendAsync(headRequest);
if (headResponse.Content.Headers.ContentLength.HasValue)
{
fileSizeBytes = headResponse.Content.Headers.ContentLength.Value;
isLargeFile = fileSizeBytes > 10 * 1024 * 1024;
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] HEAD Request Failed: {ex.Message}");
}
}
else
{
var fi = new FileInfo(pathToFile);
if (fi.Exists)
{
fileSizeBytes = fi.Length;
isLargeFile = fileSizeBytes > 10 * 1024 * 1024;
}
}
fileInfoSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] File Info: {fileInfoSw.ElapsedMilliseconds}ms");
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] File Size: {fileSizeBytes / 1024 / 1024}MB");
// ── LICENSES ──────────────────────────────────────────────────────
var licenseSw = System.Diagnostics.Stopwatch.StartNew();
var licenses = _cache.GetOrCreate("_docViewerLicenses", entry =>
{
entry.Priority = CacheItemPriority.NeverRemove;
return new List<string>
{
Path.Combine(_hostingEnvironment.WebRootPath, "Doconut.Viewer.lic"),
Path.Combine(_hostingEnvironment.WebRootPath, "Doconut.Viewer.Search.lic"),
Path.Combine(_hostingEnvironment.WebRootPath, "Doconut.Viewer.Annotation.lic")
};
});
licenseSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] License Load: {licenseSw.ElapsedMilliseconds}ms");
var docViewer = new Viewer(_cache, _accessor, licenses);
// ── BASE CONFIG ───────────────────────────────────────────────────
var configSw = System.Diagnostics.Stopwatch.StartNew();
var config = _cache.GetOrCreate($"_baseConfig_{fileExtension}", entry =>
{
entry.Priority = CacheItemPriority.NeverRemove;
return GetBaseConfig(new FileInfo("viewFile" + fileExtension));
});
configSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Base Config Load: {configSw.ElapsedMilliseconds}ms");
// ── RESOLUTION ────────────────────────────────────────────────────
int resolution;
if (fileExtension == ".ppt" || fileExtension == ".pptx")
{
if (fileSizeBytes > 150 * 1024 * 1024)
resolution = 72;
else if (fileSizeBytes > 75 * 1024 * 1024)
resolution = 85;
else if (fileSizeBytes > 25 * 1024 * 1024)
resolution = 95;
else
resolution = 110;
}
else
{
resolution = 100;
}
resolution = 200; // set to solve print generation zoom bug erported by kishan
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Resolution Selected: {resolution} DPI");
// ── OPTIONS ───────────────────────────────────────────────────────
var documentOptions = new DocOptions
{
Password = "",
ImageResolution = resolution,
TimeOut = isLargeFile ? 600 : 120
};
string cachePath = Path.Combine(_hostingEnvironment.WebRootPath, Startup.webFarmFolder);
if (Startup.useWebfarm)
{
documentOptions.IsWebfarm = true;
documentOptions.WebfarmPath = cachePath;
documentOptions.TimeOut = isLargeFile ? 300 : 60; // override timeout for webfarm
}
// ── CLEANUP TEMP FILES ────────────────────────────────────────────
var cleanupSw = System.Diagnostics.Stopwatch.StartNew();
try
{
string tempFolder =
Path.Combine(_hostingEnvironment.WebRootPath, "DoconutTempFiles");
if (!Directory.Exists(tempFolder))
Directory.CreateDirectory(tempFolder);
var oldFiles = Directory
.GetFiles(tempFolder, "DOCONUT_TEMP_*")
.Where(x =>
System.IO.File.GetCreationTime(x) <
DateTime.Now.AddHours(-2))
.ToList();
foreach (var oldFile in oldFiles)
{
try
{
System.IO.File.Delete(oldFile);
}
catch { }
}
}
catch { }
cleanupSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Temp Cleanup: {cleanupSw.ElapsedMilliseconds}ms");
// ── OPEN DOCUMENT ─────────────────────────────────────────────────
string token = string.Empty;
if (isUrlPath)
{
string tempFolder =
Path.Combine(_hostingEnvironment.WebRootPath, "DoconutTempFiles");
if (!Directory.Exists(tempFolder))
Directory.CreateDirectory(tempFolder);
tempFile = Path.Combine(
tempFolder,
$"DOCONUT_TEMP_{DateTime.Now:yyyyMMddHHmmssfff}_{Guid.NewGuid():N}{fileExtension}");
// ── DOWNLOAD ──────────────────────────────────────────────────
var downloadSw = System.Diagnostics.Stopwatch.StartNew();
using (var httpClient = new HttpClient())
{
httpClient.Timeout = TimeSpan.FromMinutes(15);
if (!string.IsNullOrWhiteSpace(UserName) &&
!string.IsNullOrWhiteSpace(Password))
{
var byteArray =
Encoding.ASCII.GetBytes($"{UserName}:{Password}");
httpClient.DefaultRequestHeaders.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue(
"Basic",
Convert.ToBase64String(byteArray));
}
using var response = await httpClient.GetAsync(
pathToFile,
HttpCompletionOption.ResponseHeadersRead);
if (!response.IsSuccessStatusCode)
{
return Json(new
{
success = false,
message =
$"Failed to download file. HTTP {(int)response.StatusCode}"
});
}
await using var networkStream =
await response.Content.ReadAsStreamAsync();
await using var fileStream = new FileStream(
tempFile,
FileMode.Create,
FileAccess.Write,
FileShare.None,
bufferSize: 1024 * 1024,
useAsync: true);
// ── FILE WRITE ────────────────────────────────────────────
var fileWriteSw = System.Diagnostics.Stopwatch.StartNew();
await networkStream.CopyToAsync(fileStream);
await fileStream.FlushAsync();
fileWriteSw.Stop();
long writtenSizeMb = 0;
try
{
if (System.IO.File.Exists(tempFile))
{
var writtenFileInfo = new FileInfo(tempFile);
writtenSizeMb = writtenFileInfo.Length / 1024 / 1024;
}
}
catch { }
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] File Write Completed | Size: {writtenSizeMb}MB | Time: {fileWriteSw.ElapsedMilliseconds}ms");
}
downloadSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] File Download Total: {downloadSw.ElapsedMilliseconds}ms");
// ── DOCONUT OPEN ──────────────────────────────────────────────
var openSw = System.Diagnostics.Stopwatch.StartNew();
token = await Task.Run(() =>
{
return docViewer.OpenDocument(
tempFile,
config,
documentOptions);
});
openSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Doconut OpenDocument: {openSw.ElapsedMilliseconds}ms");
// ── TEMP DELETE ───────────────────────────────────────────────
var deleteSw = System.Diagnostics.Stopwatch.StartNew();
try
{
if (System.IO.File.Exists(tempFile))
System.IO.File.Delete(tempFile);
}
catch { }
deleteSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Temp Delete: {deleteSw.ElapsedMilliseconds}ms");
}
else
{
var localOpenSw = System.Diagnostics.Stopwatch.StartNew();
token = await Task.Run(() =>
{
return docViewer.OpenDocument(
pathToFile,
config,
documentOptions);
});
localOpenSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Local OpenDocument: {localOpenSw.ElapsedMilliseconds}ms");
}
// ── POST PROCESSING ───────────────────────────────────────────────
var postSw = System.Diagnostics.Stopwatch.StartNew();
var tasks = new List<Task>();
if (!isLargeFile)
{
// ── ANNOTATIONS ───────────────────────────────────────────────
tasks.Add(Task.Run(() =>
{
var annotationSw = System.Diagnostics.Stopwatch.StartNew();
try
{
if (!string.IsNullOrEmpty(_annotations))
{
XmlDocument xml =
JsonConvert.DeserializeXmlNode(_annotations);
docViewer.LoadAnnotationXML(xml);
}
annotationSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[Annotations] Completed in {annotationSw.ElapsedMilliseconds}ms");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(
$"[Annotations] Skipped: {ex.Message}");
}
}));
// ── SEARCH ────────────────────────────────────────────────────
tasks.Add(Task.Run(() =>
{
var searchSw = System.Diagnostics.Stopwatch.StartNew();
try
{
var srhbytes = docViewer.SaveSearch();
if (srhbytes?.Length > 0)
{
string raw = System.Text.Encoding.UTF8.GetString(srhbytes);
string clean =
System.Text.RegularExpressions.Regex.Replace(
raw,
@"[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]",
string.Empty);
byte[] cleanBytes =
System.Text.Encoding.UTF8.GetBytes(clean);
docViewer.LoadSearchData(
new MemoryStream(cleanBytes)
{
Position = 0
});
}
searchSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[Search] Completed in {searchSw.ElapsedMilliseconds}ms");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(
$"[Search] Skipped: {ex.Message}");
}
}));
// ── EXPORT PNG ────────────────────────────────────────────────
if (Startup.useWebfarm)
{
tasks.Add(Task.Run(() =>
{
var pngSw = System.Diagnostics.Stopwatch.StartNew();
try
{
docViewer.ExportToPng(cachePath);
pngSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[ExportToPng] Completed in {pngSw.ElapsedMilliseconds}ms");
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(
$"[ExportToPng] Failed: {ex.Message}");
}
}));
}
}
else
{
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Large file — skipping Search, Annotations, ExportToPng");
}
if (tasks.Count > 0)
{
await Task.WhenAll(tasks);
}
postSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Post Processing Total: {postSw.ElapsedMilliseconds}ms");
// ── CACHE ─────────────────────────────────────────────────────────
var cacheSw = System.Diagnostics.Stopwatch.StartNew();
var cacheOpts = new MemoryCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromMinutes(30)
};
_cache.Set("docViewer-" + token, docViewer, cacheOpts);
_cache.Set("OriginalFilePath-" + token, pathToFile, cacheOpts);
cacheSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] Cache Save: {cacheSw.ElapsedMilliseconds}ms");
totalSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] TOTAL TIME: {totalSw.ElapsedMilliseconds}ms");
System.Diagnostics.Debug.WriteLine("[DocOpen] ================= END =================");
return Json(new
{
success = true,
token = token
});
}
catch (Exception e)
{
totalSw.Stop();
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] ERROR after {totalSw.ElapsedMilliseconds}ms");
System.Diagnostics.Debug.WriteLine(
$"[DocOpen] ERROR: {e}");
Response.StatusCode = 400;
return Json(new
{
success = false,
message = e.Message
});
}
finally
{
if (!string.IsNullOrEmpty(tempFile) &&
System.IO.File.Exists(tempFile))
{
try
{
System.IO.File.Delete(tempFile);
}
catch { }
}
}
}