NOTE: Apart from
(and even then it's questionable, I'm Scottish). These are machine translated in languages I don't read. If they're terrible please contact me.
You can see how this translation was done in this article.
Friday, 16 August 2024
//Less than a minute
Sie finden alle Quellcode für die Blog-Beiträge auf GitHub
Teile 1 und 2 der Serie über das Hinzufügen von Entity Framework zu einem.NET Core-Projekt.
Teil 1 kann gefunden werden Hierher.
Teil 2 kann gefunden werden Hierher.
In den vorherigen Teilen haben wir die Datenbank und den Kontext für unsere Blog-Posts eingerichtet und die Dienste hinzugefügt, um mit der Datenbank zu interagieren. In diesem Beitrag werden wir detailliert darlegen, wie diese Dienste jetzt mit den vorhandenen Controllern und Ansichten funktionieren.
Out Controller für Blogs sind wirklich ziemlich einfach; im Einklang mit der Vermeidung der 'Fat Controller' Antimuster (ein Muster, das wir in den frühen ASP.NET MVC Tage ideintified).
I MVC-Frameworks eine gute Praxis ist, so wenig wie möglich in Ihren Controller-Methoden zu tun. Dies liegt daran, dass der Controller für die Bearbeitung der Anfrage und die Rücksendung einer Antwort verantwortlich ist. Sie sollte nicht für die Geschäftslogik der Anwendung verantwortlich sein. Das ist die Verantwortung des Modells.
Die 'Fat Controller' Antimuster ist, wo der Controller zu viel tut. Dies kann zu einer Reihe von Problemen führen, darunter:
Der Blog-Controller ist relativ einfach. Es hat 4 Hauptaktionen (und eine "Kompat-Aktion" für die alten Blog-Links). Diese sind:
Task<IActionResult> Index(int page = 1, int pageSize = 5)
Task<IActionResult> Show(string slug, string language = BaseService.EnglishLanguage)
Task<IActionResult> Category(string category, int page = 1, int pageSize = 5)
Task<IActionResult> Language(string slug, string language)
IActionResult Compat(string slug, string language)
In der Folge nennen diese Aktionen die IBlogService
um die Daten zu erhalten, die sie benötigen. Das IBlogService
ist detailliert in der vorheriger Beitrag.
Im Gegenzug sind diese Aktionen wie folgt:
page
und pageSize
als Parameter. Das ist für die Pagination. der Ergebnisse.slug
der Stelle und der language
als Parameter. THIS ist die Methode, die Sie derzeit verwenden, um diesen Blog-Post zu lesen.category
, page
und pageSize
als Parameter.slug
und language
als Parameter.slug
und language
als Parameter.Wie in einem früherer Posten wir implementieren OutputCache
und ResponseCahce
um die Ergebnisse der Blog-Posts zu verbergen. Dies verbessert die Benutzererfahrung und reduziert die Belastung auf dem Server.
Diese werden mit den entsprechenden Aktionsdekoratoren durchgeführt, die die für die Aktion verwendeten Parameter (sowie hx-request
für HTMX-Anfragen). Für Examen mit Index
wir spezifizieren diese:
[ResponseCache(Duration = 300, VaryByHeader = "hx-request", VaryByQueryKeys = new[] {nameof(page), nameof(pageSize)}, Location = ResponseCacheLocation.Any)]
[OutputCache(Duration = 3600, VaryByHeaderNames = new[] {"hx-request"} ,VaryByQueryKeys = new[] { nameof(page), nameof(pageSize)})]
Die Ansichten für den Blog sind relativ einfach. Sie sind meist nur eine Liste von Blog-Posts, mit ein paar Details für jeden Beitrag. Die Ansichten sind in der Views/Blog
Ordner. Die wichtigsten Ansichten sind:
_PostPartial.cshtml
Dies ist die teilweise Ansicht für einen einzigen Blog-Post. Es wird in unserem Post.cshtml
................................................................................................................................
@model Mostlylucid.Models.Blog.BlogPostViewModel
@{
Layout = "_Layout";
}
<partial name="_PostPartial" model="Model"/>
_BlogSummaryList.cshtml
Dies ist die teilweise Ansicht für eine Liste von Blog-Posts. Es wird in unserem Index.cshtml
sowohl auf der Homepage als auch auf der Homepage.
@model Mostlylucid.Models.Blog.PostListViewModel
<div class="pt-2" id="content">
@if (Model.TotalItems > Model.PageSize)
{
<pager
x-ref="pager"
link-url="@Model.LinkUrl"
hx-boost="true"
hx-push-url="true"
hx-target="#content"
hx-swap="show:none"
page="@Model.Page"
page-size="@Model.PageSize"
total-items="@Model.TotalItems"
class="w-full"></pager>
}
@if(ViewBag.Categories != null)
{
<div class="pb-3">
<h4 class="font-body text-lg text-primary dark:text-white">Categories</h4>
<div class="flex flex-wrap gap-2 pt-2">
@foreach (var category in ViewBag.Categories)
{
<a hx-controller="Blog" hx-action="Category" hx-push-url="true" hx-get hx-target="#contentcontainer" hx-route-category="@category" href>
<span class="inline-block rounded-full dark bg-blue-dark px-2 py-1 font-body text-sm text-white outline-1 outline outline-green-dark dark:outline-white">@category</span>
</a>
}
</div>
</div>
}
@foreach (var post in Model.Posts)
{
<partial name="_ListPost" model="post"/>
}
</div>
Dabei wird die _ListPost
Teilansicht, um die einzelnen Blog-Posts zusammen mit der Hilfe für das Paging-Tag was uns erlaubt, die Blog-Beiträge zu blättern.
_ListPost.cshtml
Das _Listpost Teilansicht wird verwendet, um die einzelnen Blog-Posts in der Liste anzuzeigen. Es wird innerhalb der _BlogSummaryList
................................................................................................................................
@model Mostlylucid.Models.Blog.PostListModel
<div class="border-b border-grey-lighter pb-8 mb-8">
<a asp-controller="Blog" asp-action="Show" hx-boost="true" hx-swap="show:window:top" hx-target="#contentcontainer" asp-route-slug="@Model.Slug"
class="block font-body text-lg font-semibold transition-colors hover:text-green text-blue-dark dark:text-white dark:hover:text-secondary">@Model.Title</a>
<div class="flex space-x-2 items-center py-4">
@foreach (var category in Model.Categories)
{
<a hx-controller="Blog" hx-action="Category" class="rounded-full bg-blue-dark font-body text-sm text-white px-2 py-1 outline outline-1 outline-white" hx-push-url="true" hx-get hx-target="#contentcontainer" hx-route-category="@category" href>@category
</a>
}
@{ var languageModel = (Model.Slug, Model.Languages, Model.Language); }
<partial name="_LanguageList" model="languageModel"/>
</div>
<div class="block font-body text-black dark:text-white">@Model.Summary</div>
<div class="flex items-center pt-4">
<p class="pr-2 font-body font-light text-primary light:text-black dark:text-white">
@Model.PublishedDate.ToString("f")
</p>
<span class="font-body text-grey dark:text-white">//</span>
<p class="pl-2 font-body font-light text-primary light:text-black dark:text-white">
@Model.ReadingTime
</p>
</div>
</div>
Wie Sie hier sehen, haben wir einen Link zu den einzelnen Blog-Post, die Kategorien für den Beitrag, die Sprachen, in denen der Beitrag verfügbar ist, die Zusammenfassung des Beitrags, das veröffentlichte Datum und die Lesezeit.
Wir haben auch HTMX-Link-Tags für die Kategorien und die Sprachen, damit wir die lokalisierten Beiträge und die Beiträge für eine bestimmte Kategorie anzeigen können.
Wir haben hier zwei Möglichkeiten HTMX zu verwenden, eine, die die volle URL und eine gibt, die nur 'HTML' ist (d.h.. keine URL). Denn wir wollen die volle URL für die Kategorien und Sprachen verwenden, aber wir brauchen nicht die volle URL für den einzelnen Blog-Post.
<a asp-controller="Blog" asp-action="Show" hx-boost="true" hx-swap="show:window:top" hx-target="#contentcontainer" asp-route-slug="@Model.Slug"
Dieser Ansatz bevölkert eine vollständige URL für den einzelnen Blog-Post und nutzt hx-boost
um die Anfrage nach HTMX zu 'treiben' (dies setzt die hx-request
header zu true
).
<a hx-controller="Blog" hx-action="Category" class="rounded-full bg-blue-dark font-body text-sm text-white px-2 py-1 outline outline-1 outline-white" hx-push-url="true" hx-get hx-target="#contentcontainer" hx-route-category="@category" href>@category
</a>
Alternativ verwendet dieser Ansatz die HTMX-Tags, um die Kategorien für die Blog-Beiträge zu erhalten. Dabei wird die hx-controller
, hx-action
, hx-push-url
, hx-get
, hx-target
und hx-route-category
Tags, um die Kategorien für die Blog-Beiträge zu erhalten, während hx-push-url
ist eingestellt auf true
um die URL in den Browserverlauf zu schieben.
Es wird auch in unserem Index
Aktionsmethode für die HTMX-Anfragen.
public async Task<IActionResult> Index(int page = 1, int pageSize = 5)
{
var posts =await blogService.GetPagedPosts(page, pageSize);
if(Request.IsHtmx())
{
return PartialView("_BlogSummaryList", posts);
}
posts.LinkUrl = Url.Action("Index", "Blog");
return View("Index", posts);
}
Wo es uns ermöglicht, entweder die volle Ansicht oder nur die partielle Ansicht für HTMX-Anfragen zurückzugeben, was eine 'SPA'-ähnliche Erfahrung gibt.
In der HomeController
wir beziehen uns auch auf diese Blog-Dienste, um die neuesten Blog-Beiträge für die Homepage zu erhalten. Dies geschieht in der Index
Aktionsmethode.
public async Task<IActionResult> Index(int page = 1,int pageSize = 5)
{
var authenticateResult = GetUserInfo();
var posts =await blogService.GetPagedPosts(page, pageSize);
posts.LinkUrl= Url.Action("Index", "Home");
if (Request.IsHtmx())
{
return PartialView("_BlogSummaryList", posts);
}
var indexPageViewModel = new IndexPageViewModel
{
Posts = posts, Authenticated = authenticateResult.LoggedIn, Name = authenticateResult.Name,
AvatarUrl = authenticateResult.AvatarUrl
};
return View(indexPageViewModel);
}
Wie Sie hier sehen werden, benutzen wir die IBlogService
um die neuesten Blog-Posts für die Homepage zu erhalten. Wir verwenden auch die GetUserInfo
Methode, um die Benutzerinformationen für die Homepage zu erhalten.
Auch dies hat eine HTMX-Anforderung, die Teilansicht für die Blog-Posts zurückzugeben, damit wir die Blog-Posts in die Homepage einbinden können.
In unserem nächsten Teil werden wir in qualvolle Details gehen, wie wir die IMarkdownBlogService
um die Datenbank mit den Blog-Posts aus den Markdown-Dateien zu bevölkern. Dies ist ein Schlüsselteil der Anwendung, da es uns erlaubt, die Markdown-Dateien zu verwenden, um die Datenbank mit den Blog-Posts zu bevölkern.