ActiveReports 18 .NET Edition
Developers / Create Designer and Viewer Applications / WebDesigner Application / Configure and Use Shared Data Sources
In This Topic
    Configure and Use Shared Data Sources
    In This Topic

    The shared data sources contain connection properties that allow binding multiple reports to same data. The shared data sources can be created and edited only in Standalone Designer or VS Integrated Designer. In WebDesigner, however, you can only reference an existing data source.

    Following are the scenarios for using shared data sources in web designer:

    The shared data source solves this problem because the report definition contains only the reference to the data source definition, which is resolved on the server-side when a report is previewed.

    Note: Shared data sources are disabled by default.

    You must create a shared data source (.rdsx) in Standalone Designer or Visual Studio Integrated Designer. See Work with Local Shared Data Sources for more information.

    The steps to use shared data sources are elaborated below. You should first create a WebDesigner-integrated ASP.NET MVC Core application. See the following pages for the information on:

    We will be adding shared data source functionality in an already available sample: WebDesigner_MVC_Core.

    1. Open the WebDesigner_MVC_Core application.
    2. Place the shared reference, a .rdsx file, in the ‘resources’ folder of the project.
    3. In the script.js where web designer is initialized, use shared property to enable shared data sources. The complete script.js code is as shown.       
      script.js
      Copy Code
      import { arWebDesigner } from './web-designer.js';
      import { createViewer } from './jsViewer.min.js';
      let viewer = null;
      let serverUrl = getServerUrl();
      function getServerUrl() {
          let baseUrl = 'api';
          let virtualDirName = document.getElementById('virtualDir');
          if (virtualDirName && virtualDirName.href != window.location.origin + '/') {
              return virtualDirName.href + baseUrl;
          }
          return baseUrl;
      }
      arWebDesigner.create('#ar-web-designer', {
          server: {
              url: serverUrl
          },
          appBar: { openButton: { visible: true } },
          data: { dataSets: { canModify: true }, dataSources: { canModify: true, shared: { enabled: true } } },
          preview: {
              openViewer: (options) => {
                  if (viewer) {
                      viewer.theme = options.theme;
                      viewer.openReport(options.documentInfo.id);
                      return;
                  }
                  viewer = createViewer({
                      element: '#' + options.element,
                      reportService: {
                          url: 'api/reporting',
                      },
                      reportID: options.documentInfo.id,
                      settings: {
                          zoomType: 'FitPage',
                      },
                      theme: options.theme
                  });
              }
          }
      });
      

      Implement the IReportStore

    4. Create 'Implementation' folder.

    5. To the 'Implementation' folder, add ‘ReportStore.cs’ class which will contain implementation for IReportStore.

      ReportStore.cs
      Copy Code
      using System;
      using System.Collections.Generic;
      using System.IO;
      using System.Linq;
      using GrapeCity.ActiveReports.Rendering.Tools;
      using GrapeCity.ActiveReports.Web.Designer;
      using GrapeCity.ActiveReports.Web.Viewer;
      namespace WebDesigner_MVC_Core.Implementation
      {
          public class ReportStore : IReportStore
          {
              private static readonly string[] ReportExtensions =
              {
              ".rdl",
              ".rdlx",
              ".rdlx-master",
              ".rpx"
          };
              private readonly Dictionary<string, byte[]> _tempStorage = new Dictionary<string, byte[]>();
              private readonly DirectoryInfo _rootDirectory;
              public ReportStore(DirectoryInfo rootDirectory)
              {
                  _rootDirectory = rootDirectory;
              }
              public ReportDescriptor GetReportDescriptor(string reportId)
              {
                  if (_tempStorage.ContainsKey(reportId))
                      return new ReportDescriptor(GetReportTypeByExtension(Path.GetExtension(reportId)));
                  var fileInfo = new FileInfo(Path.Combine(_rootDirectory.FullName, reportId));
                  return new ReportDescriptor(GetReportTypeByExtension(fileInfo.Extension));
              }
              public Stream LoadReport(string reportId)
              {
                  if (_tempStorage.TryGetValue(reportId, out var tempReport))
                      return new MemoryStream(tempReport);
                  var file = new FileInfo(Path.Combine(_rootDirectory.FullName, reportId));           
                  return file.OpenRead();
              }
              public string SaveReport(ReportType reportType, string reportId, Stream reportData, SaveSettings settings = SaveSettings.None)
              {
                  if ((settings & SaveSettings.IsTemporary) != 0)
                  {
                      var tempName = Guid.NewGuid() + GetReportExtension(reportType);
                      _tempStorage.Add(tempName, reportData.ToArray());
                      return tempName;
                  }
                  var reportFullPath = Path.Combine(_rootDirectory.FullName, reportId);
                  using var fileStream = new FileStream(reportFullPath, FileMode.Create, FileAccess.Write);
                  reportData.CopyTo(fileStream);
                  return reportId;
              }
              public string UpdateReport(ReportType reportType, string reportId, Stream reportData)
              {
                  return SaveReport(reportType, reportId, reportData);
              }
              public ReportInfo[] ListReports()
              {
                  var reports = _rootDirectory
                      .EnumerateFiles("*.*")
                      .Where(fileInfo => ReportExtensions.Any(ext =>
                          fileInfo.Extension.EndsWith(ext, StringComparison.InvariantCultureIgnoreCase)))
                      .Select(fileInfo => new ReportInfo()
                      {
                          Id = fileInfo.Name,
                          Name = fileInfo.Name,
                          ReportType = GetReportTypeByExtension(fileInfo.Extension),
                      }).ToArray();
                  return reports;
              }
              private static ReportType GetReportTypeByExtension(string extension)
              {
                  switch (extension)
                  {
                      case ".rdl":
                      case ".rdlx":
                          return ReportType.RdlXml;
                      case ".rdlx-master":
                          return ReportType.RdlMasterXml;
                      case ".rpx":
                          return ReportType.RpxXml;
                      default:
                          throw new ArgumentOutOfRangeException(nameof(extension), extension, null);
                  }
              }
              private static string GetReportExtension(ReportType type)
              {
                  return type switch
                  {
                      ReportType.RdlXml => ".rdlx",
                      ReportType.RdlMasterXml => ".rdlx-master",
                      ReportType.RpxXml => ".rpx",
                      _ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
                  };
              }
              public void DeleteReport(string reportId)
              {
                  if (_tempStorage.ContainsKey(reportId))
                  {
                      _tempStorage.Remove(reportId);
                      return;
                  }
                  var file = new FileInfo(Path.Combine(_rootDirectory.FullName, reportId));
                  if (file.Exists)
                      file.Delete(); ;
              }
          }
      }
      

      Implement the IResourcesService

    6. Add 'ResourceService.cs'  to the 'Implementation' folder to add implementation for IResourcesService.

      ResourceService.cs
      Copy Code
      using System.IO;
      using System.Linq;
      using GrapeCity.ActiveReports;
      using GrapeCity.ActiveReports.Rendering.Tools;
      using GrapeCity.ActiveReports.Web.Designer;
      namespace WebDesigner_MVC_Core.Implementation
      {
          public class ResourceProvider : IResourceRepositoryProvider
          {
              private const string SharedDataSourceExtension = ".rdsx";
              private readonly DirectoryInfo _rootDirectory;
              public ResourceProvider(DirectoryInfo rootDirectory)
              {
                  _rootDirectory = rootDirectory;
              }
              public Stream GetResource(ResourceInfo resource)
              {
                  string absolutePath = Path.Combine(_rootDirectory.FullName, resource.Name);
                  var file = new FileInfo(absolutePath);
                  if (!file.Exists)
                      return null;
                  return file.OpenRead();
              }
              public ResourceDescriptor[] ListResources(ResourceType resourceType)
              {
                  if (resourceType == ResourceType.SharedDataSource)
                  {
                      var sharedDataSources = _rootDirectory
                          .EnumerateFiles("*" + SharedDataSourceExtension).Select(fileInfo =>
                          {
                              using var stream = fileInfo.OpenRead();
                              var dataSource = DataSourceTools.LoadSharedDataSource(stream);
                              return new SharedDataSourceResourceDescriptor()
                              {
                                  Id = fileInfo.Name,
                                  Name = fileInfo.Name,
                                  Type = dataSource.ConnectionProperties.DataProvider
                              };
                          }).ToArray();
                      return sharedDataSources;
                  }
                  return Enumerable.Empty<ResourceDescriptor>().ToArray();
              }
              public ResourceDescriptor[] DescribeResources(ResourceInfo[] resources)
              {
                  return Enumerable.Empty<ResourceDescriptor>().ToArray();
              }
          }
      }
      

      Configure and register services

    7. Open Startup.cs and update the file as shown below. The Startup.cs file does the following:

      1. configures the services and middleware used by the application
      2. registers the  'IReportStore' and 'IResourceRepositoryProvider' as singleton services
      3. adds reporting and designer services
      4. sets the path to the ActiveReports.config file where the SQLite provider is added
      5. configures the reporting and designer middleware
      6. serves static files
                       
        Startup.cs
        Copy Code
        using System.IO;
        using Microsoft.AspNetCore.Builder;
        using Microsoft.AspNetCore.Hosting;
        using Microsoft.Extensions.Hosting;
        using Microsoft.Extensions.Configuration;
        using Microsoft.Extensions.DependencyInjection;
        using GrapeCity.ActiveReports.Aspnetcore.Viewer;
        using GrapeCity.ActiveReports.Aspnetcore.Designer;
        using System.Text;
        using GrapeCity.ActiveReports.Web.Designer;
        using WebDesigner_MVC_Core.Implementation;
        using System;
        namespace WebDesignerMvcCore
        {
            public class Startup
            {
                private static readonly DirectoryInfo ResourcesRootDirectory =
                    new DirectoryInfo(Path.Combine(Directory.GetCurrentDirectory(), "resources" + Path.DirectorySeparatorChar));
                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.
                public void ConfigureServices(IServiceCollection services)
                {
                    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
                    services
                        .AddReportViewer()
                        .AddReportDesigner()
                        .AddSingleton<IReportStore>(new ReportStore(ResourcesRootDirectory))
                        .AddSingleton<IResourceRepositoryProvider>(new ResourceProvider(ResourcesRootDirectory))
                        .AddMvc(options => options.EnableEndpointRouting = false)
                        .AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
                }
                // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
                                       
                    public void Configure(IApplicationBuilder app,
                    IWebHostEnvironment env,
                    IReportStore reportStore,
                    IResourceRepositoryProvider resourceProvider
                    )
                {
                    if (env.IsDevelopment())
                    {
                        app.UseDeveloperExceptionPage();
                    }
                    var pathToConfig = Path.Combine(Environment.CurrentDirectory, "ActiveReports.config");
                    app.UseReportDesigner(config =>
                    {
                        config.UseReportsProvider(reportStore);
                        config.UseResourcesProvider(resourceProvider);
                        config.UseConfig(pathToConfig);
                    });
                    app.UseFileServer();
                    app.UseMvc();
                }
            }
        }
        
    8. Add 'ActiveReports.config' with following content.

      ActiveReports.config
      Copy Code
      <?xml version="1.0" encoding="utf-8" ?>
      <Configuration>
          <Extensions>
              <Data>
                  <Extension Name="SQLITE" Type="System.Data.SQLite.SQLiteFactory, System.Data.SQLite"
                             DisplayName="Sqlite Provider" />
              </Data>
          </Extensions>
      </Configuration>
      
    9. Run the application.
    10. Go to the Data tab to add the data source.

    11. In the Data Source Editor dialog, select ‘Shared Reference’ as Provider and then the ‘.rdsx’ file as Reference.Shared Reference configuration in Data Source Editor dialog

    See Also