4

What would be the best approach to maintain the dropdown lists for the whole application (like city, state etc) taking into account the SOLID principles and performance?

Right now am loading the list values into a static property and using the same like

public int DestCountry { get; set; }

private string _CountryText;
public string CountryText
{
    get
    {
        if (this.DestCountry > 0)
        {
            _CountryText = Lists.CountryList.Find(x => x.Value == Convert.ToString(this.DestCountry)).Text;
        }
        return _CountryText;
    }
}

But I am not sure whether this is the best approach possible. Could you please suggest.

3
  • Is this WebForm, WinForms, MVC, WPF, etc?
    – Graham
    Oct 8 '15 at 14:18
  • This is asp.net mvc
    – gvk
    Oct 8 '15 at 14:25
  • Why Value a string is DestCountry is an int. If Value is unique then use a Dictionary. Or not just have a class with County Id and Name.
    – paparazzo
    Dec 29 '16 at 15:03
2

This depends on some different factors:

  • first, who is responsible for maintaining them (the developer of the application, the user, some power users, an admin)?
  • is the list fixed for one version of the application, or is there a requirement to change those values without delivering a new version?
  • are those really fixed texts in one language, or do you expect them to be localized?
  • is the list of values only needed in one form/dialog/class, or will the list be needed in different places in the application?
  • if it is needed in different places, is it needed always in exactly the same way, or will it be sometimes needed in modified ways? For example, does it have to be extended, depending on the context?
  • if the chosen dropdown value has to be stored somewhere (for example, in a database), how will it be stored? As a fixed text? As an index? Where will the mapping index-to-text take place?

If you know the answer to those questions, I am sure you can work out by yourself where the best place is for your specific case. It may be either a hardcoded list in the form, a list in a reusable or extentable class, it maybe stored in a resource file, in a configuration file or in a database. Just avoid to store the same information in two different places.

2
  • The list, in this case country, has been used across multiple forms and it is being retrieved from a DB. If the above has not been declared as static, a call is being made to the DB whenever an object is created and this slows down the application considerably. This is why it was changed to static. My concern though is, if I add another row to the DB, it will not get reflected if the property is static.
    – gvk
    Sep 9 '15 at 4:24
  • 3
    @Vijayakumar: if that is what you really want to know, why don't you add this information to the question? But to give you an answer in short: you will either have to optimize your database query to get the country list faster, or you need to create a simple caching mechanism for the data. The gory details of that caching (for example, when to invalidate the cache) depend on your application and its requirements. This has nothing to do with SOLID.
    – Doc Brown
    Sep 9 '15 at 5:29
2

I would start with a data access interface which provides all the data your app needs. Here's a simple version with just the method in question to provide the allowable counties:

public interface IDataAccessProvider
{
    Country[] GetCountries();
}

public class Country 
{
    public string Id { get; set; }
    public string Name { get; set; }
}

And here's the first implementation of that interface:

public class DataAccessProvider : IDataAccessProvider
{
   // gets them from dbase, file, xml, blah blah blah
   // doesn't matter, just some resource that isn't hard coded
   return new List<County>() { ... };
}

Now, here's a static helper class to get things in and out of your Application Cache. Application Cache is a great way to store data in an app to save on network/database/fileIO etc, without having to resort to statics and such.

public static class CacheHelper
{
    public static void Insert<T>(string cacheKey, T objToCache, double hoursBeforeExpiration)
    {
        if (objToCache != null && typeof(T).IsValueType && Nullable.GetUnderlyingType(typeof(T)) == null)
            throw new Exception(string.Format("Dont add non-nullable stuff to the cache. Type: {0} KeyName: {1}", typeof(T), cacheKey));

        var expire = DateTime.Now.AddHours(hoursBeforeExpiration);
        HttpContext.Current.Cache.Insert(cacheKey, objToCache, null, expire, Cache.NoSlidingExpiration);
    }

    public static T Get<T>(string cacheItemName)
    {
        try { return (T)HttpContext.Current.Cache[cacheItemName]; }
        catch { return default(T); }
    }

    public static T RetrieveThroughCache<T>(string keyName, Func<T> retrievalCall, double hoursBeforeExpiration = 1)
    {
        var objFromCache = CacheHelper.Get<T>(keyName);
        if (objFromCache != null)
            return objFromCache;

        var objFromDataCall = retrievalCall();
        Insert(keyName, objFromDataCall, hoursBeforeExpiration);
        return objFromDataCall;
    }

    public static void Remove(string keyName)
    {
        HttpContext.Current.Cache.Remove(keyName);
    }
}

Next, we inherit from that DataAccessProvider class with a new class that knows how to use the above caching methods:

public class CachedDataAccessProvider : DataAccessProvider 
{
    public override Country[] GetCountries() 
    {
        return CacheHelper.RetrieveThroughCache("AppCountries", () => base.GetCountries());
    }
}

Now in your MVC ViewModels, you get an instance of the dataprovider interface from somewhere lower (base ViewModel constructor, DI from controller, etc etc) and you can just call the dataprovider's GetCountries() method without worrying if its in cache or not. The first call will get it fresh from the database, and subsequent hits throughout the day (the default in my static class is 24 hours in the cache) will just grab it straight from Cache. You can convert the County[] values into SelectListItems to power the dropdowns.

public class MyWhateverViewModel
{
    public string SelectedCountryId { get; set; }

    public IEnumerable<SelectListItem> GetCountryChoices() 
    {
        var dataProvider = GetIDataProviderInstance(); // or pass as param in constructor, etc
        return from country in dataProvider.GetCountries()
               select new SelectListItem {
                Text = country.Name,
                Value = country.Id,
                Selected = country.Id == SelectedCountryId 
               };
    }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.