Я только разбираюсь в ASP.MVC и может быть задаю глупые вопросы.
В данном случае вопросы будут не "как сделать", а "почему так происходит".
Делаю проект, суть которого заключается в том, что он обходит сайт, собирает ссылки на его страницы и измеряет время отклика. Потом, собранную информацию выводит в табличном виде (пока).
Проект состоит из двух страниц. На первой - в соответствующем инпуте водится поле и по нажатию кнопки идет переход на другой контроллер (ToolController), который производит замеры и выводит результаты.
Код метода первого контроллера (HomeController):
public ActionResult Submit(string Url)
{
if (CheckUrl(Url))
{
ViewBag.Error = "";
return RedirectToAction("Index", "Tool", new { Url });
}
else
{
ViewBag.Error = "Некорректный адрес!";
return RedirectToAction("Index");
}
}
Валидацию пока можно не смотреть, это буду отдельно разбираться.
Представление (фрагмент):
@using (Html.BeginForm("Submit", "Home", FormMethod.Post))
{
}
Во ToolController есть поле private поле класса VMManager, методы которого реализуют бизнес-логику. В классе VMManager есть поле вью-модели (VM), потому что все дальнейшие действия будут крутиться вокруг один раз построенной VM (сохранение в БД - пока не реализовано).
Представление выводит таблицу, состоящую из ссылок на страницы сайта (Ajax.ActionLink), по нажатию на которые должно подгружаться partialView с графическим представлением информации.
До графического представления мне пока далеко, пока разобраться бы что в табличном происходит.
Фрагмент контроллера (ToolController):
private static VMManager manager = new VMManager();
public ToolController()
{
// manager = new VMManager();
}
// GET: Tool
public ActionResult Index(string url)
{
// manager = new VMManager();
manager.VM = (SiteVM)manager.GetVM(url);
return View(manager.VM);
}
public ActionResult ShowPageResultInChart(string pattern)
{
if (pattern == "test") return null;
Thread.Sleep(1000);
return PartialView("ShowPageResultInChart");
}
Фрагмент представления:
@Html.Action("ShowPageResultInChart", new { pattern ="test" })
@foreach (var item in Model.PageResults)
{
@Ajax.ActionLink(item.PageAddress, "ShowPageResultInChart", new {pattern= item.PageAddress },
new AjaxOptions
{
UpdateTargetId = "ChartData",
LoadingElementId = "LoadingIndicator"
}
)
|
@item.MinTime |
@item.AverageTime |
@item.MaxTime |
}
В частичном представлении пока смотреть нечего: строчка "Сработал Ajax"
Теперь вопросы:
Если верить отладчику, то при первичной загрузке основной страницы запускается метод ShowPageResultInChart. Хотя он предполагался к запуску только при нажатии на Ajax.ActionLink. Почему, что я сделал не так? От этой беды я избавился условием в методе ShowPageResultInChart, но почему он срабатывает? Я правильно понимаю, что это противоречит смыслу Ajax?
Разместить его ниже таблицы я не могу по условиям задания. Причем у меня сложилось впечатление, что запускается он как минимум 2 раза, но может я ошибаюсь.
Судя по всему, у меня запускается несколько экземпляров второго контроллера. Это я понял по тому, что VM в процессе обнуляется и при нажатии на Ajax.ActionLink на входе метода ShowPageResultInChart VM = null. Такое впечатление, что первый экземпляр создается при выводе таблицы, второй - при нажатии на Ajax.ActionLink. От этой беды я избавился сделав поле менеджера статическим, но почему так происходит?
Ответ
1) ShowPageResultInChart вы вызываете не только с помощью @Ajax.ActionLink, а также с помощью @Html.Action, отсюда он и выполняется при загрузке страницы.
@Html.Action("ShowPageResultInChart", new { pattern ="test" })
2) При каждом запросе создается отдельный экземпляр класса Controller через ControllerFactory
Обратите внимание, что Html.Action Html Helper создаст другой экземпляр контроллера.
В общем, ControllerActivator.Create вызывается (для каждого запроса), чтобы создать контроллер (который создает новый контроллера или через DependencyResolver или через Activator, если не Resolver не был установлен):
public IController Create(RequestContext requestContext, Type controllerType) {
try {
return (IController) (_resolverThunk().GetService(controllerType) ? ? Activator.CreateInstance(controllerType));
}