xtrareports-devexpress-dot-xtrareports-dot-web-dot-webdocumentviewer-6c29da6b.md
Implements custom authorization to restrict access to exported documents in a web reporting application.
Namespace : DevExpress.XtraReports.Web.WebDocumentViewer
Assembly : DevExpress.XtraReports.v25.2.Web.dll
NuGet Package : DevExpress.Web.Reporting.Common
public interface IExportingAuthorizationService
Public Interface IExportingAuthorizationService
The Document Viewer queries the IExportingAuthorizationService service when the control performs the asynchronous print or export operations.
For access control purposes, all operations can be classified by the object that the document viewer processes in a particular operation. The objects are:
The IWebDocumentViewerAuthorizationService service allows you to control access to the report, generated documents and to the results of synchronous export. The IExportingAuthorizationService allows you to restrict access to the document resulted from asynchronous export.
Tip
Review the following topic for more information on the Document Viewer operations: Document Viewer Lifecycle
When export is performed synchronously, the resulting document is generated in the same request, and you can use the IWebDocumentViewerAuthorizationService.CanReadDocument method for access check.
When export is performed asynchronously (the AsyncExportApproach is true ), the exported document is stored on the server, and the Document Viewer requests the document by an URL. In this situation you can register the IExportingAuthorizationService service and use the CanReadExportedDocument method to perform access check.
When you implement these methods, you need information about the current user and id assigned to the document generated in an asynchronous export operation. Implement the WebDocumentViewerOperationLogger interface to gather all the required information.
View Example: Implement User Authorization
The following code is a custom interface implementation that allows authorized users to view the report in the Document Viewer. A custom WebDocumentViewerOperationLogger service populates dictionaries with the user id, report id, document id and asynchronous operation id. The IWebDocumentViewerAuthorizationService controls access to reports and documents, the IExportingAuthorizationService controls access to the asynchronously exported document.
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.WebDocumentViewer;
using System.Collections.Concurrent;
using System.Web;
using System;
using DevExpress.XtraPrinting;
using DevExpress.XtraReports.Web.ClientControls;
namespace AuthorizationService.Services {
public class OperationLogger: WebDocumentViewerOperationLogger,
IWebDocumentViewerAuthorizationService,
IExportingAuthorizationService
{
public override void ReportOpening(string reportId, string documentId, XtraReport report)
{
if (HttpContext.Current.Session == null) {
return;
}
SaveUsedEntityId(Constants.ReportDictionaryName, reportId);
SaveUsedEntityId(Constants.DocumentDictionaryName, documentId);
}
public override void BuildStarted(string reportId, string documentId,
ReportBuildProperties buildProperties)
{
SaveUsedEntityId(Constants.ReportDictionaryName, reportId);
SaveUsedEntityId(Constants.DocumentDictionaryName, documentId);
}
public override ExportedDocument ExportDocumentStarting(string documentId,
string asyncExportOperationId, string format, ExportOptions options,
PrintingSystemBase printingSystem, Func<ExportedDocument> doExportSynchronously)
{
SaveUsedEntityId(Constants.ExportedDocumentDictionaryName, asyncExportOperationId);
return base.ExportDocumentStarting(documentId, asyncExportOperationId, format, options,
printingSystem, doExportSynchronously);
}
public override void ReleaseDocument(string documentId) {
}
bool IWebDocumentViewerAuthorizationService.CanCreateDocument() {
return CheckUserAuthorized();
}
bool IWebDocumentViewerAuthorizationService.CanCreateReport() {
return CheckUserAuthorized();
}
bool IWebDocumentViewerAuthorizationService.CanReadDocument(string documentId) {
return CheckEntityAvailability(Constants.DocumentDictionaryName, documentId);
}
bool IWebDocumentViewerAuthorizationService.CanReadReport(string reportId) {
return CheckEntityAvailability(Constants.ReportDictionaryName, reportId);
}
bool IWebDocumentViewerAuthorizationService.CanReleaseDocument(string documentId) {
return CheckEntityAvailability(Constants.DocumentDictionaryName, documentId);
}
bool IWebDocumentViewerAuthorizationService.CanReleaseReport(string reportId) {
return CheckEntityAvailability(Constants.ReportDictionaryName, reportId);
}
public bool CanReadExportedDocument(string exportDocumentId) {
return CheckEntityAvailability(Constants.ExportedDocumentDictionaryName, exportDocumentId);
}
bool CheckUserAuthorized() {
var user = HttpContext.Current.User;
if (user == null || user.Identity == null || !user.Identity.IsAuthenticated)
{
return false;
}
return true;
}
void SaveUsedEntityId(string dictionaryName, string id) {
if (string.IsNullOrEmpty(id))
return;
ConcurrentDictionary<string, bool> dictionary = null;
lock (HttpContext.Current.Session.SyncRoot) {
if (HttpContext.Current.Session[dictionaryName] == null)
HttpContext.Current.Session[dictionaryName] = dictionary
= new ConcurrentDictionary<string, bool>();
}
if (dictionary == null)
dictionary = ((ConcurrentDictionary<string, bool>)HttpContext.Current.
Session[dictionaryName]);
dictionary.AddOrUpdate(id, false, (_1, _2) => false);
}
bool CheckEntityAvailability(string dictionaryName, string id) {
if (string.IsNullOrEmpty(id) || !CheckUserAuthorized())
return false;
lock (HttpContext.Current.Session.SyncRoot) {
if (HttpContext.Current.Session[dictionaryName] == null)
return false;
}
return
((ConcurrentDictionary<string, bool>)HttpContext.Current.
Session[dictionaryName]).ContainsKey(id);
}
void DisposeEntityRequested(string dictionaryName, string id) {
if (string.IsNullOrEmpty(id))
return;
lock (HttpContext.Current.Session.SyncRoot) {
if (HttpContext.Current.Session[dictionaryName] == null)
return;
}
((ConcurrentDictionary<string, bool>)HttpContext.Current.
Session[dictionaryName]).AddOrUpdate(id, true, (_1, _2) => true);
}
}
}
Imports DevExpress.XtraReports.Web.WebDocumentViewer
Imports System.Collections.Concurrent
Imports System.Web
Imports System
Imports DevExpress.XtraReports.UI
Imports DevExpress.XtraPrinting
Imports DevExpress.XtraReports.Web.ClientControls
Namespace AuthorizationService.Services
Public Class OperationLogger
Inherits WebDocumentViewerOperationLogger
Implements IWebDocumentViewerAuthorizationService, IExportingAuthorizationService
#Region "WebDocumentViewerOperationLogger"
Public Overrides Sub ReportOpening(ByVal reportId As String, ByVal documentId As String,
ByVal report As XtraReport)
If HttpContext.Current.Session Is Nothing Then
Return
End If
SaveUsedEntityId(Constants.ReportDictionaryName, reportId)
SaveUsedEntityId(Constants.DocumentDictionaryName, documentId)
End Sub
Public Overrides Sub BuildStarted(ByVal reportId As String, ByVal documentId As String,
ByVal buildProperties As ReportBuildProperties)
SaveUsedEntityId(Constants.ReportDictionaryName, reportId)
SaveUsedEntityId(Constants.DocumentDictionaryName, documentId)
End Sub
Public Overrides Function ExportDocumentStarting(ByVal documentId As String,
ByVal asyncExportOperationId As String,
ByVal format As String,
ByVal options As ExportOptions,
ByVal printingSystem As PrintingSystemBase,
ByVal doExportSynchronously As Func(Of ExportedDocument)) As ExportedDocument
SaveUsedEntityId(Constants.ExportedDocumentDictionaryName, asyncExportOperationId)
Return MyBase.ExportDocumentStarting(documentId, asyncExportOperationId, format,
options, printingSystem, doExportSynchronously)
End Function
Public Overrides Sub ReleaseDocument(ByVal documentId As String)
End Sub
#End Region
#Region "IWebDocumentViewerAuthorizationService"
Private Function IWebDocumentViewerAuthorizationService_CanCreateDocument() As Boolean _
Implements IWebDocumentViewerAuthorizationService.CanCreateDocument
Return CheckUserAuthorized()
End Function
Private Function IWebDocumentViewerAuthorizationService_CanCreateReport() As Boolean _
Implements IWebDocumentViewerAuthorizationService.CanCreateReport
Return CheckUserAuthorized()
End Function
Private Function IWebDocumentViewerAuthorizationService_CanReadDocument(ByVal documentId As String) _
As Boolean _
Implements IWebDocumentViewerAuthorizationService.CanReadDocument
Return CheckEntityAvailability(Constants.DocumentDictionaryName, documentId)
End Function
Private Function IWebDocumentViewerAuthorizationService_CanReadReport(ByVal reportId As String) _
As Boolean _
Implements IWebDocumentViewerAuthorizationService.CanReadReport
Return CheckEntityAvailability(Constants.ReportDictionaryName, reportId)
End Function
Private Function IWebDocumentViewerAuthorizationService_CanReleaseDocument(ByVal documentId As String) _
As Boolean _
Implements IWebDocumentViewerAuthorizationService.CanReleaseDocument
Return CheckEntityAvailability(Constants.DocumentDictionaryName, documentId)
End Function
Private Function IWebDocumentViewerAuthorizationService_CanReleaseReport(ByVal reportId As String) _
As Boolean _
Implements IWebDocumentViewerAuthorizationService.CanReleaseReport
Return CheckEntityAvailability(Constants.ReportDictionaryName, reportId)
End Function
Public Function CanReadExportedDocument(ByVal exportDocumentId As String) As Boolean _
Implements IExportingAuthorizationService.CanReadExportedDocument
Return CheckEntityAvailability(Constants.ExportedDocumentDictionaryName, exportDocumentId)
End Function
#End Region ' IWebDocumentViewerAuthorizationService, IExportingAuthorizationService
Private Function CheckUserAuthorized() As Boolean
Dim user = HttpContext.Current.User
If user Is Nothing OrElse user.Identity Is Nothing OrElse Not user.Identity.IsAuthenticated Then
Return False
End If
Return True
End Function
Private Sub SaveUsedEntityId(ByVal dictionaryName As String, ByVal id As String)
If String.IsNullOrEmpty(id) Then
Return
End If
Dim dictionary As ConcurrentDictionary(Of String, Boolean) = Nothing
SyncLock HttpContext.Current.Session.SyncRoot
If HttpContext.Current.Session(dictionaryName) Is Nothing Then
dictionary = New ConcurrentDictionary(Of String, Boolean)()
HttpContext.Current.Session(dictionaryName) = dictionary
End If
End SyncLock
If dictionary Is Nothing Then
dictionary = (DirectCast(HttpContext.Current.Session(dictionaryName),
ConcurrentDictionary(Of String, Boolean)))
End If
dictionary.AddOrUpdate(id, False, Function(_1, _2) False)
End Sub
Private Function CheckEntityAvailability(ByVal dictionaryName As String,
ByVal id As String) As Boolean
If String.IsNullOrEmpty(id) OrElse Not CheckUserAuthorized() Then
Return False
End If
SyncLock HttpContext.Current.Session.SyncRoot
If HttpContext.Current.Session(dictionaryName) Is Nothing Then
Return False
End If
End SyncLock
Return DirectCast(HttpContext.Current.Session(dictionaryName),
ConcurrentDictionary(Of String, Boolean)).ContainsKey(id)
End Function
Private Sub DisposeEntityRequested(ByVal dictionaryName As String, ByVal id As String)
If String.IsNullOrEmpty(id) Then
Return
End If
SyncLock HttpContext.Current.Session.SyncRoot
If HttpContext.Current.Session(dictionaryName) Is Nothing Then
Return
End If
End SyncLock
DirectCast(HttpContext.Current.Session(dictionaryName),
ConcurrentDictionary(Of String, Boolean)).AddOrUpdate(id, True, Function(_1, _2) True)
End Sub
End Class
End Namespace
Register the service on application startup:
protected void Application_Start() {
...
DefaultWebDocumentViewerContainer.Register<IExportingAuthorizationService, Services.OperationLogger>();
DefaultWebDocumentViewerContainer.Register<WebDocumentViewerOperationLogger, Services.OperationLogger>();
DefaultWebDocumentViewerContainer.Register<IWebDocumentViewerAuthorizationService, Services.OperationLogger>();
...
}
Protected Sub Application_Start()
...
DefaultWebDocumentViewerContainer.Register(Of IExportingAuthorizationService, Services.OperationLogger)()
DefaultWebDocumentViewerContainer.Register(Of WebDocumentViewerOperationLogger, Services.OperationLogger)()
DefaultWebDocumentViewerContainer.Register(Of IWebDocumentViewerAuthorizationService, Services.OperationLogger)()
...
End Sub
View Example: Implement User Authorization
The following code is a custom interface implementation that allows authorized users to view the report in the Document Viewer. A custom WebDocumentViewerOperationLogger service populates dictionaries with the user id, report id, document id and asynchronous operation id. The IWebDocumentViewerAuthorizationService controls access to reports and documents, the IExportingAuthorizationService controls access to the asynchronously exported document.
using System;
using System.Collections.Concurrent;
using DevExpress.XtraPrinting;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.ClientControls;
using DevExpress.XtraReports.Web.WebDocumentViewer;
namespace AspNetCore.Reporting.Common.Services.Reporting {
class DocumentViewerAuthorizationService :
WebDocumentViewerOperationLogger,
IWebDocumentViewerAuthorizationService,
IExportingAuthorizationService
{
static ConcurrentDictionary<string, string> DocumentIdOwnerMap { get; } =
new ConcurrentDictionary<string, string>();
static ConcurrentDictionary<string, string> ExportedDocumentIdOwnerMap { get; } =
new ConcurrentDictionary<string, string>();
static ConcurrentDictionary<string, string> ReportIdOwnerMap { get; } =
new ConcurrentDictionary<string, string>();
IAuthenticatiedUserService UserService { get; }
public DocumentViewerAuthorizationService(IAuthenticatiedUserService userService)
{
UserService = userService ?? throw new ArgumentNullException(nameof(userService));
}
public override void ReportOpening(string reportId, string documentId, XtraReport report)
{
MapIdentifiersToUser(UserService.GetCurrentUserId(), documentId, reportId, null);
base.ReportOpening(reportId, documentId, report);
}
public override void BuildStarted(string reportId, string documentId,
ReportBuildProperties buildProperties)
{
MapIdentifiersToUser(UserService.GetCurrentUserId(), documentId, reportId, null);
base.BuildStarted(reportId, documentId, buildProperties);
}
public override ExportedDocument ExportDocumentStarting(string documentId,
string asyncExportOperationId, string format, ExportOptions options,
PrintingSystemBase printingSystem, Func<ExportedDocument> doExportSynchronously)
{
MapIdentifiersToUser(UserService.GetCurrentUserId(), null, null, asyncExportOperationId);
return base.ExportDocumentStarting(documentId,
asyncExportOperationId, format, options, printingSystem, doExportSynchronously);
}
void MapIdentifiersToUser(string userId, string documentId,
string reportId, string exportedDocumentId)
{
if(!string.IsNullOrEmpty(exportedDocumentId))
ExportedDocumentIdOwnerMap.TryAdd(exportedDocumentId, userId);
if(!string.IsNullOrEmpty(documentId))
DocumentIdOwnerMap.TryAdd(documentId, userId);
if(!string.IsNullOrEmpty(reportId))
ReportIdOwnerMap.TryAdd(reportId, userId);
}
#region IWebDocumentViewerAuthorizationService
public bool CanCreateDocument()
{
return true;
}
public bool CanCreateReport()
{
return true;
}
public bool CanReadDocument(string documentId)
{
return DocumentIdOwnerMap.TryGetValue(documentId, out var ownerId)
&& ownerId == UserService.GetCurrentUserId();
}
public bool CanReadReport(string reportId)
{
return ReportIdOwnerMap.TryGetValue(reportId, out var ownerId)
&& ownerId == UserService.GetCurrentUserId();
}
public bool CanReleaseDocument(string documentId)
{
return true;
}
public bool CanReleaseReport(string reportId)
{
return true;
}
public bool CanReadExportedDocument(string exportedDocumentId)
{
return ExportedDocumentIdOwnerMap.TryGetValue(exportedDocumentId, out var ownerId)
&& ownerId == UserService.GetCurrentUserId();
}
#endregion
}
}
Register the service on application start. The following code registers three services which implement access check in our example:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<IWebDocumentViewerAuthorizationService, DocumentViewerAuthorizationService>();
builder.Services.AddScoped<WebDocumentViewerOperationLogger, DocumentViewerAuthorizationService>();
builder.Services.AddScoped<IExportingAuthorizationService, DocumentViewerAuthorizationService>();
var app = builder.Build();
See Also
IExportingAuthorizationService Members
IWebDocumentViewerAuthorizationService