This is a viewer only at the moment see the article on how this works.
To update the preview hit Ctrl-Alt-R (or ⌘-Alt-R on Mac) or Enter to refresh. The Save icon lets you save the markdown file to disk
This is a preview from the server running through my markdig pipeline
Pourquoi vous n’avez pas trouvé ce document sur Google (et comment je l’ai corrigé
Wednesday, 26 November 2025
I'je suis en train d’exploiter ce blog depuis un certain temps , écrivant des articles techniques détaillés sur ASP.NET CoreM SK3 Entity FrameworkMska4 HTMXMske5 et toutes sortes de M Ska6Net goodnessMka7 Pourtant, mes classements de recherche étaientM ska8 extrêmement basMSKA9 Après avoir finalement étudié pourquoiMskai10 j’ai découvert que Imska11 avait saboté mon propre SEO avec quelques erreurs de débutantsMsaka12 iciMaskan13 c’est ce qui était errant et comment je l’ai corrigéMsaa14
Le problème: Chaque page semblait identique à Google
Lorsque Google foule votre site, il regarde plusieurs signaux clés pour comprendre ce qui est de chaque pageM SK1 J’ai envoyé à Google les mêmes signaux pour chaque page unique.
The Smoking Gun: Meta Descriptions Statiques
Voici ce que mon _Layout.cshtml looked like:
<meta name="description" content="Scott Galloway is a lead developer and software engineer with a passion for building web applications.">
<meta property="og:description" content="Scott Galloway is a lead developer and software engineer with a passion for building web applications.">
Every. SingleM SK1 Page. La même descriptionMSC3 Mon article sur Services de base dans ASP.NET Core? La même description que ma page d’accueil. Mon plongée profonde dans Architecture du RAG? La même descriptionM SK1
Google voit des pages 200+ comportant des descriptions identiques et pense que "ce site a des problèmes de contenu dupliquéM SK2 ou |" ce site ne s’occupe pas de fournir des renseignements utiles' non plus de fournir de l’information utileMSC5 En tout état de causeMNK6 les classements souffrent
URL Canoniques manquantes
J’ai un blog multilingue avec des traductions. Le même contenu existe à:
/blog/my-article(anglais)/blog/my-article/fr(FrenchM SK1/blog/my-article/de(allemandM SK1
Sans les URL canoniques, Google pourrait considérer ces contenus comme dupliqués, diluant la valeur SEO à travers plusieurs URL au lieu de le regrouper sur la page principaleM SK2
Aucune donnée structurée
Google' les résultats de recherche peuvent montrer des fragments riches - renseignements sur l'auteur M SK2 dates de publication , préviews d'articles MSC4 Mais seulement si vous dites à Google au sujet de ces données en utilisant JSON-LD Données structurées. Je n’étais pas
Images sociales statiques
Chaque page partagée est la même og:image. Bien que cela n’ait pas d’incidence directe sur le classement de Google, ' il a une incidence sur les taux de cliques sur les articles qui sont partagés dans les médias sociaux, - ce qui affecte indirectement l’SEO par des signaux d’engagement.
Les solutions
1. Descriptions métadonnées dynamiques
Le premier remède consistait à rendre les descriptions dynamiques du support de layout avec un retour sensible:
@{
var currentUrl = $"https://{Context.Request.Host}{Context.Request.Path}";
var defaultDescription = "Scott Galloway is a lead developer and software engineer with a passion for building web applications.";
var pageDescription = ViewBag.Description as string ?? defaultDescription;
}
<!-- Canonical URL -->
<link rel="canonical" href="@currentUrl" />
<!-- Facebook Meta Tags -->
<meta property="og:url" content="@currentUrl">
<meta property="og:type" content="@(ViewBag.OgType ?? "website")">
<meta property="og:title" content="@ViewBag.Title">
<meta property="og:description" content="@pageDescription">
<meta property="og:site_name" content="mostlylucid" />
<!-- Twitter Meta Tags -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="@ViewBag.Title">
<meta name="twitter:description" content="@pageDescription">
<!-- Meta Description -->
<meta name="description" content="@pageDescription" />
<!-- Article metadata for blog posts -->
@if (ViewBag.PublishedDate != null)
{
<meta property="article:published_time" content="@(((DateTime)ViewBag.PublishedDate).ToString("yyyy-MM-ddTHH:mm:ssZ"))" />
<meta property="article:author" content="Scott Galloway" />
}
@if (ViewBag.Categories != null)
{
foreach (var category in ViewBag.Categories)
{
<meta property="article:tag" content="@category" />
}
}
Maintenant, le schéma se lit comme suit : ViewBag.Description si la valeur est établie, retournant à une valeur par défaut. L'URL canonique est automatiquement fixée à l'URL de la page courante .
2. Auto-Descriptions générées pour les articles de blog
Chaque post de blog génère maintenant sa description à partir des premiers caractères du contenu 155 Post.cshtml:
@using Mostlylucid.Shared.Helpers
@model Mostlylucid.Models.Blog.BlogPostViewModel
@{
Layout = "_Layout";
ViewBag.Title = $"{Model.Title} ({Model.Language.ConvertCodeToLanguage()})";
// Generate description from plain text content (first 155 chars, truncate at word boundary)
var plainText = Model.PlainTextContent ?? "";
var description = plainText.Length > 155
? plainText.Substring(0, plainText.LastIndexOf(' ', 155)) + "..."
: plainText;
description = description.Replace("\n", " ").Replace("\r", "").Trim();
ViewBag.Description = description;
// Set article metadata
ViewBag.OgType = "article";
ViewBag.PublishedDate = Model.PublishedDate;
ViewBag.Categories = Model.Categories;
// Build canonical URL (without language suffix for English)
var canonicalUrl = Model.Language == "en"
? $"https://{Context.Request.Host}/blog/{Model.Slug}"
: $"https://{Context.Request.Host}/blog/{Model.Slug}/{Model.Language}";
}
Les points clés ici:
- Retourner à la limite de mots - Nous trouvons le dernier espace avant les caractères 155 pour éviter de couper les mots en deux.
- Retirer les nouvelles lignes - Les descriptions métadonnées doivent être uniques-line
- Établissement
og:typeà "articleM SK1 - Dit aux plates-formes sociales qu’il s’agit d’un article - Passer les métadonnées de l'article - La date de publication et les catégories passent dans le schéma
3. JSONM SK1LD Données structurelles
C'est le plus grand pour les fragments riches. Ajouter un bloc de script JSON-LD à votre vue d'affichage des articles de blogM SK2
<!-- JSON-LD Structured Data for Blog Post -->
<script type="application/ld+json">
{
"@@context": "https://schema.org",
"@@type": "BlogPosting",
"headline": "@Model.Title",
"description": "@description",
"datePublished": "@Model.PublishedDate.ToString("yyyy-MM-ddTHH:mm:ssZ")",
@if (Model.UpdatedDate.HasValue)
{
@:"dateModified": "@Model.UpdatedDate.Value.ToString("yyyy-MM-ddTHH:mm:ssZ")",
}
"author": {
"@@type": "Person",
"name": "Scott Galloway",
"url": "https://mostlylucid.net/blog/aboutme"
},
"publisher": {
"@@type": "Organization",
"name": "mostlylucid",
"logo": {
"@@type": "ImageObject",
"url": "https://mostlylucid.net/img/logo.svg"
}
},
"mainEntityOfPage": {
"@@type": "WebPage",
"@@id": "@canonicalUrl"
},
"wordCount": @Model.WordCount,
"inLanguage": "@Model.Language",
"keywords": "@string.Join(", ", Model.Categories)",
"image": "https://mostlylucid.net/img/social2.jpg"
}
</script>
Notez le @@ évacuation pour le @ Symbole dans les vues de Razor - JSON-LD @context et @type qui autrement serait interprétée comme étant la syntaxe Razor.
Ces données structurées indiquent à Google:
- Quel type de contenu est-il? (BlogPosting)
- Qui l'a écrit? (Personne ayant un URL pour en apprendre davantage)
- Quand elle a été publiée et modifiée
- Quels sont les thèmes qu'il couvre? ( mots clés des catégories)
- Combien de temps est-il? (nombre de mots)
- Quelle langue est-elle'
Google peut utiliser cette fonction pour afficher des fragments riches dans les résultats de recherche, incluant l'information sur l'auteurM SK1 dates de publication, et plusMSC3
4. Descriptions uniques pour les pages clés
N’oubliez pas vos pages statiques. Chaque page devrait avoir une description uniqueM SK2 pertinente :
<!-- Home page -->
@{
ViewBag.Title = "mostlylucid- Scott Galloway's Developer Blog";
ViewBag.Description = "Technical blog covering ASP.NET Core, C#, Entity Framework, HTMX, Docker, and modern web development. Practical tutorials, NuGet packages, and open source projects.";
}
<!-- Blog index -->
@{
ViewBag.Title = "Blog Posts";
ViewBag.Description = "Technical articles on ASP.NET Core, C#, Entity Framework, Docker, and modern web development. Practical tutorials and real-world examples from a lead developer.";
}
<!-- Contact page -->
@{
ViewBag.Title = "Contact Scott Galloway";
ViewBag.Description = "Get in touch with Scott Galloway. Questions about ASP.NET Core, C#, web development, or collaboration opportunities? Send me a message.";
}
<!-- Search page -->
@{
ViewBag.Title = "Search Results";
ViewBag.Description = "Search through technical articles on ASP.NET Core, C#, Entity Framework, and web development. Find tutorials, guides, and solutions.";
}
Autres éléments essentiels de SEO
Site Web
Vous avez besoin d’une carte de site. Il s’agit là d’un simple contrôleur qui en génère un dynamiquement.
public class SiteMapController(
IBlogViewService blogViewService,
IHttpContextAccessor httpContextAccessor) : Controller
{
[HttpGet]
[ResponseCache(Duration = 43200)] // Cache for 12 hours
public async Task<IActionResult> Index()
{
var pages = await blogViewService.GetPosts();
var siteUrl = $"https://{httpContextAccessor.HttpContext?.Request.Host}";
XNamespace sitemap = "http://www.sitemaps.org/schemas/sitemap/0.9";
var feed = new XDocument(
new XDeclaration("1.0", "utf-8", null),
new XElement(sitemap + "urlset",
from page in pages
select new XElement(sitemap + "url",
new XElement(sitemap + "loc", $"{siteUrl}/blog/{page.Slug}"),
new XElement(sitemap + "lastmod", page.PublishedDate.ToString("yyyy-MM-dd")),
new XElement(sitemap + "changefreq", "weekly"),
new XElement(sitemap + "priority", "0.8")
)
)
);
return Content(feed.ToString(), "text/xml");
}
}
Inscrire la route:
app.MapControllerRoute(
name: "sitemap",
pattern: "sitemap.xml",
defaults: new { controller = "SiteMap", action = "Index" });
robots.txt
Dites aux moteurs de recherche où votre carte de site est et ce qu’il faut parcourir:
app.MapGet("/robots.txt", async context =>
{
var siteUrl = $"https://{context.Request.Host}";
var robotsTxt = $"""
User-agent: *
Allow: /
Sitemap: {siteUrl}/sitemap.xml
""";
context.Response.ContentType = "text/plain";
await context.Response.WriteAsync(robotsTxt);
});
Distribution RSS
De nombreux développeurs utilisent des lecteurs RSS. Le fait d’avoir un feed RSS contribue également à la découverte de l’information.
<link rel="alternate" type="application/atom+xml"
title="RSS Feed for mostlylucid.net"
href="https://mostlylucid.net/rss" />
Que dire des images?
Vous vous demandez peut-être de produire des images OG uniques pour chaque post. Pour un blog technique , c’est' il ne vaut probablement pas la peine d’en faire l’effort
- Recherche sur Google - Les descriptions sont plus importantes que les images
- Distributions RSS - aucune image
- Hacker News / Reddit Les miniatures - sont à peine visibles
- Liens directs - les développeurs partagent des URLs
Une image de marque cohérente est parfaite pour la reconnaissance. La production d’images personnalisées est plus importante pour le contenu visuelM SK1 les sites de nouvelles, ou les pages de marketing qui font concurrence en matière de cliques sur Facebook et Twitter .
Si vous voulez les générer, vous pouvez utiliser Graphique de l'image (que j'utilise déjà pour le traitement des images)pour superposer un texte sur une templateM SK2
public async Task<string> GenerateOgImage(string title, string slug)
{
using var image = await Image.LoadAsync("wwwroot/img/og-template.png");
var font = SystemFonts.CreateFont("Arial", 48, FontStyle.Bold);
image.Mutate(x => x.DrawText(
new RichTextOptions(font)
{
Origin = new PointF(50, 200),
WrappingLength = 1100
},
title,
Color.White));
var outputPath = $"wwwroot/og/{slug}.png";
await image.SaveAsPngAsync(outputPath);
return $"/og/{slug}.png";
}
Mais pour un blog technique? Ship what you've gotM SK2
Tester votre SEO
Test des résultats riches de Google
Utilisation Google's Rich Results Test pour valider vos données structurées. Inscrivez un URL qui vous indiquera si votre JSON -LD est valide et quels sont les résultats riches auxquels vous êtes admissible.
Voir la source de la page
Le test le plus simple - visualise la source de page et vérifie:
- est-ce que
<meta name="description">unique pour cette page? - Il y a-t-il
<link rel="canonical">? - Il y a-t-il
<script type="application/ld+json">bloc?
Console de recherche Google
Après déploiement, soumettez votre carte de site à Console de recherche Google. Vous pouvez également utiliser l’outil d’inspection des URL pour voir exactement comment Google voit vos pages et demander une révision.
Résumé
Les corrections étaient simples:
| Problème | Réparer |
|---|---|
| Méta descriptions statiques | Dynamiques ViewBag.Description avec génération automatique de contenu |
| Aucune URL canonique | Ajouté <link rel="canonical"> à l'emplacement |
| Aucune donnée structurelle | JSONM SK2LD BlogPosting schéma sur chaque poste |
| Méta-données d'article manquantes | article:published_time, article:author, article:tag tags métadonnées |
| Descriptions de pages statiques | Description unique pour la page d'accueilM SK2 Blogu, ContactMSC4 Pages de recherche SSK5 |
Le point de vue clé: Google ne peut pas lire votre esprit. Si chaque page a la même description , Google n’a aucune façon de savoir ce qui rend chaque page unique et précieuse M SK2 Dites à Google quel est chacune des pages sur laquelle vous êtes fondée, et vousM SK4 vous classerez mieuxMSC5
Donnez-le quelques semaines pour que Google re-crawl votre site, et vous devriez voir des améliorations . SEO est un long jeuM SK3 mais ces éléments fondamentaux sont les fondements de tout ce qui se bâtit sur l’implantation de .