1

I load a list of a database table via Linq in the page load of my site.

Now I must cache the list, because I will use them in a WebMethod again. (I can't load them new, because it can be changes in there).

How to cache a List<> and get it back in a WebMethod?

2
  • Are you going to be on a web farm? Commented Nov 27, 2009 at 11:59
  • Check out - en.wikipedia.org/wiki/Server_farm Basically, are you going to put your web site on more than one server? In which case the use of Session requires a bit more work... Commented Nov 27, 2009 at 19:42

6 Answers 6

4

I'd do this with the ASP.NET Cache API - here's how.

Imports System.Web

Public Class CacheManager

Private ListKey As String = "MyList"

Public Shared ReadOnly Property TypedList As List(Of Integer)

    Dim cachedObject As Object  
    Dim myList As List (Of Integer)  
    Dim userCacheKey As String = ListKey & HttpContext.Current.User.Identity.Name

    'First check to see if List is in the cache already
    cachedObject = HttpRuntime.Cache.Get(userCacheKey)

    If cachedObject Is Nothing Then
       'If List isn't in the cache already then get it...
       myList = Code to retrieve list members goes here
       ' ...and now we've got it put it in the cache
       HttpRuntime.Cache..Add(key:=userCacheKey, value:=myList, absoluteExpiration:=HttpRuntime.Cache.NoAbsoluteExpiration, slidingExpiration:=New TimeSpan(0,5,0), dependencies:=Nothing, onRemoveCallback:=Nothing, priority:=CacheItemPriority.Default)
    Else
        'List is already in the cache but everything comes out of the cache as System.Object so cast it to List (Of Integer)  
        myList = DirectCast(cachedObject, List (Of Integer))
    End If

    'Now we have List, return it to the caller
    Return myList

End Property

End Class

This gives us a class that will hold an instance of List<> per user that exists in memory for five minutes after the last time it was accessed - you can up this just by changing the length of the TimeSpan object in the slidingExpiration parameter when the List is added to the Cache.

Your usage in the page is then simply:

Public Sub Page_Load (arguments)

Dim myList As List(Of Integer)  
...
myList = CacheManager.TypedList
...
End Sub

<WebMethod()> Public Sub MyEventMethod(arguments)

Dim myList As List(Of Integer)
...
myList = CacheManager.TypedList
...

End Sub

It's not quite clear (to me) from your question whether users can change their individual List or they change the global list. If they change their individual list that's easy to cater for - change the TypedList property like this:

Imports System.Web

Public Class CacheManager

Private ListKey As String = "MyList"

Public Shared Property TypedList As List(Of Integer)
Get
    Dim cachedObject As Object  
    Dim myList As List (Of Integer)  
    Dim userCacheKey As String = ListKey & HttpContext.Current.User.Identity.Name

    'First check to see if List is in the cache already
    cachedObject = HttpRuntime.Cache.Get(userCacheKey)

    If cachedObject Is Nothing Then
       'If List isn't in the cache already then get it...
       myList = Code to retrieve list members goes here
       ' ...and now we've got it put it in the cache
       HttpRuntime.Cache.Add(key:=userCacheKey, value:=myList, absoluteExpiration:=HttpRuntime.Cache.NoAbsoluteExpiration, slidingExpiration:=New TimeSpan(0,5,0), dependencies:=Nothing, onRemoveCallback:=Nothing, priority:=CacheItemPriority.Default)
    Else
        'List is already in the cache but everything comes out of the cache as System.Object so cast it to List (Of Integer)  
        myList = DirectCast(cachedObject, List (Of Integer))
    End If

    'Now we have List, return it to the caller
    Return myList
End Get
Set (ByVal value As List(Of Integer))

    Dim userCacheKey As String = ListKey & HttpContext.Current.User.Identity.Name

    HttpRuntime.Cache.Insert(key:=userCacheKey, value:=value, absoluteExpiration:=HttpRuntime.Cache.NoAbsoluteExpiration, slidingExpiration:=New TimeSpan(0,5,0), dependencies:=Nothing, onRemoveCallback:=Nothing, priority:=CacheItemPriority.Default)

End Set
End Property

End Class

If any user making changes to the list changes it for everybody, then I'd look at using a CacheDependency.

Sign up to request clarification or add additional context in comments.

Comments

2

I would say the Session would be your best bet.

Example

Storing:

var list = new List<int>() { 1, 2, 3, 4, 5 };
Session["ListOfIntegers"] = list;

Retrieving:

var list = (List<int>)Session["ListOfIntegers"];

9 Comments

Wouldn't an application variable be better than session?
@adrianos, it depends on what the list is dependant of the application (i.e. a run once thing) or if it is Session dependant (per user). So this is really for Kovu to answer?
Yeah good point, I agree, though I'd have thought a simple list of tables would be global.
To answer: It is user specific, because each user can get his own first-page, depends on the time he joins.
Session is defintely the way to go then :)
|
1

I suppose that you want to cache (or rather persist) it separately for the user, as you mention that there can be changes.

Store the list in a Session variable, and enable session state for the web method using the [WebMethod(EnableSession:=True)] attribute.

Consider the amount of memory that you are using, though. Putting the list in a session variable will keep it in memory for a long time. (20 minutes is eons in the scope of a web application, where objects normally survive only a few milliseconds...)

2 Comments

Thats exectly my thoughts. Can I react when a user is closing the site and kill these session?
@Kovu: Not easily, and not reliably. You can use the unload event in the browser and contact the server when the user leaves, but then you have to keep track of whether the user actually leaves or just reloads the page. Also, it only works if the user is still connected.
0

You could make a property which checks if the session field contains data, if not load the data, otherwise return the field. Like so:

List<goof> data {
    get {
        List<goof> data = Session["data"] as List<goof>;
        if (data == null) Session["data"] = LINQstuff;

        return data;
    }
}

2 Comments

But my site is stateless, isn't it? So I can't have global member variables and save them over time, can I?
You're right, didn't understand the question properly. As James points out, you should indeed use the Session variable.
0

I suggest to use the System.Web.Caching.Cache class.

See http://msdn.microsoft.com/en-us/library/system.web.caching.cache.aspx

It doesn't depend on the user session but in your case I think it is better because you are inside a WebMethod.

Davide

Comments

0
[WebMethod(EnableSession = true)]
public void SetCache()
{
    LoginData userList = new LoginData
    {
        Status = "Success",
        LastLogin = DateTime.Now.ToString("yyyyMMdd-HHMMss"),
        UserName = "Some User"
    };
    HttpRuntime.Cache["loggedIn"] = userList;
}
public class LoginData
{
    public string Status { get; set; }
    public string UserName { get; set; }
    public string LastLogin { get; set; }
}

There is a big difference between a cached list and a session list and different roles they play.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.