This is a migrated thread and some comments may be shown as answers.

How to Purge Cache

5 Answers 760 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Steve
Top achievements
Rank 1
Steve asked on 10 Dec 2013, 04:49 PM
<Cache provider="File">
      <Providers>
        <Provider name="File">
          <Parameters>
            <Parameter name="BasePath" value="C:\Temp\ReportingCache" />
          </Parameters>
        </Provider>
      </Providers>
    </Cache>

With the FileCache and FileCacheProvider how can you purge the file cache when the browser closes.

I'm attempting to purge reports from the cache when the browser is closed from a window.onbeforeunload event that triggers the purge with a fallback periodic trigger that delete any orphaned cache folders older then twice the SESSION TIMEOUT.

The {InstanceID}RenderingContext and {InstanceID}ProcessingReport exist in the System.Web.Caching.Cache and the WebForm.WebCacheManager adds an OnCacheItemRemovedCallback that calls Dispose which invokes a deletion of the rendering cache folder but does not pass the recursive as its secondary parameter.

When I manually remove the {InstanceId}RenderingContext and {InstanceId}ProcessingReport from Cache, the folders do not get automatically deleted.

I can manually delete the folders within my Purge trigger, but there is no correlation between the RenderID and the InstanceID and verifying the Folder CreationTimeUtc some times throws and Access Violation Error when from the ReportViewer under load when it attempts to Read {RenderId}/Page1.


Any suggestions would be greatly appreciated.




5 Answers, 1 is accepted

Sort by
0
Stef
Telerik team
answered on 13 Dec 2013, 02:23 PM
Hello Steve,

Try using Database Cache provider or create your custom provider, where you can implement the cleaning logic easier as you will not have issues with access to cache files if they are yet in use by the process.

Let us know if you need any further help.

Regards,
Stef
Telerik

New HTML5/JS REPORT VIEWER with MOBILE AND TOUCH SUPPORT available in Telerik Reporting Q3 2013! Get the new Reporting version from your account or download a trial.

0
Steve
Top achievements
Rank 1
answered on 13 Dec 2013, 02:32 PM
I got it figured out.  
The WebCacheManager uses HttpContext.Current.Cache and while utilizing HttpRuntime.Cache access the same cache data, removing items from HttpRuntime.Cache does not trigger the OnCacheRemoved event that was registered through the HttpContext.Current.Cache.


This is my final code which purges the cache when navigating away from the browser window and is fun to watch during load testing.

In DEBUG I purge the FileCache first so I can get an accurate account for FileMemory cleanup (merely testing).  But removing the cache and disposing the objects does trigger the cleanup of the file system through the FileCache object

/// <summary>
/// Purge cache for a given instance
/// </summary>
/// <param name="instanceID">Telerik Report Instance GUID</param>
/// <returns></returns>
internal static long PurgeTelerikSessionCache(string instanceId)
{
    long before = 0;
    long after = 0;
    object obj;
    IDisposable disposable;
    string reportKey = instanceId + "ProcessingReports";
    string renderKey = instanceId + "RenderingContext";
 
    var cache = HttpContext.Current.Cache;
    var session = HttpContext.Current.Session;
    var sessionInstances = (IList<string>)session["Telerik.Reporting.LiveInstances"];
    var sessionKeys = new List<string>();
    foreach (string key in session.Keys)
        sessionKeys.Add(key);
 
 
    #if DEBUG
    before = GC.GetTotalMemory(false);
    #endif 
     
    var renderContext = cache[renderKey] as Hashtable;
    var reports = cache[reportKey] as IList;
    if (reports != null)
    {
        foreach (var report in reports)
        {
            ((IDisposable)report).Dispose();
        }
    }
 
    if (renderContext != null)
    {
        foreach (object objKey in renderContext.Keys)
        {
            obj = renderContext[objKey];
            disposable = obj as IDisposable;
            if (disposable != null) disposable.Dispose();
        }
    }
     
    cache.Remove(reportKey);
    cache.Remove(renderKey);
 
     
    // kill viewstate items
    foreach (string key in sessionKeys.Where(x => x.StartsWith(instanceId)))
    {
        obj = session[key];
        disposable = obj as IDisposable;
        if (disposable != null) disposable.Dispose();
 
        session.Remove(key);
    }
         
    if (sessionInstances != null)
    {
        sessionInstances.Remove(instanceId);
        session["Telerik.Reporting.LiveInstances"] = sessionInstances;
    }
 
    // Kill the empty session
    if (sessionInstances == null || sessionInstances.Count == 0)
        session.Abandon();
 
 
    #if DEBUG
    after = GC.GetTotalMemory(true);
    #endif
     
    return before - after;
}
0
Mahdy
Top achievements
Rank 1
answered on 07 Sep 2014, 08:22 PM
I have same problem too. I need find out Instance ID of report viewer to clear it's keys from cache. But the problem is how can i get Instance ID of report viewer? I think Instance ID is a private property that I can't get it.
0
Mahdy
Top achievements
Rank 1
answered on 08 Sep 2014, 01:32 PM
I found a dirty solution. Before load a report in report viewer I removed some keys from cache. I used following code and it worked for me.

        protected void RemoveKeyFromCache(string key)
        {
            foreach (System.Collections.DictionaryEntry entry in HttpRuntime.Cache)
                if (entry.Key.ToString().IndexOf(key) >= 0)
                    HttpRuntime.Cache.Remove(entry.Key.ToString());
        }

        protected void ClearCache()
        {
            for (int i = 0; i < Session.Count; i++)
                RemoveKeyFromCache(Session.Keys[i].ToString());
        }

        protected void LoadReport()
        {
            ClearCache();

            //load report code here 

            ReportViewer.RefreshReport();
            ReportViewer.RefreshData();
        }
0
Steve
Top achievements
Rank 1
answered on 08 Sep 2014, 01:51 PM
The [instanceID] and [RenderID] are passed back to the Reporting IFrame as QueryParameters to load the rendered report.

var frame = document.getElementById("<%= ReportViewer.ClientID %>ReportFrame");
var url = frame.contentWindow.location.search;
var instanceId = url.match(/instanceID=(^&]*)/)[1];

I pass them both in an ajax call in a window.onbeforeunload event to purge
Tags
General Discussions
Asked by
Steve
Top achievements
Rank 1
Answers by
Stef
Telerik team
Steve
Top achievements
Rank 1
Mahdy
Top achievements
Rank 1
Share this question
or