0

I have a controller that should display several selects (dropdowns) with predefined values.

I display a list of Records, each Record can have a predefined Theme and correspond to a City from the list of predefined values.

In my controller I have

private IEnumerable<Record> records;
private static IEnumerable<Theme> themes;
private static IEnumerable<City> cities;

private async Task<bool> LoadThemes()
{
    themes = await repository.GetTableEntitiesAsync<Theme>(lang);
    return true;
}

private async Task<bool> LoadCities()
{
    themes = await repository.GetTableEntitiesAsync<City>(lang);
    return true;
}

and the action

public async Task<IActionResult> Index()
{
    // records = from DB, then
    await LoadThemes(); ViewData["themes"] = this.themes;
    await LoadCities(); ViewData["cities"] = this.cities;

    return View(records);
}

public async Task<IActionResult> Edit(string id)
{
    // record => from id, then
    await LoadThemes(); ViewData["themes"] = this.themes;
    await LoadCities(); ViewData["cities"] = this.cities;

    return View(record);
}

Since I can't do a async constructor, nor I am sure passing via Index view, how can I initialize my "static" collections only once?

3
  • are you loading cities or themes in the LoadCities() method ? i.e. cities = await... Commented Jul 21, 2017 at 17:36
  • I edited the OP to explain that point Commented Jul 21, 2017 at 17:37
  • 1
    Static variables in a controller are a poor substitute for implementing real caching. And returning a boolean from a method with the only value being returned being true doesn't make sense either. Commented Jul 21, 2017 at 17:38

1 Answer 1

2

You should not use static variable in that scenario. Instead, you just store them in local variables.

View

<form asp-controller="Index" asp-action="Sample" method="post">
    <select asp-for="Cities" asp-items="@Model.Cities"></select>
    <select asp-for="ThemeId" asp-items="@Model.Themes"></select>
    <button type="submit">Submit</button>
</form>

ViewModel

public class RecordViewModel
{
    public string Id { get; set; }
    public string ThemeId { get; set; }
    public string CityId { get; set; }
    public IList<SelectListItem> Themes { get; set; }            
    public IList<SelectListItem> Cities { get; set; }

    public RecordViewModel()
    {
        Themes = new List<SelectListItem>();
        Cities = new List<SelectListItem>();
    }
}

Controller

public async Task<IActionResult> Index()
{
    var lang = "???";
    var model = new RecordViewModel
    {
        Themes = (await repository.GetTableEntitiesAsync<Theme>(lang))
            .Select(x => new SelectListItem {Value = x.Id,Text = x.Text}),
        Cities = (await repository.GetTableEntitiesAsync<City>(lang))
            .Select(x => new SelectListItem { Value = x.Id, Text = x.Text })
    };
    return View(model);
}

public async Task<IActionResult> Edit(string id)
{
    var lang = "???";
    var model = new RecordViewModel
    {
        Id = id,
        Themes = (await repository.GetTableEntitiesAsync<Theme>(lang))
            .Select(x => new SelectListItem { Value = x.Id, Text = x.Text }),
        Cities = (await repository.GetTableEntitiesAsync<City>(lang))
            .Select(x => new SelectListItem { Value = x.Id, Text = x.Text })
    };
    return View(model);
}

Other Thoughts

If you do not want to create two views - one for create and one for edit, you might want to consider creating a partial view _CreateOrUpdate.cshtml,and share it between them like this. Here are corresponding Create and Edit methods.

If you do not want to query database everytime, you might want to consider using MemoryCache like this.

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

5 Comments

ok, but the list of themes and cities don't change. is the same list of const values. Is it really necessary to load it each time in each view? I mean, could I load it once again in the controller's constructor and use it for all the views?
It is not a good practice to use static variable to cache data in that scenario. Besides, we rarely use static/singleton in web application. Instead, you should consider using MemoryCache.
We should not load data inside constructor not to mention constructor cannot be async. Otherwise, we will be query data everytime web hid that controller, although some action methods doesn't require them.
Perhaps I should take a look on the MemoryCache solution then... :)
Yes, here is the sample code using MemoryCache.

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.