This example includes simple projects with report components (Document Viewer and Report Designer) for ASP.NET WebForms, ASP.NET MVC, ASP.NET Core, and Blazor Server (JavaScript-based) platforms. The project demonstrates how to create an object data source, bind it to a report, and restore the object data source when Document Viewer or Report Designer loads a report from a REPX file.
The ObjectDataSource serves as an intermediate layer between the report and the collection of data elements to which the report is bound. The advantage of ObjectDataSource
is that it is serialized in the report definition file (REPX). Otherwise, if you bind the report to a collection of custom objects, the data source information cannot be serialized, and you cannot restore the data source when you load the report from the REPX file.
Assign an ObjectDataSource
instance to the DataSource property of the report. The ObjectDataSource
instance specifies the type, constructors, methods, and properties of a custom object that creates a collection of data items. The custom object can contain a method that populates the collection of data items at runtime or retrieves data from any external data source.
The CustomWebDocumentViewerReportResolver
service in this example implements the IWebDocumentViewerReportResolver interface. The Document Viewer calls that before loading a report specified by name. The service creates a report, assigns the data source, and passes the report to the Document Viewer.
The CustomReportStorageWebExtension
service loads and saves a report specified by name in the Report Designer. The service is a ReportStorageWebExtension descendant.
The CustomObjectDataSourceConstructorFilterService
implements the IObjectDataSourceConstructorFilterService interface and filters the list of constructors available for the ObjectDataSource
in the Report Wizard and Data Source Wizard.
The ObjectDataSourceWizardCustomTypeProvider
service implements the IObjectDataSourceWizardTypeProvider interface and defines the list of data types displayed for the ObjectDataSource
in the Report Wizard and Data Source Wizard.
This example also demonstrates how to map a report parameter to the parameter used to filter data retrieved from the data source.
Files to Review
ASP.NET WebForms:
- EmployeesDataSource.cs (VB: EmployeesDataSource.vb)
- CustomWebDocumentViewerReportResolver.cs (VB: CustomWebDocumentViewerReportResolver.vb)
- CustomReportStorageWebExtension.cs (VB: CustomReportStorageWebExtension.vb)
- CustomObjectDataSourceConstructorFilterService.cs (VB: CustomObjectDataSourceConstructorFilterService.vb)
- ObjectDataSourceWizardCustomTypeProvider.cs (VB: ObjectDataSourceWizardCustomTypeProvider.vb)
- Global.asax.cs (VB: Global.asax.vb)
ASP.NET MVC:
- EmployeesDataSource.cs
- CustomWebDocumentViewerReportResolver.cs
- CustomReportStorageWebExtension.cs
- CustomObjectDataSourceConstructorFilterService.cs
- ObjectDataSourceWizardCustomTypeProvider.cs
- Global.asax.cs
ASP.NET Core:
- EmployeesDataSource.cs
- CustomWebDocumentViewerReportResolver.cs
- CustomReportStorageWebExtension.cs
- CustomObjectDataSourceConstructorFilterService.cs
- ObjectDataSourceWizardCustomTypeProvider.cs
- Startup.cs
Blazor:
- EmployeesDataSource.cs
- CustomWebDocumentViewerReportResolver.cs
- CustomReportStorageWebExtension.cs
- ObjectDataSourceWizardCustomTypeProvider.cs
- Startup.cs
Documentation
- Register Types for Object Data Source Wizard (ASP.NET WebForms)
- Create the Object Data Source at Runtime (ASP.NET WebForms)
- Register Types for Object Data Source Wizard (ASP.NET MVC)
- Create the Object Data Source at Runtime (ASP.NET MVC)
- Register Types for Object Data Source Wizard (ASP.NET Core)
- Create the Object Data Source at Runtime (ASP.NET Core)
- Bind a Report to an Object Data Source in Blazor Applications
Does this example address your development requirements/objectives?
(you will be redirected to DevExpress.com to submit your response)
Example Code
C#using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Reporting_ObjectDS_WebForms.Employees {
[DisplayName("Employees")]
public class EmployeeList
{
public EmployeeList()
{
Items = InitializeList();
}
public EmployeeList(int noOfItems)
{
Items = InitializeList().GetRange(1, noOfItems);
}
public List<DataItem> Items { get; set; }
public List<DataItem> InitializeList()
{
return new List<DataItem>() {
new DataItem(1, 101, "Andrew Fuller", "Dr.", "Vice President, Sales"),
new DataItem(1, 102, "Anne Dodsworth", "Ms.", "Sales Representative"),
new DataItem(1, 103, "Michael Suyama", "Mr.", "Sales Representative"),
new DataItem(1, 104, "Janet Leverling", "Ms.", "Sales Representative"),
new DataItem(1, 105, "Elliot Komaroff", "Dr.", "Sales Coordinator"),
new DataItem(2, 201, "Nancy Davolio", "Ms.", "Sales Representative"),
new DataItem(2, 202, "Steven Buchanan", "Mr.", "Sales Manager"),
new DataItem(2, 203, "Laura Callahan", "Ms.", "Sales Coordinator"),
new DataItem(3, 301, "Frédérique Citeaux", "Mr.", "Sales Coordinator"),
new DataItem(3, 302, "Laurence Lebihan", "Mr.", "Sales Representative"),
new DataItem(3, 303, "Elizabeth Lincoln", "Ms.", "Sales Manager"),
new DataItem(3, 304, "Yang Wang", "Mr.", "Sales Representative"),
new DataItem(4, 401, "Antonio Moreno", "Mr.", "Sales Representative"),
new DataItem(4, 402, "Thomas Hardy", "Mr.", "Sales Representative"),
new DataItem(4, 403, "Christina Berglund", "Ms.", "Sales Manager"),
new DataItem(5, 501, "Alejandra Camino", "Ms.", "Sales Representative"),
new DataItem(5, 502, "Matti Karttunen", "Mr.", "Sales Representative"),
new DataItem(5, 503, "Rita Müller", "Mrs.", "Sales Representative"),
};
}
public List<DataItem> GetData(int noOfItems)
{
List<DataItem> revertList = new List<DataItem>(Items);
revertList.Reverse();
return revertList.Take(noOfItems).ToList();
}
}
public class DataItem {
public DataItem(int floor, int office, string personName, string titleOfCourtesy, string title) {
Floor = floor;
Office = office;
PersonName = personName;
TitleOfCourtesy = titleOfCourtesy;
Title = title;
}
public int Floor { get; set; }
public int Office { get; set; }
public string PersonName { get; set; }
public string TitleOfCourtesy { get; set; }
public string Title { get; set; }
}
}
Visual BasicImports System.Collections.Generic
Imports System.ComponentModel
Imports System.Linq
Namespace Reporting_ObjectDS_WebForms.Employees
<DisplayName("Employees")>
Public Class EmployeeList
Public Sub New()
Items = InitializeList()
End Sub
Public Sub New(ByVal noOfItems As Integer)
Items = InitializeList().GetRange(1, noOfItems)
End Sub
Public Property Items() As List(Of DataItem)
Public Function InitializeList() As List(Of DataItem)
Return New List(Of DataItem)() From {
New DataItem(1, 101, "Andrew Fuller", "Dr.", "Vice President, Sales"),
New DataItem(1, 102, "Anne Dodsworth", "Ms.", "Sales Representative"),
New DataItem(1, 103, "Michael Suyama", "Mr.", "Sales Representative"),
New DataItem(1, 104, "Janet Leverling", "Ms.", "Sales Representative"),
New DataItem(1, 105, "Elliot Komaroff", "Dr.", "Sales Coordinator"),
New DataItem(2, 201, "Nancy Davolio", "Ms.", "Sales Representative"),
New DataItem(2, 202, "Steven Buchanan", "Mr.", "Sales Manager"),
New DataItem(2, 203, "Laura Callahan", "Ms.", "Sales Coordinator"),
New DataItem(3, 301, "Frédérique Citeaux", "Mr.", "Sales Coordinator"),
New DataItem(3, 302, "Laurence Lebihan", "Mr.", "Sales Representative"),
New DataItem(3, 303, "Elizabeth Lincoln", "Ms.", "Sales Manager"),
New DataItem(3, 304, "Yang Wang", "Mr.", "Sales Representative"),
New DataItem(4, 401, "Antonio Moreno", "Mr.", "Sales Representative"),
New DataItem(4, 402, "Thomas Hardy", "Mr.", "Sales Representative"),
New DataItem(4, 403, "Christina Berglund", "Ms.", "Sales Manager"),
New DataItem(5, 501, "Alejandra Camino", "Ms.", "Sales Representative"),
New DataItem(5, 502, "Matti Karttunen", "Mr.", "Sales Representative"),
New DataItem(5, 503, "Rita Müller", "Mrs.", "Sales Representative")
}
End Function
Public Function GetData(ByVal noOfItems As Integer) As List(Of DataItem)
Dim revertList As New List(Of DataItem)(Items)
revertList.Reverse()
Return revertList.Take(noOfItems).ToList()
End Function
End Class
Public Class DataItem
Public Sub New(ByVal floor As Integer, ByVal office As Integer, ByVal personName As String, ByVal titleOfCourtesy As String, ByVal title As String)
Me.Floor = floor
Me.Office = office
Me.PersonName = personName
Me.TitleOfCourtesy = titleOfCourtesy
Me.Title = title
End Sub
Public Property Floor() As Integer
Public Property Office() As Integer
Public Property PersonName() As String
Public Property TitleOfCourtesy() As String
Public Property Title() As String
End Class
End Namespace
C#using DevExpress.DataAccess.ObjectBinding;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.WebDocumentViewer;
namespace Reporting_ObjectDS_WebForms
{
public class CustomWebDocumentViewerReportResolver : IWebDocumentViewerReportResolver
{
public XtraReport Resolve(string reportEntry)
{
if (reportEntry.StartsWith("EmployeeReport"))
{
XtraReport rep = CreateReport(reportEntry);
rep.DataSource = CreateObjectDataSource(reportEntry);
return rep;
}
return new XtraReport();
}
private object CreateObjectDataSource(string reportName)
{
if (reportName == "EmployeeReport")
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(Employees.EmployeeList);
dataSource.Constructor = ObjectConstructorInfo.Default;
dataSource.DataMember = "Items";
return dataSource;
}
else
if (reportName.EndsWith("7"))
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(Employees.EmployeeList);
// Specify the parameter's default value.
var parameter = new Parameter("noOfItems", typeof(int), 7);
dataSource.Constructor = new ObjectConstructorInfo(parameter);
dataSource.DataMember = "Items";
return dataSource;
}
else
if (reportName.EndsWith("Parameter"))
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(Employees.EmployeeList);
// Map data source parameter to report's parameter.
var parameter = new Parameter()
{
Name = "noOfItems",
Type = typeof(DevExpress.DataAccess.Expression),
Value = new DevExpress.DataAccess.Expression("?parameterNoOfItems", typeof(int))
};
dataSource.Constructor = new ObjectConstructorInfo(parameter);
dataSource.DataMember = "Items";
return dataSource;
}
else
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(Employees.EmployeeList);
var parameterNoOfItems = new Parameter("noOfItems", typeof(int), 12);
dataSource.Parameters.Add(parameterNoOfItems);
dataSource.Constructor = ObjectConstructorInfo.Default;
dataSource.DataMember = "GetData";
return dataSource;
}
}
private XtraReport CreateReport(string reportEntry)
{
if (reportEntry.Contains("Parameter"))
{
XtraReport report = new PredefinedReports.EmployeeReport();
DevExpress.XtraReports.Parameters.Parameter param =
new DevExpress.XtraReports.Parameters.Parameter()
{
Name = "parameterNoOfItems",
Type = typeof(int),
Value = 5
};
param.Description = "Number of Items";
report.Parameters.Add(param);
report.RequestParameters = false;
return report;
}
else
return new PredefinedReports.EmployeeReport();
}
}
}
Visual BasicOption Infer On
Imports DevExpress.DataAccess.ObjectBinding
Imports DevExpress.XtraReports.UI
Imports DevExpress.XtraReports.Web.WebDocumentViewer
Namespace Reporting_ObjectDS_WebForms
Public Class CustomWebDocumentViewerReportResolver
Implements IWebDocumentViewerReportResolver
Public Function Resolve(ByVal reportEntry As String) As XtraReport Implements IWebDocumentViewerReportResolver.Resolve
If reportEntry.StartsWith("EmployeeReport") Then
Dim rep As XtraReport = CreateReport(reportEntry)
rep.DataSource = CreateObjectDataSource(reportEntry)
Return rep
End If
Return New XtraReport()
End Function
Private Function CreateObjectDataSource(ByVal reportName As String) As Object
If reportName = "EmployeeReport" Then
#Region "ODS_Constructor"
Dim dataSource As New ObjectDataSource()
dataSource.Name = "EmployeeObjectDS"
dataSource.DataSource = GetType(Employees.EmployeeList)
dataSource.Constructor = ObjectConstructorInfo.Default
dataSource.DataMember = "Items"
Return dataSource
#End Region
Else
If reportName.EndsWith("7") Then
#Region "ODS_ConstructorWithParameter"
Dim dataSource As New ObjectDataSource()
dataSource.Name = "EmployeeObjectDS"
dataSource.DataSource = GetType(Employees.EmployeeList)
' Specify the parameter's default value.
Dim parameter = New Parameter("noOfItems", GetType(Integer), 7)
dataSource.Constructor = New ObjectConstructorInfo(parameter)
dataSource.DataMember = "Items"
Return dataSource
#End Region
Else
If reportName.EndsWith("Parameter") Then
#Region "ODS_MapReportParameter"
Dim dataSource As New ObjectDataSource()
dataSource.Name = "EmployeeObjectDS"
dataSource.DataSource = GetType(Employees.EmployeeList)
' Map data source parameter to report's parameter.
Dim parameter = New Parameter() With {.Name = "noOfItems", .Type = GetType(DevExpress.DataAccess.Expression), .Value = New DevExpress.DataAccess.Expression("?parameterNoOfItems", GetType(Integer))}
dataSource.Constructor = New ObjectConstructorInfo(parameter)
dataSource.DataMember = "Items"
Return dataSource
#End Region
Else
#Region "ODS_Method"
Dim dataSource As New ObjectDataSource()
dataSource.Name = "EmployeeObjectDS"
dataSource.DataSource = GetType(Employees.EmployeeList)
Dim parameterNoOfItems = New Parameter("noOfItems", GetType(Integer), 12)
dataSource.Parameters.Add(parameterNoOfItems)
dataSource.DataMember = "GetData"
dataSource.Constructor = ObjectConstructorInfo.Default
Return dataSource
#End Region
End If
End If
End If
End Function
Private Function CreateReport(ByVal reportEntry As String) As XtraReport
If reportEntry.Contains("Parameter") Then
Dim report As XtraReport = New PredefinedReports.EmployeeReport()
Dim param As New DevExpress.XtraReports.Parameters.Parameter() With {.Name = "parameterNoOfItems", .Type = GetType(Integer), .Value = 5}
param.Description = "Number of Items"
report.Parameters.Add(param)
report.RequestParameters = False
Return report
Else
Return New PredefinedReports.EmployeeReport()
End If
End Function
End Class
End Namespace
C#using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using DevExpress.XtraReports.UI;
using Reporting_ObjectDS_WebForms.PredefinedReports;
public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension {
readonly string reportDirectory;
const string FileExtension = ".repx";
public CustomReportStorageWebExtension(string reportDirectory) {
if (!Directory.Exists(reportDirectory)) {
Directory.CreateDirectory(reportDirectory);
}
this.reportDirectory = reportDirectory;
}
public override bool CanSetData(string url) {
// Determines whether or not it is possible to store a report by a given URL.
// For instance, make the CanSetData method return false for reports that should be read-only in your storage.
// This method is called only for valid URLs (i.e., if the IsValidUrl method returned true) before the SetData method is called.
return true;
}
public override bool IsValidUrl(string url) {
// Determines whether or not the URL passed to the current Report Storage is valid.
// For instance, implement your own logic to prohibit URLs that contain white spaces or some other special characters.
// This method is called before the CanSetData and GetData methods.
return Path.GetFileName(url) == url;
}
public override byte[] GetData(string url) {
// Returns report layout data stored in a Report Storage using the specified URL.
// This method is called only for valid URLs after the IsValidUrl method is called.
try {
if (Directory.EnumerateFiles(reportDirectory).Select(Path.GetFileNameWithoutExtension).Contains(url)) {
return File.ReadAllBytes(Path.Combine(reportDirectory, url + FileExtension));
}
if (ReportsFactory.Reports.ContainsKey(url)) {
using (MemoryStream ms = new MemoryStream()) {
ReportsFactory.Reports[url]().SaveLayoutToXml(ms);
return ms.ToArray();
}
}
}
catch (Exception) {
throw new FaultException(new FaultReason("Could not get report data."), new FaultCode("Server"), "GetData");
}
throw new FaultException(new FaultReason(string.Format("Could not find report '{0}'.", url)), new FaultCode("Server"), "GetData");
}
public override Dictionary<string, string> GetUrls() {
// Returns a dictionary of the existing report URLs and display names.
// This method is called when running the Report Designer,
// before the Open Report and Save Report dialogs are shown and after a new report is saved to a storage.
return Directory.GetFiles(reportDirectory, "*" + FileExtension)
.Select(Path.GetFileNameWithoutExtension)
.Union(ReportsFactory.Reports.Select(x => x.Key))
.ToDictionary<string, string>(x => x);
}
public override void SetData(XtraReport report, string url) {
// Stores the specified report to a Report Storage using the specified URL.
// This method is called only after the IsValidUrl and CanSetData methods are called.
var resolvedUrl = Path.GetFullPath(Path.Combine(reportDirectory, url + FileExtension));
if (!resolvedUrl.StartsWith(reportDirectory + Path.DirectorySeparatorChar)) {
throw new FaultException("Invalid report name.");
}
report.SaveLayoutToXml(resolvedUrl);
}
public override string SetNewData(XtraReport report, string defaultUrl) {
// Stores the specified report using a new URL.
// The IsValidUrl and CanSetData methods are never called before this method.
// You can validate and correct the specified URL directly in the SetNewData method implementation
// and return the resulting URL used to save a report in your storage.
SetData(report, defaultUrl);
return defaultUrl;
}
}
Visual BasicImports System
Imports System.Collections.Concurrent
Imports System.Collections.Generic
Imports System.IO
Imports System.Linq
Imports System.Reflection
Imports System.ServiceModel
Imports DevExpress.XtraReports.Web.Extensions
Imports DevExpress.XtraReports.UI
Imports Reporting_ObjectDS_WebForms.PredefinedReports
Namespace Reporting_ObjectDS_WebForms.Services
Public Class CustomReportStorageWebExtension
Inherits DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension
Private ReadOnly reportDirectory As String
Private Const FileExtension As String = ".repx"
Public Sub New(ByVal reportDirectory As String)
If Not Directory.Exists(reportDirectory) Then
Directory.CreateDirectory(reportDirectory)
End If
Me.reportDirectory = reportDirectory
End Sub
Public Overrides Function CanSetData(ByVal url As String) As Boolean
' Determines whether or not it is possible to store a report by a given URL.
' For instance, make the CanSetData method return false for reports that should be read-only in your storage.
' This method is called only for valid URLs (i.e., if the IsValidUrl method returned true) before the SetData method is called.
Return True
End Function
Public Overrides Function IsValidUrl(ByVal url As String) As Boolean
' Determines whether or not the URL passed to the current Report Storage is valid.
' For instance, implement your own logic to prohibit URLs that contain white spaces or some other special characters.
' This method is called before the CanSetData and GetData methods.
Return Path.GetFileName(url) = url
End Function
Public Overrides Function GetData(ByVal url As String) As Byte()
' Returns report layout data stored in a Report Storage using the specified URL.
' This method is called only for valid URLs after the IsValidUrl method is called.
Try
If Directory.EnumerateFiles(reportDirectory).Select(AddressOf Path.GetFileNameWithoutExtension).Contains(url) Then
Return File.ReadAllBytes(Path.Combine(reportDirectory, url & FileExtension))
End If
If ReportsFactory.Reports.ContainsKey(url) Then
Using ms As New MemoryStream()
ReportsFactory.Reports(url)().SaveLayoutToXml(ms)
Return ms.ToArray()
End Using
End If
Catch e1 As Exception
Throw New FaultException(New FaultReason("Could not get report data."), New FaultCode("Server"), "GetData")
End Try
Throw New FaultException(New FaultReason(String.Format("Could not find report '{0}'.", url)), New FaultCode("Server"), "GetData")
End Function
Public Overrides Function GetUrls() As Dictionary(Of String, String)
' Returns a dictionary of the existing report URLs and display names.
' This method is called when running the Report Designer,
' before the Open Report and Save Report dialogs are shown and after a new report is saved to a storage.
Return Directory.GetFiles(reportDirectory, "*" & FileExtension).Select(AddressOf Path.GetFileNameWithoutExtension).Union(ReportsFactory.Reports.Select(Function(x) x.Key)).ToDictionary(Function(x) x)
End Function
Public Overrides Sub SetData(ByVal report As XtraReport, ByVal url As String)
' Stores the specified report to a Report Storage using the specified URL.
' This method is called only after the IsValidUrl and CanSetData methods are called.
Dim resolvedUrl = Path.GetFullPath(Path.Combine(reportDirectory, url + FileExtension))
If Not resolvedUrl.StartsWith(reportDirectory + Path.DirectorySeparatorChar) Then
Throw New FaultException("Invalid report name.")
End If
report.SaveLayoutToXml(resolvedUrl)
End Sub
Public Overrides Function SetNewData(ByVal report As XtraReport, ByVal defaultUrl As String) As String
' Stores the specified report using a new URL.
' The IsValidUrl and CanSetData methods are never called before this method.
' You can validate and correct the specified URL directly in the SetNewData method implementation
' and return the resulting URL used to save a report in your storage.
SetData(report, defaultUrl)
Return defaultUrl
End Function
End Class
End Namespace
C#using DevExpress.DataAccess.Web;
using Reporting_ObjectDS_WebForms.Employees;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public class CustomObjectDataSourceConstructorFilterService : IObjectDataSourceConstructorFilterService
{
public IEnumerable<ConstructorInfo> Filter(Type dataSourceType, IEnumerable<ConstructorInfo> constructors)
{
if (dataSourceType == typeof(EmployeeList))
return constructors;
else
return constructors.Where(x => x.GetParameters().Length > 0);
}
}
Visual BasicImports DevExpress.DataAccess.Web
Imports Reporting_ObjectDS_WebForms.Employees
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Reflection
Public Class CustomObjectDataSourceConstructorFilterService
Implements IObjectDataSourceConstructorFilterService
Public Function Filter(ByVal dataSourceType As Type, ByVal constructors As IEnumerable(Of ConstructorInfo)) As IEnumerable(Of ConstructorInfo) Implements IObjectDataSourceConstructorFilterService.Filter
If dataSourceType Is GetType(EmployeeList) Then
Return constructors
Else
Return constructors.Where(Function(x) x.GetParameters().Length > 0)
End If
End Function
End Class
C#using DevExpress.DataAccess.Web;
using System;
using System.Collections.Generic;
namespace Reporting_ObjectDS_WebForms.Services {
public class ObjectDataSourceWizardCustomTypeProvider : IObjectDataSourceWizardTypeProvider {
public IEnumerable<Type> GetAvailableTypes(string context)
{
return new[] { typeof(Employees.EmployeeList) };
}
}
}
Visual BasicImports DevExpress.DataAccess.Web
Imports System
Imports System.Collections.Generic
Namespace Reporting_ObjectDS_WebForms.Services
Public Class ObjectDataSourceWizardCustomTypeProvider
Implements IObjectDataSourceWizardTypeProvider
Public Function GetAvailableTypes(ByVal context As String) As IEnumerable(Of Type) Implements IObjectDataSourceWizardTypeProvider.GetAvailableTypes
Return {GetType(Employees.EmployeeList)}
End Function
End Class
End Namespace
C#using System;
using System.IO;
using System.Web;
using DevExpress.XtraReports.Web;
using Reporting_ObjectDS_WebForms.Employees;
using Reporting_ObjectDS_WebForms.Services;
namespace Reporting_ObjectDS_WebForms {
public class Global_asax : System.Web.HttpApplication {
void Application_Start(object sender, EventArgs e) {
System.Web.Routing.RouteTable.Routes.MapPageRoute("defaultRoute", "", "~/Default.aspx");
DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(EmployeeList));
DevExpress.XtraReports.Configuration.Settings.Default.UserDesignerOptions.DataBindingMode = DevExpress.XtraReports.UI.DataBindingMode.Expressions;
DevExpress.XtraReports.Web.WebDocumentViewer.Native.WebDocumentViewerBootstrapper.SessionState = System.Web.SessionState.SessionStateBehavior.Default;
DevExpress.XtraReports.Web.QueryBuilder.Native.QueryBuilderBootstrapper.SessionState = System.Web.SessionState.SessionStateBehavior.Default;
DevExpress.XtraReports.Web.ReportDesigner.Native.ReportDesignerBootstrapper.SessionState = System.Web.SessionState.SessionStateBehavior.Default;
DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension.RegisterExtensionGlobal(new CustomReportStorageWebExtension(Server.MapPath("/Reports")));
DevExpress.XtraReports.Web.ReportDesigner.DefaultReportDesignerContainer.RegisterObjectDataSourceConstructorFilterService<CustomObjectDataSourceConstructorFilterService>();
DevExpress.XtraReports.Web.WebDocumentViewer.DefaultWebDocumentViewerContainer.Register<DevExpress.XtraReports.Web.WebDocumentViewer.IWebDocumentViewerReportResolver, CustomWebDocumentViewerReportResolver>();
DevExpress.XtraReports.Web.ReportDesigner.DefaultReportDesignerContainer.RegisterObjectDataSourceWizardTypeProvider<ObjectDataSourceWizardCustomTypeProvider>();
System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;
ASPxReportDesigner.StaticInitialize();
DevExpress.XtraReports.Web.ClientControls.LoggerService.Initialize((ex, message) => System.Diagnostics.Debug.WriteLine("[{0}]: Exception occurred. Message: '{1}'. Exception Details:\r\n{2}", DateTime.Now, message, ex));
DevExpress.Web.ASPxWebControl.CallbackError += new EventHandler(Application_Error);
}
void Application_End(object sender, EventArgs e) {
// Code that runs on application shutdown
}
void Application_Error(object sender, EventArgs e) {
// Code that runs when an unhandled error occurs
}
void Session_Start(object sender, EventArgs e) {
// Code that runs when a new session is started
}
void Session_End(object sender, EventArgs e) {
// Code that runs when a session ends.
// Note: The Session_End event is raised only when the sessionstate mode
// is set to InProc in the Web.config file. If session mode is set to StateServer
// or SQLServer, the event is not raised.
}
}
}
Visual BasicImports System
Imports System.IO
Imports System.Web
Imports DevExpress.XtraReports.Web
Imports Reporting_ObjectDS_WebForms.Services
Namespace Reporting_ObjectDS_WebForms
Public Class Global_asax
Inherits System.Web.HttpApplication
Private Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
System.Web.Routing.RouteTable.Routes.MapPageRoute("defaultRoute", "", "~/Default.aspx")
DevExpress.XtraReports.Configuration.Settings.Default.UserDesignerOptions.DataBindingMode = DevExpress.XtraReports.UI.DataBindingMode.Expressions
DevExpress.XtraReports.Web.WebDocumentViewer.Native.WebDocumentViewerBootstrapper.SessionState = System.Web.SessionState.SessionStateBehavior.Default
DevExpress.XtraReports.Web.QueryBuilder.Native.QueryBuilderBootstrapper.SessionState = System.Web.SessionState.SessionStateBehavior.Default
DevExpress.XtraReports.Web.ReportDesigner.Native.ReportDesignerBootstrapper.SessionState = System.Web.SessionState.SessionStateBehavior.Default
DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension.RegisterExtensionGlobal(New CustomReportStorageWebExtension(Server.MapPath("/Reports")))
DevExpress.XtraReports.Web.ReportDesigner.DefaultReportDesignerContainer.RegisterObjectDataSourceConstructorFilterService(Of CustomObjectDataSourceConstructorFilterService)()
DevExpress.XtraReports.Web.WebDocumentViewer.DefaultWebDocumentViewerContainer.Register(Of DevExpress.XtraReports.Web.WebDocumentViewer.IWebDocumentViewerReportResolver, CustomWebDocumentViewerReportResolver)()
DevExpress.XtraReports.Web.ReportDesigner.DefaultReportDesignerContainer.RegisterObjectDataSourceWizardTypeProvider(Of ObjectDataSourceWizardCustomTypeProvider)()
System.Net.ServicePointManager.SecurityProtocol = System.Net.ServicePointManager.SecurityProtocol Or System.Net.SecurityProtocolType.Tls12
ASPxReportDesigner.StaticInitialize()
DevExpress.XtraReports.Web.ClientControls.LoggerService.Initialize(AddressOf ProcessException)
AddHandler DevExpress.Web.ASPxWebControl.CallbackError, AddressOf Application_Error
End Sub
Private Sub ProcessException(ex As Exception, message As String)
Debug.WriteLine("[{0}]: Exception occurred. Message: '{1}'. Exception Details:" & ControlChars.CrLf & "{2}", Date.Now, message, ex)
End Sub
Private Sub Application_End(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs on application shutdown
End Sub
Private Sub Application_Error(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs when an unhandled error occurs
End Sub
Private Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs when a new session is started
End Sub
Private Sub Session_End(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs when a session ends.
' Note: The Session_End event is raised only when the sessionstate mode
' is set to InProc in the Web.config file. If session mode is set to StateServer
' or SQLServer, the event is not raised.
End Sub
End Class
End Namespace
C#using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Reporting_ObjectDS_Mvc.Employees
{
[DisplayName("Employees")]
public class EmployeeList
{
public EmployeeList()
{
Items = InitializeList();
}
public EmployeeList(int noOfItems)
{
Items = InitializeList().GetRange(1, noOfItems);
}
public List<DataItem> Items { get; set; }
public List<DataItem> InitializeList()
{
return new List<DataItem>() {
new DataItem(1, 101, "Andrew Fuller", "Dr.", "Vice President, Sales"),
new DataItem(1, 102, "Anne Dodsworth", "Ms.", "Sales Representative"),
new DataItem(1, 103, "Michael Suyama", "Mr.", "Sales Representative"),
new DataItem(1, 104, "Janet Leverling", "Ms.", "Sales Representative"),
new DataItem(1, 105, "Elliot Komaroff", "Dr.", "Sales Coordinator"),
new DataItem(2, 201, "Nancy Davolio", "Ms.", "Sales Representative"),
new DataItem(2, 202, "Steven Buchanan", "Mr.", "Sales Manager"),
new DataItem(2, 203, "Laura Callahan", "Ms.", "Sales Coordinator"),
new DataItem(3, 301, "Frédérique Citeaux", "Mr.", "Sales Coordinator"),
new DataItem(3, 302, "Laurence Lebihan", "Mr.", "Sales Representative"),
new DataItem(3, 303, "Elizabeth Lincoln", "Ms.", "Sales Manager"),
new DataItem(3, 304, "Yang Wang", "Mr.", "Sales Representative"),
new DataItem(4, 401, "Antonio Moreno", "Mr.", "Sales Representative"),
new DataItem(4, 402, "Thomas Hardy", "Mr.", "Sales Representative"),
new DataItem(4, 403, "Christina Berglund", "Ms.", "Sales Manager"),
new DataItem(5, 501, "Alejandra Camino", "Ms.", "Sales Representative"),
new DataItem(5, 502, "Matti Karttunen", "Mr.", "Sales Representative"),
new DataItem(5, 503, "Rita Müller", "Mrs.", "Sales Representative"),
};
}
public List<DataItem> GetData(int noOfItems)
{
List<DataItem> revertList = new List<DataItem>(Items);
revertList.Reverse();
return revertList.Take(noOfItems).ToList();
}
}
public class DataItem
{
public DataItem(int floor, int office, string personName, string titleOfCourtesy, string title)
{
Floor = floor;
Office = office;
PersonName = personName;
TitleOfCourtesy = titleOfCourtesy;
Title = title;
}
public int Floor { get; set; }
public int Office { get; set; }
public string PersonName { get; set; }
public string TitleOfCourtesy { get; set; }
public string Title { get; set; }
}
}
C#using DevExpress.DataAccess.ObjectBinding;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.WebDocumentViewer;
namespace Reporting_ObjectDS_Mvc
{
public class CustomWebDocumentViewerReportResolver : IWebDocumentViewerReportResolver
{
public XtraReport Resolve(string reportEntry)
{
if (reportEntry.StartsWith("EmployeeReport"))
{
XtraReport rep = CreateReport(reportEntry);
rep.DataSource = CreateObjectDataSource(reportEntry);
return rep;
}
return new XtraReport();
}
private object CreateObjectDataSource(string reportName)
{
if (reportName == "EmployeeReport")
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(Employees.EmployeeList);
dataSource.Constructor = ObjectConstructorInfo.Default;
dataSource.DataMember = "Items";
return dataSource;
}
else
if (reportName.EndsWith("7"))
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(Employees.EmployeeList);
// Specify the parameter's default value.
var parameter = new Parameter("noOfItems", typeof(int), 7);
dataSource.Constructor = new ObjectConstructorInfo(parameter);
dataSource.DataMember = "Items";
return dataSource;
}
else
if (reportName.EndsWith("Parameter"))
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(Employees.EmployeeList);
// Map data source parameter to report's parameter.
var parameter = new Parameter()
{
Name = "noOfItems",
Type = typeof(DevExpress.DataAccess.Expression),
Value = new DevExpress.DataAccess.Expression("?parameterNoOfItems", typeof(int))
};
dataSource.Constructor = new ObjectConstructorInfo(parameter);
dataSource.DataMember = "Items";
return dataSource;
}
else
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(Employees.EmployeeList);
var parameterNoOfItems = new Parameter("noOfItems", typeof(int), 12);
dataSource.Parameters.Add(parameterNoOfItems);
dataSource.DataMember = "GetData";
dataSource.Constructor = ObjectConstructorInfo.Default;
return dataSource;
}
}
private XtraReport CreateReport(string reportEntry)
{
if (reportEntry.Contains("Parameter"))
{
XtraReport report = new PredefinedReports.EmployeeReport();
DevExpress.XtraReports.Parameters.Parameter param =
new DevExpress.XtraReports.Parameters.Parameter()
{
Name = "parameterNoOfItems",
Type = typeof(int),
Value = 5
};
param.Description = "Number of Items";
report.Parameters.Add(param);
report.RequestParameters = false;
return report;
}
else
return new PredefinedReports.EmployeeReport();
}
}
}
C#using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.ServiceModel;
using DevExpress.XtraReports.Web.Extensions;
using DevExpress.XtraReports.UI;
using Reporting_ObjectDS_Mvc.PredefinedReports;
namespace Reporting_ObjectDS_Mvc.Services
{
public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension
{
readonly string reportDirectory;
const string FileExtension = ".repx";
public CustomReportStorageWebExtension(string reportDirectory) {
if (!Directory.Exists(reportDirectory)) {
Directory.CreateDirectory(reportDirectory);
}
this.reportDirectory = reportDirectory;
}
private bool IsWithinReportsFolder(string url, string folder) {
var rootDirectory = new DirectoryInfo(folder);
var fileInfo = new FileInfo(Path.Combine(folder, url));
return fileInfo.Directory.FullName.ToLower().StartsWith(rootDirectory.FullName.ToLower());
}
public override bool CanSetData(string url) {
// Determines whether or not it is possible to store a report by a given URL.
// For instance, make the CanSetData method return false for reports that should be read-only in your storage.
// This method is called only for valid URLs (i.e., if the IsValidUrl method returned true) before the SetData method is called.
return true;
}
public override bool IsValidUrl(string url) {
// Determines whether or not the URL passed to the current Report Storage is valid.
// For instance, implement your own logic to prohibit URLs that contain white spaces or some other special characters.
// This method is called before the CanSetData and GetData methods.
return Path.GetFileName(url) == url;
}
public override byte[] GetData(string url) {
// Returns report layout data stored in a Report Storage using the specified URL.
// This method is called only for valid URLs after the IsValidUrl method is called.
try {
if (Directory.EnumerateFiles(reportDirectory).Select(Path.GetFileNameWithoutExtension).Contains(url))
{
return File.ReadAllBytes(Path.Combine(reportDirectory, url + FileExtension));
}
if (ReportsFactory.Reports.ContainsKey(url))
{
using (MemoryStream ms = new MemoryStream()) {
ReportsFactory.Reports[url]().SaveLayoutToXml(ms);
return ms.ToArray();
}
}
} catch (Exception) {
throw new FaultException(new FaultReason("Could not get report data."), new FaultCode("Server"), "GetData");
}
throw new FaultException(new FaultReason(string.Format("Could not find report '{0}'.", url)), new FaultCode("Server"), "GetData");
}
public override Dictionary<string, string> GetUrls() {
// Returns a dictionary of the existing report URLs and display names.
// This method is called when running the Report Designer,
// before the Open Report and Save Report dialogs are shown and after a new report is saved to a storage.
return Directory.GetFiles(reportDirectory, "*" + FileExtension)
.Select(Path.GetFileNameWithoutExtension)
.Union(ReportsFactory.Reports.Select(x => x.Key))
.ToDictionary<string, string>(x => x);
}
public override void SetData(XtraReport report, string url) {
// Stores the specified report to a Report Storage using the specified URL.
// This method is called only after the IsValidUrl and CanSetData methods are called.
if(!IsWithinReportsFolder(url, reportDirectory))
throw new FaultException(new FaultReason("Invalid report name."), new FaultCode("Server"), "GetData");
report.SaveLayoutToXml(Path.Combine(reportDirectory, url + FileExtension));
}
public override string SetNewData(XtraReport report, string defaultUrl) {
// Stores the specified report using a new URL.
// The IsValidUrl and CanSetData methods are never called before this method.
// You can validate and correct the specified URL directly in the SetNewData method implementation
// and return the resulting URL used to save a report in your storage.
SetData(report, defaultUrl);
return defaultUrl;
}
}
}
C#using DevExpress.DataAccess.Web;
using Reporting_ObjectDS_Mvc.Employees;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public class CustomObjectDataSourceConstructorFilterService : IObjectDataSourceConstructorFilterService
{
public IEnumerable<ConstructorInfo> Filter(Type dataSourceType, IEnumerable<ConstructorInfo> constructors)
{
if (dataSourceType == typeof(EmployeeList))
return constructors;
else
return constructors.Where(x => x.GetParameters().Length > 0);
}
}
C#using DevExpress.DataAccess.Web;
using System;
using System.Collections.Generic;
namespace Reporting_ObjectDS_Mvc.Services {
public class ObjectDataSourceWizardCustomTypeProvider : IObjectDataSourceWizardTypeProvider {
public IEnumerable<Type> GetAvailableTypes(string context) {
return new[] { typeof(Employees.EmployeeList) };
}
}
}
C#using System;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Routing;
using DevExpress.Web.Mvc;
using Reporting_ObjectDS_Mvc.Employees;
using Reporting_ObjectDS_Mvc.Services;
namespace Reporting_ObjectDS_Mvc {
// Note: For instructions on enabling IIS6 or IIS7 classic mode,
// visit http://go.microsoft.com/?LinkId=9394801
public class MvcApplication : System.Web.HttpApplication {
protected void Application_Start() {
DevExpress.XtraReports.Configuration.Settings.Default.UserDesignerOptions.DataBindingMode = DevExpress.XtraReports.UI.DataBindingMode.Expressions;
DevExpress.XtraReports.Web.WebDocumentViewer.Native.WebDocumentViewerBootstrapper.SessionState = System.Web.SessionState.SessionStateBehavior.Default;
DevExpress.XtraReports.Web.QueryBuilder.Native.QueryBuilderBootstrapper.SessionState = System.Web.SessionState.SessionStateBehavior.Default;
DevExpress.XtraReports.Web.ReportDesigner.Native.ReportDesignerBootstrapper.SessionState = System.Web.SessionState.SessionStateBehavior.Default;
DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension.RegisterExtensionGlobal(new CustomReportStorageWebExtension(Server.MapPath("/Reports")));
DevExpress.XtraReports.Web.WebDocumentViewer.DefaultWebDocumentViewerContainer.Register<DevExpress.XtraReports.Web.WebDocumentViewer.IWebDocumentViewerReportResolver, CustomWebDocumentViewerReportResolver>();
DevExpress.XtraReports.Web.ReportDesigner.DefaultReportDesignerContainer.RegisterObjectDataSourceWizardTypeProvider<ObjectDataSourceWizardCustomTypeProvider>();
DevExpress.XtraReports.Web.ReportDesigner.DefaultReportDesignerContainer.RegisterObjectDataSourceConstructorFilterService<CustomObjectDataSourceConstructorFilterService>();
DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(EmployeeList));
System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;
MVCxReportDesigner.StaticInitialize();
DevExpress.XtraReports.Web.ClientControls.LoggerService.Initialize((ex, message) => System.Diagnostics.Debug.WriteLine("[{0}]: Exception occurred. Message: '{1}'. Exception Details:\r\n{2}", DateTime.Now, message, ex));
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
ModelBinders.Binders.DefaultBinder = new DevExpress.Web.Mvc.DevExpressEditorsBinder();
DevExpress.Web.ASPxWebControl.CallbackError += Application_Error;
}
protected void Application_Error(object sender, EventArgs e) {
Exception exception = System.Web.HttpContext.Current.Server.GetLastError();
//TODO: Handle Exception
}
}
}
C#using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Reporting_ObjectDS_AspNetCore
{
[DisplayName("Employees")]
public class EmployeeList
{
public EmployeeList()
{
Items = InitializeList();
}
public EmployeeList(int noOfItems)
{
Items = InitializeList().GetRange(1, noOfItems);
}
public List<DataItem> Items { get; set; }
public List<DataItem> InitializeList()
{
return new List<DataItem>() {
new DataItem(1, 101, "Andrew Fuller", "Dr.", "Vice President, Sales"),
new DataItem(1, 102, "Anne Dodsworth", "Ms.", "Sales Representative"),
new DataItem(1, 103, "Michael Suyama", "Mr.", "Sales Representative"),
new DataItem(1, 104, "Janet Leverling", "Ms.", "Sales Representative"),
new DataItem(1, 105, "Elliot Komaroff", "Dr.", "Sales Coordinator"),
new DataItem(2, 201, "Nancy Davolio", "Ms.", "Sales Representative"),
new DataItem(2, 202, "Steven Buchanan", "Mr.", "Sales Manager"),
new DataItem(2, 203, "Laura Callahan", "Ms.", "Sales Coordinator"),
new DataItem(3, 301, "Frédérique Citeaux", "Mr.", "Sales Coordinator"),
new DataItem(3, 302, "Laurence Lebihan", "Mr.", "Sales Representative"),
new DataItem(3, 303, "Elizabeth Lincoln", "Ms.", "Sales Manager"),
new DataItem(3, 304, "Yang Wang", "Mr.", "Sales Representative"),
new DataItem(4, 401, "Antonio Moreno", "Mr.", "Sales Representative"),
new DataItem(4, 402, "Thomas Hardy", "Mr.", "Sales Representative"),
new DataItem(4, 403, "Christina Berglund", "Ms.", "Sales Manager"),
new DataItem(5, 501, "Alejandra Camino", "Ms.", "Sales Representative"),
new DataItem(5, 502, "Matti Karttunen", "Mr.", "Sales Representative"),
new DataItem(5, 503, "Rita Müller", "Mrs.", "Sales Representative"),
};
}
public List<DataItem> GetData(int noOfItems)
{
List<DataItem> revertList = new List<DataItem>(Items);
revertList.Reverse();
return revertList.Take(noOfItems).ToList();
}
}
public class DataItem
{
public DataItem(int floor, int office, string personName, string titleOfCourtesy, string title)
{
Floor = floor;
Office = office;
PersonName = personName;
TitleOfCourtesy = titleOfCourtesy;
Title = title;
}
public int Floor { get; set; }
public int Office { get; set; }
public string PersonName { get; set; }
public string TitleOfCourtesy { get; set; }
public string Title { get; set; }
}
}
C#using DevExpress.DataAccess.ObjectBinding;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.WebDocumentViewer;
namespace Reporting_ObjectDS_AspNetCore
{
public class CustomWebDocumentViewerReportResolver : IWebDocumentViewerReportResolver
{
public XtraReport Resolve(string reportEntry)
{
if (reportEntry.StartsWith("EmployeeReport"))
{
XtraReport rep = CreateReport(reportEntry);
rep.DataSource = CreateObjectDataSource(reportEntry);
return rep;
}
return new XtraReport();
}
private object CreateObjectDataSource(string reportName)
{
if (reportName == "EmployeeReport")
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(EmployeeList);
dataSource.Constructor = ObjectConstructorInfo.Default;
dataSource.DataMember = "Items";
return dataSource;
}
else
if (reportName.EndsWith("7"))
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(EmployeeList);
// Specify the parameter's default value.
var parameter = new Parameter("noOfItems", typeof(int), 7);
dataSource.Constructor = new ObjectConstructorInfo(parameter);
dataSource.DataMember = "Items";
return dataSource;
}
else
if (reportName.EndsWith("Parameter"))
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(EmployeeList);
// Map data source parameter to report's parameter.
var parameter = new Parameter()
{
Name = "noOfItems",
Type = typeof(DevExpress.DataAccess.Expression),
Value = new DevExpress.DataAccess.Expression("?parameterNoOfItems", typeof(int))
};
dataSource.Constructor = new ObjectConstructorInfo(parameter);
dataSource.DataMember = "Items";
return dataSource;
}
else
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(EmployeeList);
var parameterNoOfItems = new Parameter("noOfItems", typeof(int), 12);
dataSource.Parameters.Add(parameterNoOfItems);
dataSource.Constructor = ObjectConstructorInfo.Default;
dataSource.DataMember = "GetData";
return dataSource;
}
}
private XtraReport CreateReport(string reportEntry)
{
if (reportEntry.Contains("Parameter"))
{
XtraReport report = new PredefinedReports.EmployeeReport();
DevExpress.XtraReports.Parameters.Parameter param =
new DevExpress.XtraReports.Parameters.Parameter()
{
Name = "parameterNoOfItems",
Type = typeof(int),
Value = 5
};
param.Description = "Number of Items";
report.Parameters.Add(param);
report.RequestParameters = false;
return report;
}
else
return new PredefinedReports.EmployeeReport();
}
}
}
C#using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.Extensions;
using Microsoft.AspNetCore.Hosting;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Reporting_ObjectDS_AspNetCore.Services
{
public class CustomReportStorageWebExtension : ReportStorageWebExtension
{
readonly string ReportDirectory;
const string FileExtension = ".repx";
public CustomReportStorageWebExtension(IWebHostEnvironment env) {
ReportDirectory = Path.Combine(env.ContentRootPath, "Reports");
if (!Directory.Exists(ReportDirectory)) {
Directory.CreateDirectory(ReportDirectory);
}
}
private bool IsWithinReportsFolder(string url, string folder) {
var rootDirectory = new DirectoryInfo(folder);
var fileInfo = new FileInfo(Path.Combine(folder, url));
return fileInfo.Directory.FullName.ToLower().StartsWith(rootDirectory.FullName.ToLower());
}
public override bool CanSetData(string url) {
// Determines whether or not it is possible to store a report by a given URL.
// For instance, make the CanSetData method return false for reports that should be read-only in your storage.
// This method is called only for valid URLs (i.e., if the IsValidUrl method returned true) before the SetData method is called.
return true;
}
public override bool IsValidUrl(string url) {
// Determines whether or not the URL passed to the current Report Storage is valid.
// For instance, implement your own logic to prohibit URLs that contain white spaces or some other special characters.
// This method is called before the CanSetData and GetData methods.
return Path.GetFileName(url) == url;
}
public override byte[] GetData(string url) {
// Returns report layout data stored in a Report Storage using the specified URL.
// This method is called only for valid URLs after the IsValidUrl method is called.
try {
if (Directory.EnumerateFiles(ReportDirectory).Select(Path.GetFileNameWithoutExtension).Contains(url))
{
return File.ReadAllBytes(Path.Combine(ReportDirectory, url + FileExtension));
}
if (ReportsFactory.Reports.ContainsKey(url))
{
using (MemoryStream ms = new MemoryStream()) {
ReportsFactory.Reports[url]().SaveLayoutToXml(ms);
return ms.ToArray();
}
}
} catch (Exception ex) {
throw new DevExpress.XtraReports.Web.ClientControls.FaultException("Could not get report data.", ex);
}
throw new DevExpress.XtraReports.Web.ClientControls.FaultException(string.Format("Could not find report '{0}'.", url));
}
public override Dictionary<string, string> GetUrls() {
// Returns a dictionary of the existing report URLs and display names.
// This method is called when running the Report Designer,
// before the Open Report and Save Report dialogs are shown and after a new report is saved to a storage.
return Directory.GetFiles(ReportDirectory, "*" + FileExtension)
.Select(Path.GetFileNameWithoutExtension)
.Union(ReportsFactory.Reports.Select(x => x.Key))
.ToDictionary<string, string>(x => x);
}
public override void SetData(XtraReport report, string url) {
// Stores the specified report to a Report Storage using the specified URL.
// This method is called only after the IsValidUrl and CanSetData methods are called.
if(!IsWithinReportsFolder(url, ReportDirectory))
throw new DevExpress.XtraReports.Web.ClientControls.FaultException("Invalid report name.");
report.SaveLayoutToXml(Path.Combine(ReportDirectory, url + FileExtension));
}
public override string SetNewData(XtraReport report, string defaultUrl) {
// Stores the specified report using a new URL.
// The IsValidUrl and CanSetData methods are never called before this method.
// You can validate and correct the specified URL directly in the SetNewData method implementation
// and return the resulting URL used to save a report in your storage.
SetData(report, defaultUrl);
return defaultUrl;
}
}
}
C#using DevExpress.DataAccess.Web;
using Reporting_ObjectDS_AspNetCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
public class CustomObjectDataSourceConstructorFilterService : IObjectDataSourceConstructorFilterService
{
public IEnumerable<ConstructorInfo> Filter(Type dataSourceType, IEnumerable<ConstructorInfo> constructors)
{
if (dataSourceType == typeof(EmployeeList))
return constructors;
else
return constructors.Where(x => x.GetParameters().Length > 0);
}
}
C#using DevExpress.DataAccess.Web;
using System;
using System.Collections.Generic;
namespace Reporting_ObjectDS_AspNetCore.Services {
public class ObjectDataSourceWizardCustomTypeProvider : IObjectDataSourceWizardTypeProvider {
public IEnumerable<Type> GetAvailableTypes(string context) {
return new[] { typeof(EmployeeList) };
}
}
}
C#using DevExpress.AspNetCore;
using DevExpress.AspNetCore.Reporting;
using DevExpress.XtraReports.Web.Extensions;
using DevExpress.XtraReports.Web.WebDocumentViewer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Reporting_ObjectDS_AspNetCore.Services;
namespace Reporting_ObjectDS_AspNetCore {
public class Startup {
public Startup(IConfiguration configuration, IWebHostEnvironment hostingEnvironment) {
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
services.AddDevExpressControls();
services.AddScoped<ReportStorageWebExtension, CustomReportStorageWebExtension>();
services.AddTransient<IWebDocumentViewerReportResolver, CustomWebDocumentViewerReportResolver>();
services
.AddControllersWithViews();
services.ConfigureReportingServices(configurator => {
configurator.ConfigureReportDesigner(designerConfigurator => {
designerConfigurator.RegisterDataSourceWizardConfigFileConnectionStringsProvider();
designerConfigurator.RegisterObjectDataSourceWizardTypeProvider<ObjectDataSourceWizardCustomTypeProvider>();
designerConfigurator.RegisterObjectDataSourceConstructorFilterService<CustomObjectDataSourceConstructorFilterService>();
});
configurator.ConfigureWebDocumentViewer(viewerConfigurator => {
viewerConfigurator.UseCachedReportSourceBuilder();
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) {
DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(EmployeeList));
DevExpress.XtraReports.Configuration.Settings.Default.UserDesignerOptions.DataBindingMode = DevExpress.XtraReports.UI.DataBindingMode.Expressions;
app.UseDevExpressControls();
System.Net.ServicePointManager.SecurityProtocol |= System.Net.SecurityProtocolType.Tls12;
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
} else {
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
C#using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Reporting_ObjectDS_Blazor
{
[DisplayName("Employees")]
public class EmployeeList
{
public EmployeeList()
{
Items = InitializeList();
}
public EmployeeList(int noOfItems)
{
Items = InitializeList().GetRange(1, noOfItems);
}
public List<DataItem> Items { get; set; }
public List<DataItem> InitializeList()
{
return new List<DataItem>() {
new DataItem(1, 101, "Andrew Fuller", "Dr.", "Vice President, Sales"),
new DataItem(1, 102, "Anne Dodsworth", "Ms.", "Sales Representative"),
new DataItem(1, 103, "Michael Suyama", "Mr.", "Sales Representative"),
new DataItem(1, 104, "Janet Leverling", "Ms.", "Sales Representative"),
new DataItem(1, 105, "Elliot Komaroff", "Dr.", "Sales Coordinator"),
new DataItem(2, 201, "Nancy Davolio", "Ms.", "Sales Representative"),
new DataItem(2, 202, "Steven Buchanan", "Mr.", "Sales Manager"),
new DataItem(2, 203, "Laura Callahan", "Ms.", "Sales Coordinator"),
new DataItem(3, 301, "Frédérique Citeaux", "Mr.", "Sales Coordinator"),
new DataItem(3, 302, "Laurence Lebihan", "Mr.", "Sales Representative"),
new DataItem(3, 303, "Elizabeth Lincoln", "Ms.", "Sales Manager"),
new DataItem(3, 304, "Yang Wang", "Mr.", "Sales Representative"),
new DataItem(4, 401, "Antonio Moreno", "Mr.", "Sales Representative"),
new DataItem(4, 402, "Thomas Hardy", "Mr.", "Sales Representative"),
new DataItem(4, 403, "Christina Berglund", "Ms.", "Sales Manager"),
new DataItem(5, 501, "Alejandra Camino", "Ms.", "Sales Representative"),
new DataItem(5, 502, "Matti Karttunen", "Mr.", "Sales Representative"),
new DataItem(5, 503, "Rita Müller", "Mrs.", "Sales Representative"),
};
}
public List<DataItem> GetData(int noOfItems)
{
List<DataItem> revertList = new List<DataItem>(Items);
revertList.Reverse();
return revertList.Take(noOfItems).ToList();
}
}
public class DataItem
{
public DataItem(int floor, int office, string personName, string titleOfCourtesy, string title)
{
Floor = floor;
Office = office;
PersonName = personName;
TitleOfCourtesy = titleOfCourtesy;
Title = title;
}
public int Floor { get; set; }
public int Office { get; set; }
public string PersonName { get; set; }
public string TitleOfCourtesy { get; set; }
public string Title { get; set; }
}
}
C#using DevExpress.DataAccess.ObjectBinding;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.Extensions;
using DevExpress.XtraReports.Web.WebDocumentViewer;
using Reporting_ObjectDS_Blazor.Reports;
using System.IO;
namespace Reporting_ObjectDS_Blazor
{
public class CustomWebDocumentViewerReportResolver : IWebDocumentViewerReportResolver
{
readonly ReportStorageWebExtension reportStorageWebExtension;
public CustomWebDocumentViewerReportResolver(ReportStorageWebExtension reportStorageWebExtension)
{
this.reportStorageWebExtension = reportStorageWebExtension;
}
public XtraReport Resolve(string reportEntry)
{
string reportName = reportEntry.Substring(0, reportEntry.IndexOf("?") == -1 ? reportEntry.Length : reportEntry.IndexOf("?"));
var reportLayout = reportStorageWebExtension.GetData(reportEntry);
if (reportLayout == null)
return new XtraReport();
using (var ms = new MemoryStream(reportLayout))
{
var report = XtraReport.FromXmlStream(ms);
report.DataSource = CreateObjectDataSource(reportName);
return report;
}
}
private object CreateObjectDataSource(string reportName)
{
if (reportName == "EmployeeReport")
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(EmployeeList);
dataSource.Constructor = ObjectConstructorInfo.Default;
dataSource.DataMember = "Items";
return dataSource;
}
else
if (reportName == "EmployeeReport7")
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(EmployeeList);
// Specify the parameter's default value.
var parameter = new Parameter("noOfItems", typeof(int), 7);
dataSource.Constructor = new ObjectConstructorInfo(parameter);
dataSource.DataMember = "Items";
return dataSource;
}
else
if (reportName == "EmployeeReportXtraParameter")
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(EmployeeList);
// Map data source parameter to report's parameter.
var parameter = new Parameter()
{
Name = "noOfItems",
Type = typeof(DevExpress.DataAccess.Expression),
Value = new DevExpress.DataAccess.Expression("?parameterNoOfItems", typeof(int))
};
dataSource.Constructor = new ObjectConstructorInfo(parameter);
dataSource.DataMember = "Items";
return dataSource;
}
else
{
ObjectDataSource dataSource = new ObjectDataSource();
dataSource.Name = "EmployeeObjectDS";
dataSource.DataSource = typeof(EmployeeList);
var parameterNoOfItems = new Parameter("noOfItems", typeof(int), 12);
dataSource.Parameters.Add(parameterNoOfItems);
dataSource.DataMember = "GetData";
dataSource.Constructor = ObjectConstructorInfo.Default;
return dataSource;
}
}
//private XtraReport AddParameterToReport(XtraReport report)
//{
// DevExpress.XtraReports.Parameters.Parameter param =
// new DevExpress.XtraReports.Parameters.Parameter()
// {
// Name = "parameterNoOfItems",
// Type = typeof(int),
// Value = 5
// };
// param.Description = "Number of Items";
// report.Parameters.Add(param);
// report.RequestParameters = false;
// return report;
//}
}
}
C#using System;
using Microsoft.AspNetCore.Hosting;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using DevExpress.XtraReports.UI;
using DevExpress.XtraReports.Web.ClientControls;
using DevExpress.XtraReports.Parameters;
namespace Reporting_ObjectDS_Blazor
{
public class CustomReportStorageWebExtension : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension
{
readonly string ReportDirectory;
const string FileExtension = ".repx";
public CustomReportStorageWebExtension(IWebHostEnvironment env)
{
ReportDirectory = Path.Combine(env.ContentRootPath, "Reports");
if (!Directory.Exists(ReportDirectory))
{
Directory.CreateDirectory(ReportDirectory);
}
}
private bool IsWithinReportsFolder(string url, string folder)
{
var rootDirectory = new DirectoryInfo(folder);
var fileInfo = new FileInfo(Path.Combine(folder, url));
return fileInfo.Directory.FullName.ToLower().StartsWith(rootDirectory.FullName.ToLower());
}
public override bool CanSetData(string url)
{
// Determines whether it is possible to store a report by a given URL.
// For instance, make the CanSetData method return false for reports that should be read-only in your storage.
// This method is called only for valid URLs (for example, if the IsValidUrl method returns true) before the SetData method is called.
return true;
}
public override bool IsValidUrl(string url)
{
// Determines whether the URL passed to the current Report Storage is valid.
// For instance, implement your own logic to prohibit URLs that contain white spaces or other special characters.
// This method is called before the CanSetData and GetData methods.
return Path.GetFileName(url) == url;
}
public override byte[] GetData(string url)
{
string reportName = url.Substring(0, url.IndexOf("?") == -1 ? url.Length : url.IndexOf("?"));
var query = Microsoft.AspNetCore.WebUtilities.QueryHelpers.ParseQuery(url.Substring(url.IndexOf("?")+1));
var parameterDictionary = query.SelectMany(x => x.Value, (col, value) => new KeyValuePair<string, string>(col.Key, value));
bool needExtraParameter = reportName.Contains("XtraParameter");
if (reportName.StartsWith("EmployeeReport")) reportName = "EmployeeReport";
try
{
if (Directory.EnumerateFiles(ReportDirectory).
Select(Path.GetFileNameWithoutExtension).
Contains(reportName))
{
string path = Path.Combine(ReportDirectory, reportName + FileExtension);
if (parameterDictionary.Count() == 0)
return File.ReadAllBytes(path);
else
{
using (MemoryStream ms = new MemoryStream())
{
XtraReport report = XtraReport.FromXmlFile(path);
foreach (KeyValuePair<string, string> entry in parameterDictionary)
{
if (report.Parameters[entry.Key] != null)
{
report.Parameters[entry.Key].Value = entry.Value;
report.Parameters[entry.Key].Visible = true;
}
}
if (needExtraParameter)
{
Parameter param = new Parameter(){
Name = "parameterNoOfItems",
Type = typeof(int),
Value = 5
};
param.Description = "Number of Items";
report.Parameters.Add(param);
}
report.RequestParameters = false;
report.SaveLayoutToXml(ms);
return ms.ToArray();
}
}
}
}
catch (Exception ex)
{
throw new FaultException("Could not get report data.", ex);
}
throw new FaultException(string.Format("Could not find report '{0}'.", url));
}
public override Dictionary<string, string> GetUrls()
{
// Returns a dictionary of the existing report URLs and display names.
// This method is called when running the Report Designer,
// before the Open Report and Save Report dialogs are shown and after a new report is saved to storage.
return Directory.GetFiles(ReportDirectory, "*" + FileExtension)
.Select(Path.GetFileNameWithoutExtension)
.ToDictionary<string, string>(x => x);
}
public override void SetData(XtraReport report, string url)
{
// Stores the specified report to a Report Storage using the specified URL.
// This method is called only after the IsValidUrl and CanSetData methods are called.
if (!IsWithinReportsFolder(url, ReportDirectory))
throw new DevExpress.XtraReports.Web.ClientControls.FaultException("Invalid report name.");
report.SaveLayoutToXml(Path.Combine(ReportDirectory, url + FileExtension));
}
public override string SetNewData(XtraReport report, string defaultUrl)
{
// Stores the specified report using a new URL.
// The IsValidUrl and CanSetData methods are never called before this method.
// You can validate and correct the specified URL directly in the SetNewData method implementation
// and return the resulting URL used to save a report in your storage.
SetData(report, defaultUrl);
return defaultUrl;
}
}
}
C#using DevExpress.DataAccess.Web;
using System;
using System.Collections.Generic;
namespace Reporting_ObjectDS_Blazor
{
public class ObjectDataSourceWizardCustomTypeProvider : IObjectDataSourceWizardTypeProvider
{
public IEnumerable<Type> GetAvailableTypes(string context)
{
return new[] { typeof(EmployeeList) };
}
}
}
C#using DevExpress.AspNetCore.Reporting;
using DevExpress.Blazor.Reporting;
using DevExpress.XtraReports.Web.Extensions;
using DevExpress.XtraReports.Web.WebDocumentViewer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Reporting_ObjectDS_Blazor
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddDevExpressBlazorReporting();
services.AddScoped<ReportStorageWebExtension, CustomReportStorageWebExtension>();
services.AddTransient<IWebDocumentViewerReportResolver, CustomWebDocumentViewerReportResolver>();
services.ConfigureReportingServices(configurator =>
{
configurator.ConfigureReportDesigner(designerConfigurator =>
{
designerConfigurator.RegisterObjectDataSourceWizardTypeProvider<ObjectDataSourceWizardCustomTypeProvider>();
});
DevExpress.Utils.DeserializationSettings.RegisterTrustedClass(typeof(EmployeeList));
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseDevExpressBlazorReporting();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
endpoints.MapControllers();
});
}
}
}