Неплохая идея использовать большую статическую переменную?

Я работаю с ASP.NET MVC 4, и я хочу загрузить большой объем данных и сделать его доступным во всех моих классах. Вот минималистский образец моего кода:

public class MyController : Controller
{
 public static List<myobject> myList = null;

 public ActionResult Index()
 {
 MyViewModel model = new MyViewModel();
 myList = GetAllData(User.IDentity.Name); // Fill my list with 2k rows
 model.List = myList;

 return View(model);
 }


 public JsonResult GetData(int i)
 {
 return Json(myList.Where(x => x.Data == i));
 }
</myobject>

}

Все работает с локальными, но у меня есть некоторые проблемы с несколькими пользователями, когда я щенка на сервере (авария).

Думаю, я ошибся. Я уверен, что у меня есть утечки памяти с тезисом статических данных.

Как я могу избежать этой проблемы? Должен ли я использовать синглтон?

4 ответа

Контроллеры являются апатридами, поэтому каждый вызов действия создает новый экземпляр контроллера, что приведет к поражению цели того, что вы пытаетесь достичь. Это сказало следующее в лучшей реализации создания экземпляра static, выполнив его в конструкторе:

public MyController()
{
 myList = GetAllData(); 
}

Тем не менее, я советую против этого, поскольку я думаю, что проблема является скорее недостатком в вашем дизайне или неправильным пониманием того, как состояние обрабатывается в контроллерах - они не имеют гражданства.

Изменение: добавление примера для комментария по адресу: Общее соглашение будет заключаться в следующем: 1. Удалите статическую информацию, это действительно не даст вам никакой выгоды.

Затем:

public ActionResult Index()
 {
 MyViewModel model = new MyViewModel();

 model.List = GetAllData(User.IDentity.Name);;

 return View(model);
 }


 public JsonResult GetData(int i)
 {
 var model = GetAllData(User.IDentity.Name).Where(x => x.Data == i).ToList();
 return Json(model);
 }

Вам не нужны статические, клиентские вызовы в Index и GetData никогда не будут выполняться в том же экземпляре контроллера, статический бесполезен в этом случае.


Я должен сказать "да", потому что это не так, как все работает. Каждый раз, когда вы вызываете контроллер, создается новый экземпляр, и вам нужно получить данные для каждого действия. Вы можете иметь свойство внутри своего контроллера и заполнить его в конструкторе, чтобы повторно использовать его во всех действиях, но это все равно будет касаться базы данных каждый раз, когда вы вызываете действие.

public class MyController : Controller
{ 
 private readonly IDataGetter _dataGetter;

 public MyController(IDataGetter dataGetter)
 {
 _dataGetter = dataGetter;
 }

 public ActionResult Index()
 {
 MyViewModel model = new MyViewModel();
 myList = _dataGetter.GetAllData(User.IDentity.Name); // Fill your list with 2k rows
 model.List = myList;

 return View(model);
 }
}

Я думаю, что вы находитесь за то, что вы не хотите ударять DB для каждого раза, когда вам нужны данные из GetAllData().

Что бы я сделал (предполагая, что данные не часто меняются и что вы хотите повторно использовать этот метод в разных контроллерах), создается BaseController и наследуется от этого контроллера вместо контроллера. Добавьте OutputCache в это действие контроллера, так что вам не нужно каждый раз ударять базу данных.

public class BaseController : Controller
{
 [OutputCache(Duration = 3600)] //cache 3600 sec
 public List<somedatamodel> GetAllData()
 {
 return _dataGetter.GetAllData(User.Identity.Name);
 }
}
</somedatamodel>

Затем во всех действиях контроллера выше, где вы хотите получить доступ к своим данным, вы можете сделать вызов этого базового метода. Это сохранит его в кэше, и вам не нужно получать его из базы данных каждый раз.

var allData = base.GetAllData();

Примечание. Перед тем, как попытаться заставить это работать, вы должны, вероятно, прочитать об инжекции зависимостей и инверсии управления.


Почему бы не использовать статический constuctor? Он будет заполняться только один раз, и он будет готов к тому, когда он понадобится.

public class MyController : Controller
{
 public static List<myobject> myList = null;
 static MyController()
 {
 myList = GetAllData(User.IDentity.Name); // Fill my list with 2k rows
 }

 public ActionResult Index()
 {
 MyViewModel model = new MyViewModel();
 model.List = myList;

 return View(model);
 }

 public JsonResult GetData(int i)
 {
 return Json(myList.Where(x => x.Data == i));
 }
}
</myobject>


Есть много недостатков использования статических переменных, и в вашем сценарии нет причин их использовать. Используйте переменную экземпляра и инициализируйте ее так (для всех действий контроллера):

private List<myobject> myList;

protected override void Initialize(RequestContext requestContext)
{
 myList = GetAllData();
}

public ActionResult Index()
{
 MyViewModel model = new MyViewModel();
 model.List = myList;
 return View(model);
}

public JsonResult GetData(int i)
{
 return Json(myList.Where(x => x.Data == i));
}
</myobject>

licensed under cc by-sa 3.0 with attribution.