Varför du inte hittade det här på Google? (Svenska (Swedish))

Varför du inte hittade det här på Google?

Wednesday, 26 November 2025

//

9 minute read

Jag har drivit den här bloggen i ett tag nu., skriver detaljerade tekniska artiklar på ASP, ., NET Core och ,, Beståndsdel av enhet, ,, HTMX och ,, och alla möjliga sorters.

Problemet: Varje sida såg lika ut som Google

När Google går igenom din sida, tittar den på flera nyckelsignaler för att förstå vad varje sida handlar om.

The Smoking Gun: Statiska Metabeschreibunger

Här är vad min _Layout.cshtml såg ut som

<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.">

Varje. Enlig. sida . Samma beskrivningM SK3 Min artikel om Hintergrundtjänster i ASP.NET Core? Samma beskrivning som min hemsida. Min djupdykning in RAG arkitektur? Samma beskrywing.

Google ser 200+ sidor med identiska beskrywings och tror att "den här sidan har duplicerade innehållsmängder M SK2 eller

Missande kanoniska URLs

Jag har en flerspråkig blogg med översättningar. Samma innehåll existerar på

  • /blog/my-article ( engelska)
  • /blog/my-article/fr ( franskaM SK1
  • /blog/my-article/de (DeutskM SK1

Utan kanoniska URLs, Google skulle kunna se dessa som duplicerade innehåll, som dämpar SEO-värdet över flera URLs istället för att konsolidera det på den primära sidan

Ingen strukturerad data

Googles sökresultat kan visa rika fragment. JSON-LD strukturerade data. Jag var

Statiska sociala bilder

Varje sida delade samma og:image. Medan detta inte affecterar direkt Googles rankinger , påverkar det click- -through rates when articles are shared on social media.

The Fixes

1. Dynamiska Metabeschreibunger

Den första lösningen var att göra layout stöd för dynamiska beschreibunger med en vetlig fallback

@{
    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" />
    }
}

Nu låter layouten ViewBag.Description om ställts, faller tillbaka till en standardversion. Den kanoniska URL: n ställs automatiskt till den nuvarande sidan

2. Automatiskt-Generat descriptions for blog posts

Varje bloggpost genererar nu dess Beschreibung från de första 155-tecknen i innehållet 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}";
}

Nyckelpunkten här:

  1. Spräng vid ordgränsen - Vi hittar det sista utrymmet innan 155-tecknen för att undvika att skära ihop ord
  2. Strippa nya linjer - Metabeschreibunger borde vara ensamma
  3. Bestämda og:type till "articleM SK1 - säger till sociala plattformar att det här är en artikel , inte en generisk webbsida
  4. Passa artikel-metadata - Published date and categories flow through to the layout

3. JSON-LD Strukturerade data

Det här är den stora för rika snippets.

<!-- 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>

Kom ihåg @@ att fly ut för @ symbol i Razor-uppfattningar - JSON -LD använder @context och @type som annars skulle tolkas som Razor syntax.

Denna strukturerade data säger till Google:

  • Vilken typ av innehåll är detta? (Blogposting)
  • Vem skrev det? (Person med en URL för att lära sig mer
  • När den publicerades och ändrades
  • Vilka ämnen omfattas av den (talord från kategorier)
  • Hur länge är det? (tal ord)
  • Vilket språk det är, ', i

Google kan använda detta för att visa innehållsrika fragment i sökresultaten, inklusive författareinformationen , publiceringsdatum, och merM SK3

4. Enkela Beschreibunger för nyckelsidor

Glöm inte dina statiska sidor.

<!-- 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.";
}

Andra SEO nödvändigheter

Sitemap

Du behöver en platskarta. Här' är en enkel kontroller som genererar en dynamiskt

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");
    }
}

Registrera vägen:

app.MapControllerRoute(
    name: "sitemap",
    pattern: "sitemap.xml",
    defaults: new { controller = "SiteMap", action = "Index" });

robotar.txt

Berätta för sökmotorer var din webbkarta är och vad man ska gå igenom

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);
});

RSS-flöde

Många utvecklare använder RSS-reader.

<link rel="alternate" type="application/atom+xml"
      title="RSS Feed for mostlylucid.net"
      href="https://mostlylucid.net/rss" />

Vad sägs om bilder?

Du kanske undrar om att generera unika OG-bilder för varje Beitrag.

  • Sök på Google - beskriver är viktigare än bilder
  • RSS-flöden - inga bilder
  • Hacker-nyheter / Reddit - tummenailer knappt synliga
  • Direkta länkar - utvecklare som delar URLs

Ett konsekvent varumärke är bra för att känna igen

Om du ville generera dem, så kunde du använda Bildform ( som jag redan använder för bildbearbeitning

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";
}

Men för en teknisk blogg

Testa din SEO

Google Rich Results Test

Använda Googles rika resultattest att validera dina strukturerade data.

Se sidan källa

Den enklaste testen - tittar på sidans källa och kontrollerar

  • Är <meta name="description"> unikt för denna sida?
  • Finns det en <link rel="canonical">?
  • Finns det en <script type="application/ld+json"> block?

Googles sökkonsole

Efter att sätta igång, skicka din webbkarta till Googles sökkonsole. Du kan också använda URL Inspection-Toolet för att se exakt hur Google ser dina sidor och fråga om redigering

sammanfattning

Bestämningarna var enkla.

Problemet Fixera
Statiska metabeschreibunger Dynamiska ViewBag.Description med automatiserad generation av innehåll
Inga kanoniska URLs Hinnades <link rel="canonical"> till layout
Inga strukturerade data BlogPosting schema på varje gång
Missande artikel-metadata article:published_time, article:author, article:tag meta-tag
Statiska webbsidorsbeschreibunger Enkela webbsidor för hemsidan, BlogM SK3 Kontakt

Den viktigaste insikten Google kan inte läsa din tankar. Om varje sida har samma beskrivning , Google har inget sätt att veta vad som gör varje sida unik och värdefulla M SK2 Säg till Google vad varje sida handlar om , så kommer du att rankera bättre

Give it a few weeks for Google to re

Fortsättning avläsning

Finding related posts...
logo

© 2026 Scott Galloway — Unlicense — All content and source code on this site is free to use, copy, modify, and sell.