Building Dynamic Structured Data with JSON-LD in ASP.NET Core

By Tan Lee Published on May 28, 2025  500
Adding structured data to your website is a powerful way to enhance your site's SEO and improve how your content appears in search engine results.

In this article, we’ll walk through how to dynamically generate JSON-LD structured data in an ASP.NET Core application using the FoxLearn.AspNetCore.JsonLd library.

FoxLearn.AspNetCore.JsonLd a lightweight .NET library that simplifies the process of adding JSON-LD structured data to your ASP.NET Core applications. It automatically injects JSON-LD in the <head> section of your HTML without needing any manual HTML edits.

The first step is to install the FoxLearn.AspNetCore.JsonLd NuGet package.

You can install it in your project via the .NET CLI or using Visual Studio's NuGet Package Manager.

Via the .NET CLI:

Open your terminal and run the following command:

dotnet add package FoxLearn.AspNetCore.JsonLd

Via the NuGet UI in Visual Studio:

  1. Right-click on your project and select Manage NuGet Packages.

  2. Search for FoxLearn.AspNetCore.JsonLd and click Install.

jsonld aspnetcore

Next, we need to configure the services in your Program.cs or Startup.cs file. This involves adding the necessary services to the DI container and setting up structured data schemas.

Configure JSON-LD in Program.cs (ASP.NET Core 6+):

// Add default for each page
builder.Services.ConfigureJsonLd<WebSite>(options =>
{
    options.Id = "https://foxlearn.com#website";
    options.Url = new Uri("https://foxlearn.com");
    options.Name = "FoxLearn";
    options.Description = "Welcome to foxlearn.com! This site is a blog about everything that matters in the world of programming.";
    options.InLanguage = "en-US";
    options.PotentialAction = new SearchAction
    {
        Target = new Uri("https://foxlearn.com/post/search?q={search_term_string}"),
        QueryInput = "required name=search_term_string"
    };
});

builder.Services.AddJsonLd();

Next, add UseJsonLd() in the app pipeline:

app.UseJsonLd(); // Add this to enable JSON-LD injection in HTML

In the code above:

  • We configure JSON-LD for an Website schema, setting properties like Name, Description, etc.

  • We call app.UseJsonLd() to automatically inject the generated JSON-LD data into your HTML <head>.

Adding Structured Data in Controller or ViewModel

You can dynamically generate structured data using a helper service:

public class JsonLdGenerator
{
    private const string Hosting = "https://foxlearn.com";
    private readonly IJsonLdBuilder _jsonLdBuilder;

    public JsonLdGenerator(IJsonLdBuilder jsonLdBuilder)
    {
        _jsonLdBuilder = jsonLdBuilder;
    }

    private Uri BuildUri(string path = "") => new Uri($"{Hosting}/{path}".TrimEnd('/'));

    private Organization CreateOrganization() => new Organization
    {
        Name = "FoxLearn",
        Url = BuildUri(),
        Logo = new ImageObject()
        {
            Url = BuildUri("img/logo.png"),
        },
        Description = "Welcome to foxlearn.com! This site is a blog about everything that matters in the world of programming.",
        SameAs = new[] { new Uri("https://x.com/tanhynh"), new Uri("https://www.youtube.com/foxlearn") },
        ContactPoint = new[]
        {
                new ContactPoint
                {
                    Name = "Tan Lee",
                    ContactType = "Customer Service",
                    Email = "mailto:[email protected]"
                }
            }
    };

    private BreadcrumbList CreateBreadcrumb(string id, params (int pos, string name, string path)[] crumbs) => new BreadcrumbList
    {
        Id = id,
        ItemListElement = crumbs.Select(c =>
        {
            var item = new ListItem
            {
                Position = c.pos,
                Name = c.name,
                Item = BuildUri(c.path)
            };
            return item;
        }).ToArray()
    };


    public void Home()
    {
        _jsonLdBuilder.Add(new WebPage
        {
            Id = $"{Hosting}#webpage",
            Url = BuildUri(),
            Name = "Home",
            InLanguage = "en-US",
            IsPartOf = new WebSite
            {
                Id = $"{Hosting}#website"
            }
        });

        _jsonLdBuilder.Add(CreateBreadcrumb($"{Hosting}#breadcrumb", (1, "Home", "")));
    }

    public void Contact()
    {
        _jsonLdBuilder.Add(new ContactPage
        {
            Id = $"{Hosting}/contact.html#contactpage",
            Name = "Contact Us",
            Url = BuildUri("contact.html"),
            InLanguage = "en-US",
            MainEntity = CreateOrganization(),
            IsPartOf = new WebSite()
            {
                Id = $"{Hosting}#website"
            }
        });

        _jsonLdBuilder.Add(CreateBreadcrumb($"{Hosting}/contact.html#breadcrumb",
            (1, "Home", ""),
            (2, "Contact Us", "contact.html")
        ));
    }

