You can use any file storage. The example can be found in this Sample Application. I’ve cut the most important parts to give you an idea of how it can be configured.
using GroupDocs.Viewer;
using GroupDocs.Viewer.UI.Core;
using GroupDocs.Viewer.UI.Core.Entities;
using GroupDocs.Viewer.UI.SelfHost.Api;
...
public void ConfigureServices(IServiceCollection services)
{
services.AddTransient<IFileStorage, MyFileStorage>();
services.AddTransient<IFileTypeResolver, MyFileTypeResolver>();
...
class MyFileStorage : IFileStorage
{
public Task<IEnumerable<FileSystemEntry>> ListDirsAndFilesAsync(string dirPath)
{
throw new NotImplementedException();
}
public Task<byte[]> ReadFileAsync(string filePath)
{
// Read file from any storage here
return File.ReadAllBytesAsync("./Storage/sample.docx");
}
public Task<string> WriteFileAsync(string fileName, byte[] bytes, bool rewrite)
{
throw new NotImplementedException();
}
}
class MyFileTypeResolver : IFileTypeResolver
{
public Task<FileType> ResolveFileTypeAsync(string filePath)
{
// resolve file type by file path
return Task.FromResult<FileType>(FileType.DOCX);
}
}
Since you’re going to read the file from your custom storage you can implement IFileTypeResolver to avoid automatic file type detection based on magic numbers and file contents analysis.
Thank you for your quick response Vladimir, really appreciate it.
I’ve run the sample app and roughly get the idea. I will study it more on how to gel with our application design.
Probably one more doubt, regarding the cache. If it’s required, is there a way for “auto” cleanup? We intend to render document as a whole (all pages).
You’re welcome! Auto cleanup is not implemented for the file cache, so the files are always there. You can use In Memory Cache where you can specify the lifetime for cache entries (link to the source code).
I’m using the Sample Application (sample-viewer-app) that you sent, and trying to view PDF document. I’ve modified the source file to a PDF file, and also the FileTypeResolver to use FileType.PDF. But I encountered error from Aspose.PDF:
System.NullReferenceException
HResult=0x80004003
Message=Object reference not set to an instance of an object.
Source=Aspose.PDF
StackTrace:
at #=z53DiufXzQJ_xboSmAwF1lzdRU5nPOMxgig==.#=z_ul7S4OCg2c0bpYl6w==(#=z7DkZdtMHbbsf$k1nHCBKOt6FbULB #=zZ0x0cFo=)
Also, is there way to set Viewer’s language? I see there’s Supported and Default language. But since our application is multi language, we’d like to set the language on each document viewing.
Can you share the app that you’ve got and the sample file you’re trying to view? Which environment you’re running the app?
Such a feature is not supported out of the box. But you can make a custom endpoint e.g. /my-viewer-config where you can decide which language is the default. Not that you have to keep config in AddGroupDocsViewerUI and your custom one in sync (Sample App).
For the first issue of loading PDF file, it’s working on other machines.
As for the language config, yes this solution also works.
Now we have another issue. Our application have certain routing codes for different clients. So the pattern is like “/{routecode}/viewer” . However the {routecode} is read as plain string instead of pattern.
The static resources are redirected to here:
/%7Broutecode%7D/viewer/runtime.js
/%7Broutecode%7D/viewer/polyfills.js
/%7Broutecode%7D/viewer/main.js
Still encounter the same error. I believe it’s because the index.html content, is still using the plain string itself. Please refer to my screenshot document (I run GroupDocs.Viewer.UI sample and just change the endpoints mapping to
The issue has been fixed for UIPath, so it is supports route templates with parameters. In case you keep APIEndpoint and ApiPath static it would work. Please check this viewer-net-ui.zip (2.5 KB) sample app as a demonstration.
The main “viewer” is successfully loaded, yes, because it’s the first hit. But when the viewer load, the HTML base is set to literal string of uipath image.png (2.7 KB)
which then will request to /%7Bcode%7D/viewer/runtime.js, instead of /AAA/viewer/runtime.js image.png (6.4 KB)
In our case, this routecode is used by load balancer to route to respective server the routecode belongs to (we also need the same for other paths and endpoint). Otherwise the request will not reach the web server.