clement
clement

Reputation: 4266

DropDownListFor is changing SelectedItem I've put on Cache

I am using cache on SelectListItems in my asp.net MVC app to store SelectListItems I'm using on lots of pages. The issue is that when I'm using it trough DropDownListFor, if I provide a selected value to this DropDownListFor, the SelectListItems looks to be changed... And I want to keep th SelectListItems in cache without "selected" property!

Here is the cache:

public IEnumerable<SelectListItem> GetAllPersonnelCached()
{
CacheHelper.SaveToCache("mykey", valueToCache, 240); //HttpContext.Current.Cache.Add
CacheHelper.GetFromCache<IEnumerable<SelectListItem>>("mykey"); //HttpContext.Current.Cache["mykey"]
}

This is the properties of the model I'm using

        public int? personnelSelected{ get; set; }
        public IEnumerable<SelectListItem> personnelList{ get; set; }

And How I fill it:

responsibleSelected = 100;
personnelList = GetAllPersonnelCached();

And here is how I am using the data on HTML part

@Html.DropDownListFor(x => x.personnelSelected, Model.personnelList, "PlaceHolder", new { data_placeholder = " " })

When I am running this code for a webpage, it works well. BUT then, when I call the GetAllPersonnelCached, it gives me all item as expected but the ListItem that has id 100 is "selecteditem". WHY? The fact that I'm using DropDownListFor makes changes on the List (referenced by the cache property in memory)? If yes, how to prevent this? Make the select list item readonly?

Thanks to all

Upvotes: 0

Views: 521

Answers (1)

pfx
pfx

Reputation: 23274

The source code of the DropDownListFor shows that this extension method internally sets the Selected property.

Because a SelectListItem is a reference type, this change occurs on the corresponding item in the cache.

One way to prevent this is to return new SelectListItem objects from the GetAllPersonnelCached method, instead of the original cached ones.

public IEnumerable<SelectListItem> GetAllPersonnelCached()
{
    CacheHelper.SaveToCache("mykey", valueToCache, 240); 
    var cachedItems = CacheHelper.GetFromCache<IEnumerable<SelectListItem>>("mykey");

    return cachedItems.Select(o => new SelectListItem(o.Text, o.Value);
}  

You might consider not to cache the SelectListItem instances, but the personnel-data objects instead which you transform to SelectListItem instances on retrieval.

// Assume your PersonnelData looks like below.    
class PersonnelData
{
    int Id { get; set; }
    string Name { get; set; }
}

public IEnumerable<SelectListItem> GetAllPersonnelCached()
{
    // valueToCache is a list of PersonnelData objects.
    CacheHelper.SaveToCache("mykey", valueToCache, 240);
    var cachedPersonnelData = CacheHelper.GetFromCache<IEnumerable<PersonnelData>>("mykey");

    return cachedPersonnelData.Select(o => new SelectListItem(o.Name, o.Id.ToString());
}

Upvotes: 2

Related Questions