Обычно меня путает «почему» (а не «как») использования определенных типов возврата C# в Razor Pages. В некоторых случаях я понимаю «почему», но не понимаю, когда мне следует использовать одно вместо другого. Моя первоначальная путаница началась с асинхронных типов, но теперь я это понимаю. Это также было связано с типом void
, который я немного лучше понимаю, но все еще не понимаю.
Я изучаю несколько различных фрагментов кода, чтобы лучше понять, и могу использовать некоторые полезные объяснения - Документы и другие источники на самом деле не приносят мне его домой.
Некоторые из методов исходят от некоторых DI и не обязательно имеют отношение (я думаю, насколько я знаю, это причина использования одного возвращаемого типа вместо другого, и в этом случае я ценю объяснение). Вот несколько различных фрагментов, которые, как я надеюсь, сообщество поможет мне лучше понять, «почему» использовать один тип возвращаемого значения вместо другого (или следует ли мне просто придерживаться одного типа, поскольку это не повлияет на результат что делается).
Первый:
public void OnGet()
{
ServicesContainer = _helper
.GetRecentContentItemsByContentTypeAsync("Services")
.GetAwaiter()
.GetResult()
.SingleOrDefault();
ServicesList = _helper
.GetRecentContentItemsByContentTypeAsync("Service")
.GetAwaiter()
.GetResult()
.OrderByDescending(c => c.CreatedUtc)
.Take(3);
}
Сам код у меня нет проблем с пониманием - он извлекает контейнер и элементы списка внутри. Моя страница Razor просто отображает элементы списка с помощью повторяющегося цикла foreach
. Я также понимаю, что код получает эту информацию, и это самый простой пример. Так что, в моем понимании, никаких проблем.
Второй:
public async Task OnGetAsync(string projectTitle)
{
Project = _helper
.QueryContentItemsAsync(q => q
.Where(c => c.DisplayText == projectTitle))
.GetAwaiter()
.GetResult()
.SingleOrDefault();
var relatedProjects =
(IEnumerable<string>)Project?
.Content
.Project.RelatedProjects?
.ContentItemIds?.ToObject<string[]>();
if (relatedProjects?.Count() > 0)
{
RelatedProjects = await
_helper.GetContentItemsByIdAsync(relatedProjects);
}
}
Вышеупомянутое также извлекает «контейнер», который может иметь элементы (связанные проекты), но в этом случае он делает это немного иначе, поскольку может не быть ничего, что можно было бы перечислить, кроме самого проекта. Но почему он использует Task
вместо OnGet
?
В третьих:
public async Task<IActionResult> OnGet()
{
HeaderInfo = await _helper
.GetContentItemByAliasAsync("alias:fullwidth");
return Page();
}
Здесь это всего лишь единичный предмет. Но опять же, зачем использовать Task
и почему <IActionResult>
возвращает страницу, когда весь другой код не требует возврата страницы? И почему он не использует OnGetAsync
?
В этих элементах нет ничего особенного - все они хранятся на CMS (например, в них нет ничего динамичного). Первый - контейнер с элементами списка. Второй элемент с потенциально связанными элементами (если они существуют в CMS, а их нет). Третий - всего лишь один предмет.
И зачем на первом использовать void
, а не
Заранее благодарим за то, что поделились любопытством.
Каждый раз, когда к OnGet()
делается запрос, IIS должен дождаться возврата данных, прежде чем сможет обработать другие запросы. Сделав OnGet()
асинхронным, это позволяет IIS выполнять другие задачи, ожидая возврата ваших данных. Это уменьшает узкие места и заставляет IIS работать быстрее и эффективнее.
Всякий раз, когда метод помечен как async
, он должен возвращать объект Task
. Если вашему методу нечего возвращать, он все равно должен быть помечен как Task OnGetAsync()
. Если ваш метод действительно возвращает значение, вы можете указать тип возвращаемого значения в объекте Task
, как в Task<IActionResult> OnGetAsync()
.
Итак, что касается ваших методов, вот что происходит:
public void OnGet()
{
// Synchronous method that returns nothing
// IIS stops handling requests here until your method returns
}
public async Task OnGetAsync(string projectTitle)
{
// Asynchronous method that returns nothing.
// When your code reaches the await keyword,
// IIS resumes handling other tasks while awaiting
// for your method to return
}
public async Task<IActionResult> OnGet()
{
// Asynchronous method that returns an IActionResult value
// When your code reaches the await keyword,
// IIS resumes handling other tasks while awaiting
// for your method to return
}
@REMESQ Вы должны возвращать IActionResult или Task <IActionResult> только в том случае, если вам нужно вернуть какой-то ActionResult. В идеале вы должны точно указать тип, который вы хотите вернуть. Обычно вам не нужно возвращать IActionResult, если вы хотите показать страницу, подключенную к PageModel, где расположены эти методы. Вам нужно будет вернуть IActionResult, если вы хотите перенаправить, вернуть JSON, NotFoundResult и т. Д .: learnrazorpages.com/razor-pages/action-results
@MikeBrind "Только если" обычно основан на причине. В этом случае причиной может быть производительность? Или это только вопрос порядка? Или ...?
@LGSon Должен только как для иллюстрации ваших намерений. return Page()
неявно присутствует в обработчике страницы.
@MikeBrind Спасибо ... надеялся, что причина :)
public async Task<IActionResult> OnGet() { HeaderInfo = await _helper .GetContentItemByAliasAsync("alias:fullwidth"); return Page(); }
На самом деле вам не нужно ничего возвращать из этого метода. Вы могли бы так же легко написать
public async Task OnGet()
{
HeaderInfo = await _helper
.GetContentItemByAliasAsync("alias:fullwidth");
}
Когда вы вызываете метод Page()
, отображается текущая страница. Это происходит неявно в любом случае, если не указан другой тип возвращаемого значения.
Как правило, вы вызываете метод Page()
только как один из нескольких возможных возвращаемых типов, тогда как другие возвращаемые типы - это IActionResults. Самый распространенный пример - публикация формы:
public IActionResult Create()
{
if (ModelState.IsValid)
{
return RedirectToPage("Success"); // redirect as part of PRG
}
else
{
return Page(); // redisplay the page with validation errors
}
}
В этом случае вы должны объявить возвращаемый тип (вместо void или Task), потому что вы хотите использовать метод RedirectToPage, который возвращает RedirectToResult (тип IActionResult). Вы также должны указать подходящий тип возвращаемого значения в случае else
, отсюда и вызов return Page()
.
Спасибо за понимание. Полезно, так как у меня есть планы вернуть часть JSON на других страницах, а также иметь несколько страниц форм. Еще раз спасибо.
@remesq вы также можете использовать веб-API для возврата JSON learnrazorpages.com/web-api
Ясный и лаконичный. Спасибо. Последующие действия: мне не ясно, могу ли я просто продолжить и заставить весь мой код возвращать
IActionResult
, поскольку кажется, что оба набора кода просто получают информацию от CMS, пока я отображаю информацию на странице Razor. Это имеет значение? Другими словами, есть ли что-то особенное в первом или третьем фрагменте кода, что заставляет делать каждый из них таким же образом?