AR13 Web Viewer Not Loading Themes and Images

Posted by: nicolaas.coetzee on 8 October 2019, 1:11 am EST

  • Posted 8 October 2019, 1:11 am EST

    Hi

    I am having trouble getting themes and images working on preview in the AR13 Web Viewer. In the designer the theme and images are being loaded and can be seen as in the screenshot below


    However when attempting to preview the report neither the theme nor the image get loaded as seen in the screenshot below


    Any guidance would be appreciated.
  • Replied 8 October 2019, 6:12 pm EST

    Hello Nicolaas,

    In my understanding, at runtime, the designer failed to locate the path of the themes and images. You need to update the resource as shown in the attached sample code.
    If the issue still reproduces, please share the stripped-down application with us so that I can replicate the issue at my end.
    This will be very helpful for us.

    Thanks,
    Mohit

    ReportResources.zip
  • Replied 9 October 2019, 12:52 am EST

    Hi Mohitg

    Thanks for the reply. I have tried your suggestion and I have managed to get a File based theme to work. I was not expecting the themes and other resources to be dependent on embedded paths for preview, I was hoping they would use the same methods that the designer does.

    This poses a new question. How would I pull a theme from an API on preview? The designer can pull themes form the API by doing the following

    public Theme GetTheme(string id) {
    try {
    string[] IDparts = id.Split('|');
    if (IDparts.Length != 2) {
    throw new LoggedException($"Invalid theme selected - {id}.");
    }
    Theme theme = null;
    ReportPreviewOptions reportPreviewOptions = GetPreviewOptionsFromHeaders();
    if (reportPreviewOptions == null) {
    return null;
    }
    HttpResponseMessage result = ReportHttpClient.SendRequest(reportPreviewOptions.CoreURL, $"Theme/GetThemeDetailsByID/{IDparts[1]}", reportPreviewOptions.Token, HttpMethod.Get);
    if (result.IsSuccessStatusCode) {
    Dictionary<string, ThemeDet> coreThemeDetails = result.Content.ReadAsStringAsync().Result.ConvertJsonStringToObjectAsync<Dictionary<string, ThemeDet>>().Result;
    if (coreThemeDetails.Values == null || coreThemeDetails.Values.Count == 0) {
    throw new Exception($" theme for ID {IDparts[1]} has not been properly configured");
    }
    theme = ParseTheme(coreThemeDetails);
    } else {
    throw new Exception("Failed to get theme.");
    }
    return theme;
    } catch (Exception ex) {
    throw new LoggedException($"Failed to get theme {id}", ex);
    }
    }

    public IThemeInfo[] GetThemesList() {
    List<ReportTheme> reportThemes = new List<ReportTheme>();
    ReportPreviewOptions reportPreviewOptions = GetPreviewOptionsFromHeaders();
    try {
    HttpResponseMessage result = ReportHttpClient.SendRequest(reportPreviewOptions.CoreURL, "Theme/GetAllThemeDefinitionStubs", reportPreviewOptions.Token, HttpMethod.Get);
    if (result.IsSuccessStatusCode) {
    List<ThemeDet> coreThemes = result.Content.ReadAsStringAsync().Result.ConvertJsonStringToObjectAsync<List<ThemeDet>>().Result;
    foreach (var item in coreThemes) {
    result = null;
    result = ReportHttpClient.SendRequest(reportPreviewOptions.CoreURL, $"Theme/GetThemeByID/{item.ID}", reportPreviewOptions.Token, HttpMethod.Get);
    if (result.IsSuccessStatusCode) {
    ThemeDefinition coreTheme = result.Content.ReadAsStringAsync().Result.ConvertJsonStringToObjectAsync<ThemeDefinition>().Result;
    ReportTheme reportTheme = new ReportTheme();
    reportTheme = (ReportTheme)ParseTheme(coreTheme.Details);
    reportTheme.Id = "APITheme |" + item.ID;
    reportTheme.Title = item.Name;
    reportThemes.Add(reportTheme);
    } else {
    throw new LoggedException("Failed to get theme.");
    }
    }
    } else {
    throw new LoggedException("Failed to get themes.");
    }
    } catch (Exception ex) {
    throw new LoggedException("Failed to get themes.", ex);
    }

    return reportThemes.ToArray();
    }


    But I don`t seem how I would be able to embed the API call into the saved report for preview

    FYI my report are based on the MVC Core solution.
  • Replied 9 October 2019, 10:53 pm EST

    Hello,

    You can use the CustomResourceLoactor to get the theme from API. You can refer te following link to how to implement in the WebDesigner:
    https://www.grapecity.com/forums/ar-dev/webdesignerjsviewer-set-da#hello-kevini-got-a-reply-f

    Also, if you want to know about ResourceLocator class, please refer to the following link:
    https://help.grapecity.com/activereports/webhelp/AR13/webframe.html#AdvancedCustomResourceLocator.html
    https://help.grapecity.com/activereports/webhelp/AR13/webframe.html#CustomResourceLocator.html

    Hope it helps.

    Thanks,
    Mohit
  • Replied 10 October 2019, 7:56 pm EST

    Hi Mohit

    Thanks for the above information. I have tried to implement the CustomResourceLocator, one thing that I don`t quite understand is how to link the Resource locator to the report. I assume I will have to create ResourceLocators for each of the resource types I would like to retrieve i.e. Themes, images or SubReports since each of the types would be handled differently. Is this assumption correct?

    I can see how this example https://www.grapecity.com/forums/ar-dev/webdesignerjsviewer-set-da#hello-kevini-got-a-reply-f would handle sub reports but I don`t understand how it will handle themes or images.

    The documentation links on the other hand suggest assigning the resource locator
    PageReport def = new PageReport(reader);
    def.ResourceLocator = new MyPicturesLocator();

    But this does not seem applicable to the WebViewer since it does not use PageReports but instead uses GrapeCity.ActiveReports.PageReportModel.Report objects. Does this mean I should convert the Report object to a PageReport and back (not sure if this would even work) to assign the ResourceLocator or is there a better way?

    Any advice or guidance would be appreciated.


  • Marked as Answer

    Replied 10 October 2019, 10:18 pm EST

    Hello Nicolaas,

    No, you don't need to create a different resource locator for all of this. You just need to create a single resource locator. You need to handle IF else condition for all images, themes and subreport in the GetResource method.


    {
    public override Resource GetResource(ResourceInfo resourceInfo)
    {
    Resource _resource;
    // URI you can give API address of theme
    Uri uri = new Uri("file:///C:/Users/MohitG/source/repos/JSViewer_MVC/JSViewer_MVC/LocateDataSoource.rdlx");
    //Here it compare the resource name(either theme/image/subreport), load the data to the specfic property.
    if (resourceInfo.Name.Equals("LocateDataSoource.rdlx"))
    {
    byte[] _buffer = System.Text.UTF8Encoding.UTF8.GetBytes(File.ReadAllText(@"C:\Users\MohitG\source\repos\JSViewer_MVC\JSViewer_MVC\LocateDataSoource.rdlx"));
    MemoryStream _ms = new MemoryStream(_buffer);
    if (_ms != null)
    {
    _resource = new Resource(_ms,uri);
    }
    }
    return _resource;
    }
    }


    >>But this does not seem applicable to the WebViewer since it does not use PageReports
    Sorry for the confusion, I had provided the documentation link to just know more about ResourceLocator. You can use directly use the GrapeCity.ActiveReports.PageReportModel.Report objects as shown in the provided forum link.
    https://www.grapecity.com/forums/ar-dev/webdesignerjsviewer-set-da#hello-kevini-got-a-reply-f

    private object GetReport(string arg)
    {

    var stream = new FileStream($@"C:\Users\MohitG\source\repos\JSViewer_MVC\JSViewer_MVC\main.rdlx", FileMode.Open);
    var resourceLocator = new SubReportResourceLocator();

    if (stream == null)
    throw new ReportNotFoundException();

    using (var reader = new StreamReader(ReportConverter.ToXml(GrapeCity.ActiveReports.PageReportModel.Report object)))
    {
    var report = PersistenceFilter.Load(reader, resourceLocator);
    report.Site = new ReportSite(resourceLocator);
    if (string.IsNullOrEmpty(report.Name))
    report.Name = "Main.rdlx";
    return report;
    }
    }


    Hope it clarifies your question.

    Thanks,
  • Replied 14 October 2019, 7:41 pm EST

    Hi Mohit

    Thanks for the above clarification. I have tried implementing the custom resource locator as suggested however at the moment I am getting a new error which I have not seen

    I have not found anything in the documentation about the LayoutEngine. Any advice?

  • Replied 14 October 2019, 8:29 pm EST

    I managed to solve the above issue. It was a error in the way I implemented the ReportSite.
  • Replied 14 October 2019, 8:45 pm EST

    Hello Nicolaas,

    I am glad that your issue is resolved now. Please feel free to revert if you face any issue further.

    Thanks,
    Mohit
  • Replied 14 October 2019, 8:57 pm EST

    Hi Mohit

    The code is now running as expected but the themes are still not taking affect on preview time. Is there a specific way the resource needs to be Encoded perhaps?

    Currently I am returning my Theme resource like this
    return new Resource(new MemoryStream(Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(theme))), ResourceUri);

    The "ResourceUri" is set to the full api path or file path in this case.

    Design time works fine but I need to handle the resource like this to have it work
            public Theme GetTheme(string id) {
    CustomResourceLocator customResourceLocator = new CustomResourceLocator(cacheProvider, httpContextAccessor);
    Resource themeResource = customResourceLocator.GetResource(new ResourceInfo(id));
    if (themeResource.Value == null) {
    return null;
    }
    themeResource.Value.Position = 0;
    using (StreamReader sr = new StreamReader(themeResource.Value)) {
    return JsonConvert.DeserializeObject<Theme>(sr.ReadToEnd());
    }
    }
  • Replied 15 October 2019, 6:22 pm EST

    Hello Nicolaas,

    I tried at our end and theme is load successfully at preview time at my end. I have used the following code at my end:


    private object GetReport(string arg)
    {

    var stream = new FileStream($@"C:\Users\MohitG\source\repos\JSViewer_MVC\JSViewer_MVC\test.rdlx", FileMode.Open);
    var resourceLocator = new SubReportResourceLocator();

    if (stream == null)
    throw new ReportNotFoundException();

    using (var reader = new StreamReader(stream))
    {
    var report = PersistenceFilter.Load(reader, resourceLocator);
    report.Site = new ReportSite(resourceLocator);
    if (string.IsNullOrEmpty(report.Name))
    report.Name = "Main.rdlx";
    return report;
    }
    }



    public class ReportSite : ISite
    {
    private readonly ResourceLocator _resourceLocator;

    public ReportSite(ResourceLocator resourceLocator)
    {
    _resourceLocator = resourceLocator;
    }

    public object GetService(Type serviceType) =>
    serviceType == typeof(ResourceLocator) ? _resourceLocator : null;

    public IComponent Component => null;
    public IContainer Container => null;
    public bool DesignMode => false;
    public string Name { get; set; }
    }
    public class SubReportResourceLocator : ResourceLocator
    {
    public override Resource GetResource(ResourceInfo resourceInfo)
    {
    Resource _resource;
    Uri uri = new Uri("http://localhost:44320");

    if (resourceInfo.Name.Equals("Handsome.rdlx-theme"))
    {
    byte[] _buffer = System.Text.UTF8Encoding.UTF8.GetBytes(File.ReadAllText(@"C:\Users\MohitG\Documents\GrapeCity Samples\ActiveReports 13\Web\WebDesigner_MVC\resources\Handsome.rdlx-theme"));
    MemoryStream _ms = new MemoryStream(_buffer);
    if (_ms != null)
    {
    _resource = new Resource(_ms,uri);
    }
    }
    return _resource;
    }
    }



    >>JsonConvert.SerializeObject(theme))
    Is theme an object which contains data from API? You have to fetch theme from API as you do in GetTheme method.

    >>Design time works fine but I need to handle the resource like this to have it work
    Design-time is already working at your end as per your initial post. The main issue is at preview time. You need to handle only report service, not designer service.
    If you provide the sample, I can look into your sample to make it work.

    Thanks,
    Mohit
  • Replied 15 October 2019, 7:36 pm EST

    Hi Mohit

    I finally got the theme loading.
    The problem was the way I was populating the Resource.Value. I was populating it with a GrapeCity.ActiveReports.Aspnetcore.Designer.Services.Theme object loaded into a steam. This worked in design time since I was handling the object stream correctly but at runtime it does not work.

    When I changed my resource locator to return the raw file data as per your last post - like this
    MemoryStream ms = new MemoryStream();
    using (StreamReader sr = new StreamReader(themeFileLocation)) {
    byte[] themeFileData = Encoding.UTF8.GetBytes(sr.ReadToEnd());
    ms = new MemoryStream(themeFileData);
    }
    return new Resource(ms, themeUri);
    the themes started working

    So I believe the source of the issue here was that it was unclear how the resource stream should have been populated to work at runtime.

    Thanks for the help.
  • Replied 15 October 2019, 10:33 pm EST

    Hello Nicolaas,

    There are two services used in the WebDesigner. One for design the report and one for previewing the report. You can't use the designer service at the time of preview that's why you are facing the issue.
    I am glad that your issue is solved now. I hope you have completed the integration of WebDesigner in your application.

    Thanks,
    Mohit
Need extra support?

Upgrade your support plan and get personal unlimited phone support with our customer engagement team

Learn More

Forum Channels