Background:
On my most recent assignment, I was faced with the challenge of previewing a file from within a SharePoint site. The restriction was that you could not download it for security reasons yet needed to be shown in a preview. All that is exposed is an API to access the documents from a server in a secure location and you are to preview them in SharePoint online without copying it to any SharePoint document library or so. We achieved this by making use of a blob object. If we get the data as a blob, then using the SPFx webpart we can preview it directly from blob object without copying it to any location. Of course, not all types of documents can be previewed using this approach. In those cases, for which blob objects are not supported, the files have to be downloaded to the local system of the user assuming that the user has the permission to download and thus complying with the security requirement.
Steps to implement Blob Preview:
Create SPFX application
First, we need to create a basic SPFX application from the command prompt using the command “yo @microsoft/sharepoint” and follow the necessary steps as mentioned in this link https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part
Connect with libraries
Import the necessary libraries for connecting API, previewing files and creating blobs as shown below:
import FileViewer from 'react-file-viewer';
import b64toBlob from 'b64-to-blob';
import { HttpClient, IHttpClientOptions, HttpClientResponse } from '@microsoft/sp-http';
Create blob and URL
Get the document in base64 format from the API call.
Convert the data to blob based on the file type as shown below:
this.setState({ errorMessage: null, fileId: null, fileName: null, fileAuthor: null, filePath: null, fileContent: null },
() => {
this.callAPIWithFlow(apiTestFlowURL, this.state.fileType)
.then((response) => {
console.log("api response: ", response);
if (response["success"] == true) {
this.setState({
fileId: response["response"]["Id"],
fileName: response["response"]["Name"],
fileAuthor: response["response"]["Author"],
fileContent: response["response"]["body"]["$content"],
filePath: response["path"],
});
var blobImage = null;
if (this.state.fileType == "png" || this.state.fileType == "tif" || this.state.fileType == "tiff" || this.state.fileType == "jpg" || this.state.fileType == "jpeg" || this.state.fileType == "snag") {
blobImage = b64toBlob(this.state.fileContent, "image/" + this.state.fileType);
}
else if (this.state.fileType == "txt") {
blobImage = b64toBlob(this.state.fileContent, "text/html");
}
else {
blobImage = b64toBlob(this.state.fileContent, "application/octet-stream");
}
this.setState({ blobUrl: URL.createObjectURL(blobImage) });
} else {
this.setState({ errorMessage: response["errorMessage"] });
}
});
});
Also create the blob URL as shown above. At this stage, we have the blob ready for preview/download.
Preview document
The code snippet below specifies how we preview the document from blob object based on the file type in the SPFX render function.
{this.state.fileType == 'txt' ?
<div style={{ margin: 10 }}>
<iframe src={this.state.blobUrl} id='DocView' width='100%' height ='500px' frameBorder='0'></iframe>
</div>
:
this.state.fileType == 'tif' ?
<div style={{ margin: 10 }}>
<img src={`data:image/` + this.state.fileType + `;base64,${this.state.fileContent}`} />
</div>
:
<div style={{ margin: 10, height: 400 }}>
<FileViewer style={{ height: 400 }} fileType={this.state.fileType} filePath={this.state.blobUrl} />
</div>
}
Constraints
Let us look at few downsides of this approach. The limitations stem from the fact that the File viewer does not support all file types. Some of it can be handled by code and others using SharePoint permissions.
- For file types which can be previewed from blob object, the documents are previewed in an iframe as shown in the last code snippet.
- For file types that cannot be previewed, the only option is to download. We can give the users permission to be able to download the files which cannot be previewed (mostly non-office files). This way the security of the documents can be maintained efficiently.
Sample Application
The below sample has the preview area in the right end which displays the file viewer/iframe-based preview, depending on the document type selected from the list of documents shown in the left. The list of documents is obtained from the API call to the server which is provided by the client.
Conclusion
So, what have we really got here? For most cases, one would use an API to copy documents in a document library where the documents will be stored and then preview can be made. The permissions to this library can be restrictive and a user can only view the document. The trouble starts when the API provided does not allow you to copy the file over and just may be the case with increasing concern for confidentiality and security. Under such a scenario, you can make use of the blob to render a preview of the content of the file without actually downloading or making a copy of it. And of course, once you have the file in a blob, you can dig deeper !
Feel free to contact me for any further details. Happy blobbing.
Can I have this code which stored in any github repository?