ActiveReports 18 .NET Edition
Developers / Create Designer and Viewer Applications / Blazor 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 the 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.

    We will be adding shared data source functionality in an already available Blazor Designer Server Application sample

    1. Open the Blazor Designer Server Application.
    2. Place the shared reference, a .rdsx  file, in the ‘resources’ folder of the project.
    3. In the Index.razor where web designer is initialized, use Shared property to enable shared data sources. The complete Index.razor code is as shown.       
      Index.razor
      Copy Code
      @page "/"
      @inject IJSRuntime JSRuntime
      <PageTitle>Index</PageTitle>
      <link href="_content/@(typeof(ReportViewer).Assembly.GetName().Name)/jsViewer.min.css" rel="stylesheet" />
      <div id="designerContainer">
          <ReportDesigner @ref="_designer" RpxSettings="@_rpx" AppBarSettings="@_appBar" DataSettings="@_data" PreviewSettings="@_preview" />
      </div>
      @code {
          private ReportDesigner _designer;
          private ReportViewer _viewer;
          private RpxSettings _rpx;
          private AppBarSettings _appBar;
          private DataSettings _data;
          private PreviewSettings _preview;
          public Index()
          {
              _rpx = new RpxSettings
              {
                  Enabled = true
              };
              _appBar = new AppBarSettings
              {
                  OpenButton = new OpenButton { Visible = true }
              };
              _data = new DataSettings
              {
                  DataSets = new DataSets { CanModify = true },
                  DataSources = new DataSources
                  {
                      CanModify = true,
                      Shared = new SharedDataSourceOptions()
                      {
                          Enabled = true
                      }
                  }
              };
              _preview = new PreviewSettings
              {
                  OpenViewer = OpenViewer
              };
          }
          private async void OpenViewer(ViewerSettings settings)
          {
              if(_viewer != null)
              {
                  await _viewer.SetTheme(settings.Theme);
                  await _viewer.OpenReport(settings.DocumentInfo.Id);
                  return;
              }
              _viewer = new ReportViewer();
              var initOptions = new InitializationOptions();
              initOptions.ReportID = settings.DocumentInfo.Id;
              initOptions.PanelsLocation = PanelsLocation.toolbar;
              initOptions.Theme = settings.Theme;
              initOptions.ReportLoaded = (reportInfo) =>
              {
              };
              await _viewer.Render(JSRuntime, settings.Element, initOptions);
          }
      }
      

      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 GrapeCity.ActiveReports.Rendering.Tools;
      using GrapeCity.ActiveReports.Web.Designer;
      using GrapeCity.ActiveReports.Web.Viewer;
      namespace BlazorDesignerServer.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));
                  //if (!file.Exists)
                  //    throw new ReportNotFoundException();
                  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 IResourceRepositoryProvider

    6. Add 'ResourceProvider.cs'  to the 'Implementation' folder to add implementation for IResourceRepositoryProvider.

      ResourceProvider.cs
      Copy Code
      using GrapeCity.ActiveReports.Rendering.Tools;
      using GrapeCity.ActiveReports.Web.Designer;
      using GrapeCity.ActiveReports;
      namespace BlazorDesignerServer.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 Program.cs and update the file as shown below. The Program.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
        The complete Program.cs is as shown.                             
        Program.cs
        Copy Code
        using GrapeCity.ActiveReports.Aspnetcore.Designer;
        using GrapeCity.ActiveReports.Aspnetcore.Viewer;
        using Microsoft.AspNetCore.SignalR;
        using System.Text;
        using GrapeCity.ActiveReports.Web.Designer;
        using BlazorDesignerServer.Implementation;
        var builder = WebApplication.CreateBuilder(args);
        var ResourcesRootDirectory =
            new DirectoryInfo(Path.Combine(Directory.GetCurrentDirectory(), "resources"));
        Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
        // Add services to the container.
        builder.Services.AddReportViewer();
        builder.Services.AddReportDesigner();
        builder.Services.AddSingleton<IReportStore>(new ReportStore(ResourcesRootDirectory));
        builder.Services.AddSingleton<IResourceRepositoryProvider>(new ResourceProvider(ResourcesRootDirectory));
        builder.Services.AddRazorPages().AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
        builder.Services.AddServerSideBlazor();
        builder.Services.Configure<HubOptions>(options =>
        {
            options.MaximumReceiveMessageSize = 524288000; //500MB
        });
        builder.Services.AddCors();
        var app = builder.Build();
        // Configure the HTTP request pipeline.
        if (!app.Environment.IsDevelopment())
        {
            app.UseExceptionHandler("/Error");
        }
        // For use as a server for BlazorWebAssembly
        app.UseCors(cors => cors.SetIsOriginAllowed(origin => new Uri(origin).Host == "localhost")
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials()
            .WithExposedHeaders("Content-Disposition"));
        var reportStore = app.Services.GetService<IReportStore>();
        var resourceProvider = app.Services.GetService<IResourceRepositoryProvider>();
        app.UseReportDesigner(config =>
        {
            config.UseReportsProvider(reportStore);
            config.UseResourcesProvider(resourceProvider);
        });
        app.UseStaticFiles();
        app.UseRouting();
        app.MapControllers();
        app.MapBlazorHub();
        app.MapFallbackToPage("/_Host");
        app.Run();
        
    8. Run the application.
    9. Go to the Data tab to add the data source.

    10. 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