Current filter:
                                You should refresh the page.
                                  • Hi,
                                    my app use .NET Core 2.2 and Angular 7.

                                    I have a report with multiple subreports.
                                    When I load the report in Web Viewer, the method GetData() in my custom implementation of ReportStorageWebExtension goes to a web service to grab a byte array representing the XtraReport object for the main report and for every subreport.

                                    Unfortunately the signature of GetData() method is not async.
                                    Is there any way to load reports asynchronously to achieve the functional equivalent to the following?

                                    [C#]
                                    public async Task<byte[]> GetData(string url) { //… byte[] responseData = null; using (var httpClient = new HttpClient()){ var response = await httpClient.GetAsync(url); if (response.IsSuccessStatusCode) responseData = await response.Content.ReadAsByteArrayAsync(); } return responseData; }

                                    Thanks

                                2 Solutions

                                Creation Date Importance Sort by

                                Fixed:

                                • 19.2.4 :
                                • 19.1.8 :

                                Hi Claudio,
                                Report storage methods do not come with their async version. However, all calls made from the Web Report Designer to a backend application that hosts this designer are made by using asynchronous JavaScript, so these requests are executed asynchronously on the client's web page. As a result, the issue you encountered is not completely clear to me. Would you please clarify why the current architecture does not meet your requirements? What benefits would you like to get by using the async approach?
                                Please let us know.

                                Regards,
                                Yaroslav

                                Show all comments
                                • Claudio Soli 10.14.2019

                                  Hi Yaroslav,

                                  My issue is related to loading reports in Web Viewer.

                                  When I open a report with multiple subreports in Web Viewer I have experienced this:

                                  1. the client sends an asynchronous request to the controller DXXRDV in the backend with the main report's url;
                                  2. the controller DXXRDV calls GetData() method of my custom ReportStorageWebExtension;
                                  3. in GetData() I grab the report xml data from my API endpoint;
                                  4. then GetData() is called by DXXRDV multiple time, sequentially, one for each subreport until all subreports are obtained from API.

                                  So in this last step I get a synchronous behaviour where subreports are loaded sequentially, one after the other, and I need to wait the end of the previous API request before starting the next one.
                                  In my scenario this leads to slow performance and remarkable waiting times on report opening.
                                  Is there a possible solution?

                                  Thanks

                                • Yaroslav (DevExpress Support) 10.14.2019

                                  Thank you for the clarification. I confirm that subreports are loaded sequentially. This behavior is not really specific to web reports, this is how the core reporting engine is written.

                                  >>Is there a possible solution?
                                  As I understand, it takes certain time for the data layer you have implemented (a web service) to retrieve a single definition of a remote report. You've profiled the application and this is the cause of the delay that you observe upon requesting any complex report in your application. Can you confirm that my understanding is correct? If the answer is Yes, can you please clarify how the asynchronous approach can speed things up in this particular case? Are we sure not to confuse the asynchronous approach with the parallel programming model where multiple threads will request different reports concurrently?

                                  From my perspective, the only appropriate way to address this issue is to allow subreports embedding so everything will be delivered in one REPX file. Is it something you'd be interested to see in future versions of our components, even though it will require some work on the already existing reports? Also, can you clarify if using DetailReportBands instead of XRSubreports is something you already considered?

                                  Regards,
                                  Yaroslav

                                • Claudio Soli 10.15.2019

                                  Hi Yaroslav,

                                  I attach a video to better show you the encountered performance problem.

                                  As you can see, if I refresh the Web Viewer related page multiple times, at some point the application hangs with an DXXRDV pending request. From that moment the application becomes unresponsive and I need to recycle the related IIS application pool.

                                  Below the log extract of the pending request where GetData() is printed after the report XML data has been grabbed from API and 89368|0|VDA_DEMO is the main report which contains 6 subreports.

                                  2019-10-15 11:07:45.178 +02:00 [Information] Request starting HTTP/1.1 POST http://dev01/q3dev/reports/DXXRDV application/x-www-form-urlencoded; charset=UTF-8 90
                                  2019-10-15 11:07:45.178 +02:00 [Debug] Request is continuing in applying rules. Current url is "http://dev01/q3dev/reports/DXXRDV"
                                  2019-10-15 11:07:45.178 +02:00 [Debug] "POST" requests are not supported
                                  2019-10-15 11:07:45.178 +02:00 [Debug] "POST" requests are not supported
                                  2019-10-15 11:07:45.178 +02:00 [Debug] "POST" requests are not supported
                                  2019-10-15 11:07:45.179 +02:00 [Debug] AuthenticationScheme: "Cookies" was successfully authenticated.
                                  2019-10-15 11:07:45.179 +02:00 [Debug] AuthenticationScheme: "Cookies" was successfully authenticated.
                                  2019-10-15 11:07:45.179 +02:00 [Debug] Connection id ""0HLQH9P3K2E8U"", Request id ""0HLQH9P3K2E8U:00000004"": started reading request body.
                                  2019-10-15 11:07:45.179 +02:00 [Debug] Connection id ""0HLQH9P3K2E8U"", Request id ""0HLQH9P3K2E8U:00000004"": done reading request body.
                                  2019-10-15 11:07:45.179 +02:00 [Debug] 2 candidate(s) found for the request path '"/DXXRDV"'
                                  2019-10-15 11:07:45.179 +02:00 [Debug] Endpoint '"Blulink.Reports.Controllers.CustomWebDocumentViewerController.Invoke (Blulink.Reports)"' with route pattern '"DXXRDV"' is valid for the request path '"/DXXRDV"'
                                  2019-10-15 11:07:45.179 +02:00 [Debug] Endpoint '"Blulink.Reports.Controllers.HomeController.Index (Blulink.Reports)"' with route pattern '"{**url}"' is valid for the request path '"/DXXRDV"'
                                  2019-10-15 11:07:45.179 +02:00 [Debug] Request matched endpoint '"Blulink.Reports.Controllers.CustomWebDocumentViewerController.Invoke (Blulink.Reports)"'
                                  2019-10-15 11:07:45.179 +02:00 [Information] Executing endpoint '"Blulink.Reports.Controllers.CustomWebDocumentViewerController.Invoke (Blulink.Reports)"'
                                  2019-10-15 11:07:45.179 +02:00 [Information] Route matched with "{action = "Invoke", controller = "CustomWebDocumentViewer", page = ""}". Executing action "Blulink.Reports.Controllers.CustomWebDocumentViewerController.Invoke (Blulink.Reports)"
                                  2019-10-15 11:07:45.179 +02:00 [Debug] Execution plan of "authorization" filters (in the following order): ["Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter"]
                                  2019-10-15 11:07:45.179 +02:00 [Debug] Execution plan of "resource" filters (in the following order): ["Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.SaveTempDataFilter"]
                                  2019-10-15 11:07:45.179 +02:00 [Debug] Execution plan of "action" filters (in the following order): ["Microsoft.AspNetCore.Mvc.Internal.ControllerActionFilter (Order: -2147483648)", "Microsoft.AspNetCore.Mvc.ModelBinding.UnsupportedContentTypeFilter (Order: -3000)", "Microsoft.AspNetCore.Mvc.Internal.ResponseCacheFilter"]
                                  2019-10-15 11:07:45.179 +02:00 [Debug] Execution plan of "exception" filters (in the following order): ["None"]
                                  2019-10-15 11:07:45.179 +02:00 [Debug] Execution plan of "result" filters (in the following order): ["Microsoft.AspNetCore.Mvc.ViewFeatures.Internal.SaveTempDataFilter"]
                                  2019-10-15 11:07:45.179 +02:00 [Information] Authorization was successful.
                                  2019-10-15 11:07:45.186 +02:00 [Information] Executing action method "Blulink.Reports.Controllers.CustomWebDocumentViewerController.Invoke (Blulink.Reports)" - Validation state: Valid
                                  2019-10-15 11:07:45.187 +02:00 [Information] ReportLoggerService [10/15/2019 11:07:45]: Info: '"OperReport operation. Report id: 89368|0|VDA_DEMO?company=QPAP&language=en"'.
                                  2019-10-15 11:07:45.187 +02:00 [Debug] AuthenticationScheme: "Cookies" was successfully authenticated.
                                  2019-10-15 11:07:45.207 +02:00 [Debug] GetData() = http://dev01/q3dev/api/QPAP/Reports/89368|0|VDA_DEMO
                                  2019-10-15 11:07:45.227 +02:00 [Debug] AuthenticationScheme: "Cookies" was successfully authenticated.
                                  2019-10-15 11:07:45.251 +02:00 [Debug] GetData() = http://dev01/q3dev/api/QPAP/Reports/89368|0|VDA_DEMO_P7
                                  2019-10-15 11:07:45.263 +02:00 [Debug] AuthenticationScheme: "Cookies" was successfully authenticated.
                                  2019-10-15 11:07:45.283 +02:00 [Debug] GetData() = http://dev01/q3dev/api/QPAP/Reports/89368|0|VDA_DEMO_P6
                                  2019-10-15 11:07:45.295 +02:00 [Debug] AuthenticationScheme: "Cookies" was successfully authenticated.
                                  2019-10-15 11:07:45.323 +02:00 [Debug] GetData() = http://dev01/q3dev/api/QPAP/Reports/89368|0|VDA_DEMO_P5
                                  2019-10-15 11:07:45.334 +02:00 [Debug] AuthenticationScheme: "Cookies" was successfully authenticated.

                                  What could cause the request to freeze inside DXXRDV controller?

                                  Thanks

                                • Yaroslav (DevExpress Support) 10.15.2019

                                  >>As you can see, if I refresh the Web Viewer related page multiple times, at some point the application hangs with an DXXRDV pending request
                                  I see the issue in the attached screencast and I must admit that that's not how I envisioned the situation from your original post. I though it always takes time to request any report, but it now appears that the issue is more sporadic.

                                  >>What could cause the request to freeze inside DXXRDV controller?
                                  The DXXRDV is responsible for many things as this is the end-point that serves all viewer requests, such as requests for starting the document generation, printing or exporting. I can't say for sure what goes wrong here. You mentioned that the entire application goes unresponsive which would indicate a serious problem such as running out of available memory or other resources. To troubleshoot the issue, I suggest that you collect various performance-related metrics in the Windows Performance Monitor to see how the application behaves when you constantly refresh the page. Also, verify that no unhandled exceptions are thrown using the built-in logger provider or while attaching to the application with the Visual Studio debugger: Debug ASP.NET or ASP.NET Core apps in Visual Studio.

                                  Let us know if you find anything.

                                  Regards,
                                  Yaroslav

                                • Claudio Soli 10.16.2019

                                  Hi Yaroslav,

                                  I verified that no unhandled exception are thrown but I found that in processing the last request (before the application goes unresponsive) 15 seconds are spent inside the ReportManagementService (see the attached image).

                                  Thanks

                                • Yaroslav (DevExpress Support) 10.16.2019

                                  The results of your profiler session present a great interest for us Claudio, thank you. Still, I believe there is more to this. Can you clarify if you do any particular customization over the document viewer in your Angular application? Do you implement a solution similar to the one described in the Web Document Viewer - How to dispose of a report object after the report generation thread?
                                  Please let us know so we can try reproducing the same freezing on our side.

                                • Claudio Soli 10.17.2019

                                  Hi,

                                  using Close via javascript as suggested in https://www.devexpress.com/Support/Center/Question/Details/T809676/web-document-viewer-how-to-dispose-of-a-report-object-after-the-report-generation
                                  solve server memory consume.
                                  But the problem of large time spent (15 sec) in ReportManagementService still remain.

                                  Any News

                                  Thanks

                                • Yaroslav (DevExpress Support) 10.17.2019

                                  So, do you confirm that you use this solution in your front-end application? Can you share the relevant source code?

                                • Claudio Soli 10.18.2019

                                  Hi,

                                  yes, I use that solution.
                                  Below the most relevant part of my source code.

                                  [Startup.cs]

                                  [C#]
                                  //... public void ConfigureServices(IServiceCollection services) { //... services.AddDevExpressControls(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2).ConfigureApplicationPartManager(x => { var parts = x.ApplicationParts; var aspNetCoreReportingAssemblyName = typeof(DevExpress.AspNetCore.Reporting.WebDocumentViewer.WebDocumentViewerController).Assembly.GetName().Name; var reportingPart = parts.FirstOrDefault(part => part.Name == aspNetCoreReportingAssemblyName); if (reportingPart != null) { parts.Remove(reportingPart); } }); services.ConfigureReportingServices(configurator => { configurator.ConfigureReportDesigner(designerConfigurator => { designerConfigurator.RegisterDataSourceWizardJsonConnectionStorage<ReportConnectionJsonProvider>(); }); configurator.ConfigureWebDocumentViewer(viewerConfigurator => { viewerConfigurator.UseCachedReportSourceBuilder(); }); }); services.AddSpaStaticFiles(configuration => { configuration.RootPath = "wwwroot/angular"; }); services.AddHttpContextAccessor(); services.AddSingleton<WebDocumentViewerOperationLogger, WebViewerOperationLog>(); //... } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILogger<Startup> logger) { //... ReportShared.reportStorage = new BlulinkReportStorage(app.ApplicationServices.GetRequiredService<ILogger<BlulinkReportStorage>>(), app.ApplicationServices.GetService<IHttpContextAccessor>()); DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension.RegisterExtensionGlobal(ReportShared.reportStorage); DevExpress.XtraReports.Configuration.Settings.Default.UserDesignerOptions.DataBindingMode = DevExpress.XtraReports.UI.DataBindingMode.Expressions; if (env.IsDevelopment()) { DevExpress.XtraReports.Web.ClientControls.LoggerService.Initialize(new ReportLoggerService(app.ApplicationServices.GetRequiredService<ILogger<ReportLoggerService>>())); } //... #if DEBUG app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider( Path.Combine(Directory.GetCurrentDirectory(), "ClientApp\\node_modules")), RequestPath = "/modules" }); #endif app.UseStaticFiles(); app.UseSpaStaticFiles(); // cerco nella cartella angular specificata in AddSpaStaticFiles() app.UseAuthentication(); app.UseDevExpressControls(); app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); routes.MapRoute( name: "spa-fallback", template: "{**url}", defaults: new { controller = "Home", action = "Index" }); }); //... } //...

                                  [DevExpressCustomControllers.cs]

                                  [C#]
                                  [Authorize] [ApiExplorerSettings(IgnoreApi = true)] [Route("DXXRDV")] public class CustomWebDocumentViewerController : WebDocumentViewerController { public CustomWebDocumentViewerController(IWebDocumentViewerMvcControllerService controllerService) : base(controllerService) {} public override Task<IActionResult> Invoke() { return base.Invoke(); } } [Authorize] [ApiExplorerSettings(IgnoreApi = true)] [Route("DXXQB")] public class CustomQueryBuilderController : QueryBuilderController { public CustomQueryBuilderController(IQueryBuilderMvcControllerService controllerService) : base(controllerService) {} public override Task<IActionResult> Invoke() { return base.Invoke(); } } [Authorize] [ApiExplorerSettings(IgnoreApi = true)] [Route("DXXRD")] public class CustomReportDesignerController : ReportDesignerController { public CustomReportDesignerController(IReportDesignerMvcControllerService controllerService) : base(controllerService) {} public override Task<IActionResult> Invoke() { return base.Invoke(); } }

                                  [ApiController.cs]

                                  [C#]
                                  [Authorize] public class ApiController : Controller { private readonly ILogger<ApiController> logger = null; private readonly IHttpContextAccessor httpContextAccessor = null; private readonly IServiceProvider serviceProvider; public ApiController(ILogger<ApiController> logger, IHttpContextAccessor httpContextAccessor, IServiceProvider serviceProvider) { this.logger = logger; this.httpContextAccessor = httpContextAccessor; this.serviceProvider = serviceProvider; } [HttpPost] public ActionResult GetReportDesignerModel(string reportUrl) { XtraReport report = null; var reportStorage = ReportShared.reportStorage; if (reportStorage.IsValidUrl(reportUrl)) { report = reportStorage.GetData(reportUrl); } if (report == null) { return NotFound(); } string modelJsonScript = new ReportDesignerClientSideModelGenerator(HttpContext.RequestServices) .GetJsonModelScript( report, null, "/DXXRD", "/DXXRDV", "/DXXQB" ); return Content(modelJsonScript, "application/json"); } }

                                  [BlulinkReportStorage.cs]

                                  [C#]
                                  public class BlulinkReportStorage : DevExpress.XtraReports.Web.Extensions.ReportStorageWebExtension { readonly string reportLocalDirectory; private readonly ILogger logger; private readonly string BaseUrlReportStorage = "Reports"; private readonly IHttpContextAccessor httpContextAccessor; public BlulinkReportStorage(ILogger<BlulinkReportStorage> logger, IHttpContextAccessor httpContextAccessor) { this.logger = logger; this.reportLocalDirectory = ReportShared.reportLocalDirectory; this.httpContextAccessor = httpContextAccessor; } public override bool CanSetData(string url) { return true; } public override bool IsValidUrl(string url) { if (string.IsNullOrEmpty(url)) { logger.LogDebug("Report url can't be empty"); return false; } return true; } public override byte[] GetData(string url) { HttpResponseMessage response = null; try { byte[] responseData = null; using (var httpClient = new HttpClient()) { var access_token = httpContextAccessor.HttpContext.GetTokenAsync("access_token").Result; httpClient.SetBearerToken(access_token); response = httpClient.GetAsync(url).Result; //url omitted if (response.IsSuccessStatusCode) { responseData = response.Content.ReadAsByteArrayAsync().Result; if (responseData.Length > 0) { return responseData; } } else { logger.LogDebug("GetReportFromUrl: Report " + reportUrl + " not found"); } } } catch (Exception ex) { logger.LogError(ex.ToString()); } finally { if (response != null) response.Dispose(); } return null; } public override Dictionary<string, string> GetUrls() { string company = Convert.ToString(httpContextAccessor.HttpContext.Request.Headers["BlulinkCompanyID"]); if (company == null) { logger.LogError("GetUrls(): Critical Error, no company detected"); return new Dictionary<string, string>(); } HttpResponseMessage response = null; try { string responseData = null; using (var httpClient = new HttpClient()) { var access_token = httpContextAccessor.HttpContext.GetTokenAsync("access_token").Result; httpClient.SetBearerToken(access_token); response = httpClient.GetAsync(url).Result; //url omitted if (response.IsSuccessStatusCode) { responseData = response.Content.ReadAsStringAsync().Result; if (responseData.Length > 0) { return JsonConvert.DeserializeObject<string[]>(responseData).Select(r => new { Id = r.Split('|')[2], Url = r }).ToDictionary(r => r.Url, r => r.Id); } } } } catch (Exception ex) { logger.LogError(ex.ToString()); } finally { if (response != null) response.Dispose(); } return new Dictionary<string, string>(); } public override void SetData(XtraReport report, string url) { //... HttpResponseMessage response = null; try { using (var httpClient = new HttpClient()) { var access_token = httpContextAccessor.HttpContext.GetTokenAsync("access_token").Result; httpClient.SetBearerToken(access_token); httpClient.DefaultRequestHeaders.Accept.Clear(); httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); Byte[] bytes; using (var memoryStream = new MemoryStream()) { report.SaveLayoutToXml(memoryStream); bytes = memoryStream.ToArray(); } StringContent json = new StringContent(JsonConvert.SerializeObject(bytes), Encoding.UTF8, "application/json"); response = httpClient.PutAsync(apiUrl, json).Result; //apiUrl omitted if (!response.IsSuccessStatusCode) { logger.LogError("SetData: Save Report Error response from Api. Report not saved"); throw new FaultException(new FaultReason("SetData: Save Report Error response from Api.Report not saved"), new FaultCode("Server"), "SetData"); } } } catch { /**/ } finally { if (response != null) response.Dispose(); } } public override string SetNewData(XtraReport report, string defaultUrl) { SetData(report, defaultUrl); return defaultUrl; } }

                                  [WebViewerOperationLog.cs]

                                  [C#]
                                  public class WebViewerOperationLog : WebDocumentViewerOperationLogger { private readonly ILogger logger; private IServiceProvider serviceProvider; public WebViewerOperationLog(ILogger<WebViewerOperationLog> logger, IServiceProvider serviceProvider) : base() { this.logger = logger; this.serviceProvider = serviceProvider; } public override Action BuildStarting(string reportId, string reportUrl, XtraReport report, ReportBuildProperties buildProperties) { string language = null; if (buildProperties.Parameters["language"] != null) { // get language from language setted by user drop down in UI language = (string)buildProperties.Parameters["language"]; } if(language == null) { language = ReportShared.defaultLanguage; } var httpContextAccessor = serviceProvider.GetService<IHttpContextAccessor>(); var reportStorage = ReportShared.reportStorage; ReportLocalization.SetReportLanguage(reportStorage, report, null, language, true); //method for change labels text based on language requested by user //... return base.BuildStarting(reportId, report, buildProperties); } }

                                  [ReportConnectionJsonProvider.cs]

                                  [C#]
                                  public class ReportConnectionJsonProvider : IDataSourceWizardJsonConnectionStorage { private static readonly List<JsonDataConnection> connections = new List<JsonDataConnection>(); private readonly ILogger logger; private readonly IHttpContextAccessor httpContextAccessor; public bool CanSaveConnection => true; public ReportConnectionJsonProvider(IConfiguration configuration, ILogger logger, IHttpContextAccessor httpContextAccessor) { this.logger = logger; this.httpContextAccessor = httpContextAccessor; GetConnections(); } public IEnumerable GetConnections() { if (connections.Count <= 0) { var access_token = httpContextAccessor.HttpContext.GetTokenAsync("access_token").Result; List<ReportUriJsonSource> sources = new List<ReportUriJsonSource> { new ReportUriJsonSource() { Uri = new Uri(firstEndpointUrl) //firstEndpointUrl omitted }, new ReportUriJsonSource() { Uri = new Uri(secondEndpointUrl) // secondEndpointUrl omitted } }; List connectionNames = new List { "ConnectionName1", "ConnectionName2" }; int i = 0; foreach(var source in sources) { source.QueryParameters.Add(parameters[i]); source.HeaderParameters.Add(new HeaderParameter("Authorization", "bearer " + access_token)); var jsonDataConnection = new JsonDataConnection(source) { Name = connectionNames[i], StoreConnectionNameOnly = true, }; connections.Add(jsonDataConnection); i++; } } return connections; } public bool ContainsConnection(string connectionName) { if (!string.IsNullOrEmpty(connectionName) && connections.Count(c => c.Name == connectionName) > 0) { return true; } return false; } public void SaveConnection(string connectionName, JsonDataConnection connection, bool saveCredentials) { if (!string.IsNullOrEmpty(connectionName)) { connections.Add(connection); } } public JsonDataConnection GetJsonDataConnection(string name) { var connection = connections.FirstOrDefault(c => c.Name == name); if (connection != null) { var jsonSource = connection.GetJsonSource(); if(jsonSource != null && jsonSource is ReportUriJsonSource) { var access_token = httpContextAccessor.HttpContext.GetTokenAsync("access_token").Result; addAuthorizationHeaderParam((ReportUriJsonSource)jsonSource, access_token); } } return connection; } public static void addAuthorizationHeaderParam(ReportUriJsonSource uriJsonSource, string access_token) { var existAuthparam = uriJsonSource.HeaderParameters.Count(h => h.Name == "Authorization"); if (existAuthparam > 0) { // update access_token if auth parameter already exists var authParam = uriJsonSource.HeaderParameters.FirstOrDefault(h => h.Name == "Authorization"); authParam.Value = "bearer " + access_token; } else { uriJsonSource.HeaderParameters.Add(new HeaderParameter("Authorization", "bearer " + access_token)); } } }

                                  [ReportUriJsonSource.cs]

                                  [C#]
                                  public class ReportUriJsonSource : UriJsonSource { private string _jsonString = string.Empty; protected override JsonSourceBase Clone() { var clone = new ReportUriJsonSource() { Uri = Uri, RootElement = RootElement, _jsonString = _jsonString }; foreach(var param in QueryParameters) { clone.QueryParameters.Add(param); } foreach (var header in HeaderParameters) { clone.HeaderParameters.Add(header); } return clone; } public override string GetJsonString() { if (string.IsNullOrEmpty(_jsonString)){ // no new request to Api if json already obtained HttpResponseMessage response = null; using (var client = new HttpClient()) { var authorizationHeader = HeaderParameters.FirstOrDefault(h => h.Name == "Authorization"); // add the authorization header to the request if(authorizationHeader!=null) client.DefaultRequestHeaders.Add("Authorization", (string)authorizationHeader.Value); try { response = client.GetAsync(Uri).Result; if (response.IsSuccessStatusCode) { var responseData = response.Content.ReadAsStringAsync().Result; if (responseData.Length > 0) { _jsonString = responseData; } } } catch{/**/} finally { if(response!=null) response.Dispose(); } } } return _jsonString; } }

                                  [report-viewer.ts]

                                  [JavaScript]
                                  customizeMenuActions(event) { //... // take into account page refresh (also with F5) to release server allocated resources window.onbeforeunload = function (evt) { event.sender.Close(); } //... }
                                • Yaroslav (DevExpress Support) 10.18.2019

                                  Hi Claudio,
                                  Thank you for sharing the relevant code. Unfortunately, there is no immediate answer I can provide you with here. We need to research this issue in detail to check what goes wrong in the described application setup and how we can improve things. We'll reply in this thread once there is news to share, so please keep an eye on it in order not to miss any updates.
                                  In the meantime, to address the memory issue, I suggest that you adjust the default cache settings instead of disposing of the report manually when the page closes. By default, the cache is stored on the web server for 2 hours, but you can adjust this value using the CacheCleanerSettings class.

                                  Regards,
                                  Yaroslav

                                • Claudio Soli 10.28.2019

                                  Hi,

                                  Do you have any news?

                                  Thanks

                                • Yaroslav (DevExpress Support) 10.29.2019

                                  Hi Claudio,
                                  We are working on a possible solution that will change the way the caching mechanism works. The fix is complex which makes it difficult to provide any time estimates here. As soon as we have any news, you will be automatically notified, so please don't be concerned about missing anything.

                                  By the way, have you tried to adjust the cache settings manually instead of disposing of the report on the page unload event? Does it work for you as an immediate workaround?

                                  Regards,
                                  Yaroslav

                                • Claudio Soli 10.29.2019

                                  Hi Yaroslav,

                                  yes, I tried to adjust the cache settings manually but the situation is practically the same.

                                  Please, keep me updated.

                                  Thanks

                                • Claudio Soli 11.11.2019

                                  Hi Yaroslav,

                                  Can I ask you when you plan to release the hotfix 19.1.8?

                                  Thanks

                                • Yaroslav (DevExpress Support) 11.11.2019

                                  Hi Claudio,
                                  Once a hotfix (an intermediate build) is requested, It takes a few working days to prepare and publish it. We'll release a hotfix for version 19.1.7 as soon as it's possible. The official release v19.1.8 is scheduled to the end of this month.
                                  We're looking forward to your results once you've had an opportunity to test the new changes.

                                  Regards,
                                  Yaroslav