    public void Privacy()
    {
        _jsonLdBuilder.Add(new WebPage
        {
            Id = $"{Hosting}/privacy.html#webpage",
            Name = "Privacy Policy",
            Url = BuildUri("privacy.html"),
            InLanguage = "en-US",
            MainEntity = CreateOrganization(),
            IsPartOf = new WebSite()
            {
                Id = $"{Hosting}#website"
            }
        });

        _jsonLdBuilder.Add(CreateBreadcrumb($"{Hosting}/privacy.html#breadcrumb",
            (1, "Home", ""),
            (2, "Privacy Policy", "privacy.html")
        ));
    }

    public void About()
    {
        _jsonLdBuilder.Add(new AboutPage
        {
            Id = $"{Hosting}/about.html#aboutpage",
            Name = "About Us",
            Url = BuildUri("about.html"),
            InLanguage = "en-US",
            MainEntity = CreateOrganization(),
            IsPartOf = new WebSite()
            {
                Id = $"{Hosting}#website"
            }
        });

        _jsonLdBuilder.Add(CreateBreadcrumb($"{Hosting}/about.html#breadcrumb",
            (1, "Home", ""),
            (2, "About Us", "about.html")
        ));
    }

    public void Donate()
    {
        _jsonLdBuilder.Add(new WebPage
        {
            Id = $"{Hosting}/donate.html#webpage",
            Name = "Donate",
            Url = BuildUri("donate.html"),
            InLanguage = "en-US",
            MainEntity = new DonateAction
            {
                Name = "FoxLearn",
                Target = BuildUri("donate.html"),
                Description = "You're welcome to donate to foxlearn.com using the PayPal Donate form below. You can choose any amount you'd like.",
                Recipient = CreateOrganization()
            },
            IsPartOf = new WebSite()
            {
                Id = $"{Hosting}#website"
            }
        });

        _jsonLdBuilder.Add(CreateBreadcrumb($"{Hosting}/donate.html#breadcrumb",
            (1, "Home", ""),
            (2, "Donate", "donate.html")
        ));
    }

    public void HowTo()
    {
        _jsonLdBuilder.Add(new WebPage
        {
            Id = $"{Hosting}/howto.html#webpage",
            Name = "How to",
            Url = BuildUri("howto.html"),
            InLanguage = "en-US",
            MainEntity = CreateOrganization(),
            IsPartOf = new WebSite()
            {
                Id = $"{Hosting}#website"
            }
        });

        _jsonLdBuilder.Add(CreateBreadcrumb($"{Hosting}/howto.html#breadcrumb",
            (1, "Home", ""),
            (2, "How to", "howto.html")
        ));
    }

    public void Author()
    {
        var authorUrl = "author/tanlee";
        _jsonLdBuilder.Add(new ProfilePage
        {
            Id = $"{Hosting}/author/tanlee#profilepage",
            Name = "Tan Lee",
            Url = BuildUri(authorUrl),
            MainEntity = new Person
            {
                Name = "Tan Lee",
                Url = BuildUri(authorUrl),
                SameAs = new[] { new Uri("https://x.com/tanhynh"), new Uri("https://www.youtube.com/foxlearn") }
            },
            IsPartOf = new WebSite()
            {
                Id = $"{Hosting}#website"
            }
        });

        _jsonLdBuilder.Add(CreateBreadcrumb($"{Hosting}/author/tanlee#breadcrumb",
            (1, "Home", ""),
            (2, "Author", authorUrl)
        ));
    }

    public void Search(string value)
    {
        var searchUrl = $"post/search?q={value}";

        _jsonLdBuilder.Add(new SearchResultsPage
        {
            Id = $"{Hosting}/{searchUrl}#searchresultspage",
            Name = "Search Results",
            Url = BuildUri(searchUrl),
            InLanguage = "en-US",
            MainEntity = CreateOrganization(),
            IsPartOf = new WebSite()
            {
                Id = $"{Hosting}#website"
            }
        });

        _jsonLdBuilder.Add(CreateBreadcrumb($"{Hosting}/{searchUrl}#breadcrumb",
            (1, "Home", ""),
            (2, "Search", searchUrl)
        ));
    }

    public void Category(Category obj)
    {
        var categoryPath = $"{obj.UrlSlug}/page1.html";
        _jsonLdBuilder.Add(new CollectionPage
        {
            Id = $"{Hosting}/{categoryPath}#collectionpage",
            Name = obj.CategoryName,
            Url = BuildUri(categoryPath),
            InLanguage = "en-US",
            MainEntity = CreateOrganization(),
            IsPartOf = new WebSite()
            {
                Id = $"{Hosting}#website"
            }
        });

        _jsonLdBuilder.Add(CreateBreadcrumb($"{Hosting}/{categoryPath}#breadcrumb",
            (1, "Home", ""),
            (2, obj.CategoryName!, categoryPath)
        ));
    }

    public void Detail(Post obj)
    {
        var postPath = $"{obj.CategoryUrlSlug}/{obj.PostUrlSlug}-{obj.PostId}.html";
        var postUri = BuildUri(postPath);

        var blogPosting = new BlogPosting
        {
            Id = $"{Hosting}/{postPath}#blogposting",
            Headline = obj.Title,
            Url = postUri,
            DatePublished = obj.CreatedDate.ToUniversalTime(),
            Description = obj.ShortDescription,
            Author = new Person
            {
                Name = "Tan Lee",
                Url = BuildUri("author/tanlee")
            },
            Publisher = CreateOrganization(),
            IsPartOf = new WebSite()
            {
                Id = $"{Hosting}#website"
            },
            DateModified = obj.ModifiedDate?.ToUniversalTime(),
            MainEntityOfPage = new WebPage
            {
                Id = $"{Hosting}/{postPath}"
            }
        };

        if (!string.IsNullOrEmpty(obj.ImageUrl))
            blogPosting.Image = new ImageObject { Url = BuildUri(obj.ImageUrl.TrimStart('/')) };

        _jsonLdBuilder.Add(blogPosting);

        _jsonLdBuilder.Add(CreateBreadcrumb($"{Hosting}/{postPath}#breadcrumb",
            (1, "Home", ""),
            (2, obj.CategoryName!, obj.CategoryUrlSlug!),
            (3, obj.Title!, postPath)
        ));
    }
}

Use in Controller

public class HomeController : Controller
{
    private readonly JsonLdGenerator _jsonLdGenerator;

    public HomeController(JsonLdGenerator jsonLdGenerator)
    {
        _jsonLdGenerator = jsonLdGenerator;
    }

    public async Task<IActionResult> Index(int? page)
    {
        _jsonLdGenerator.Home();
        var posts = await _postRepository.GetPagedPostsAsync(PostType.Article, page ?? 1);
        return View(posts);
    }
}

In this example:

  • We create a BreadcrumbList schema, which is used to represent navigational breadcrumbs.

  • The IJsonLdBuilder is used to add the breadcrumb data to the page.

  • When the page is rendered, this structured data will be injected into the <head> section.

Output:

<script type="application/ld+json">
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "WebSite",
      "inLanguage": "en-US",
      "@id": "https://foxlearn.com#website",
      "url": "https://foxlearn.com",
      "potentialAction": {
        "@type": "SearchAction",
        "query-input": "required name=search_term_string",
        "target": "https://foxlearn.com/post/search?q={search_term_string}"
      },
      "name": "FoxLearn",
      "description": "Welcome to foxlearn.com! This site is a blog about everything that matters in the world of programming."
    },
    {
      "@type": "WebPage",
      "isPartOf": {
        "@type": "WebSite",
        "@id": "https://foxlearn.com#website"
      },
      "mainEntity": {
        "@type": "Organization",
        "contactPoint": [
          {
            "@type": "ContactPoint",
            "email": "[email protected]",
            "contactType": "Customer Service",
            "name": "Tan Lee"
          }
        ],
        "logo": {
          "@type": "ImageObject",
          "url": "https://foxlearn.com/img/logo.png"
        },
        "url": "https://foxlearn.com",
        "sameAs": [
          "https://x.com/tanhynh",
          "https://www.youtube.com/foxlearn"
        ],
        "name": "FoxLearn",
        "description": "Welcome to foxlearn.com! This site is a blog about everything that matters in the world of programming."
      },
      "inLanguage": "en-US",
      "@id": "https://foxlearn.com#webpage",
      "url": "https://foxlearn.com",
      "name": "Home"
    },
    {
      "@type": "BreadcrumbList",
      "itemListElement": [
        {
          "@type": "ListItem",
          "position": 1,
          "item": {
            "@id": "https://foxlearn.com/",
            "@type": "Thing",
            "name": "Home"
          }
        }
      ],
      "@id": "https://foxlearn.com#breadcrumb"
    }
  ]
}
</script>

This <script> block will be automatically injected into the <head> section of the HTML, and search engines can easily parse it to understand the structured data about your website.

If you prefer injecting JSON-LD tags via Razor:

Enable the Tag Helper: In _ViewImports.cshtml:

@addTagHelper *, FoxLearn.AspNetCore.JsonLd

Inject in Layout: In your main layout (e.g., _Layout.cshtml):

<head>
    ...
    <json-ld />
</head>

You can use the Google Rich Results Test tool to verify that your JSON-LD data is correctly implemented and can be recognized by search engines.

  • Visit Google’s Rich Results Test.

  • Enter the URL of your page or paste the raw HTML.

  • Run the test to see if your structured data appears correctly.

By integrating FoxLearn.AspNetCore.JsonLd into your ASP.NET Core project, you can easily inject dynamic JSON-LD structured data into your pages, enhancing SEO and making your content more discoverable in search engines.

Related