How-to use Orchard Core as a decoupled CMS for your website

Published 12/4/2022 9:03:40 AM
Filed under Web development

We've been using wordpress for the Aigency website since last year and it helped us to quickly set up things for the company. However, we've found that wordpress has a number of issues that just aren't fixable for us.

So instead of continuing to use Wordpress, we decided to look for something new. There are a large number of options when it comes to building websites with a CMS but I personally would like something simple.

In this post we'll explore Orchard Core as a CMS and why I prefer to build our website with it.

Introduction to Orchard Core

Orchard Core is a framework to build modular multi-tenant applications with ASP.NET Core. On top of this framework there's the CMS that provides modules to manage content on the website.

Before Orchard Core there was Orchard, the same principles but for ASP.NET on .NET Framework.

Orchard has been an old-time friend of mine. Joop Snijder and I started knowNow a company that built knowledge management systems a couple of years ago. Our product was based on this open source CMS. We heavily modified it up to a point where we weren't exactly able to upgrade to the latest releases anymore. Which was fine since by then we had changed so much it wasn't Orchard anymore.

I remember pushing out docs changes and code changes to Orchard from time to time. It has a great community of people that are willing to help in a lot of ways.

When I needed to find an alternative to Wordpress, it was only logical to take another peek at Orchard Core to see how it would do with my current use case.

Three ways to build a website

Orchard Core offers four ways to build a website:

  • Fully managed CMS
  • Decoupled CMS
  • Headless CMS
  • Multi-tenant modular applications

First, you can configure your web application as a fully managed CMS. Orchard takes care of managing the content and rendering that content. This is a mode for developers who are looking to build just a CMS and need limited customization.

A second method to build a website with Orchard is to use the backend of the CMS but not the frontend. You are responsible for rendering the content on the website. Orchard manages the content on the website through the backend admin panel.

If you're building a single page application which needs content, you can also use Orchard to manage content. In this case you would host Orchard as a separate website without a frontend. Content is managed through the backend and served via the REST or GraphQL API.

Finally, you can Orchard for modular multi-tenant applications without any CMS functionality. In that case you're likely not managing any content.

Our website

We opted to build our website with Orchard as a decoupled CMS. We have a couple of reasons to go for this option:

  • We have mostly content that doesn't change often but has a complex layout
  • We have podcasts and blogs that we want to change regularly

The Aigency website is a marketing website that doesn't change weekly. So we have a design that's pretty to look at and complex to build with the elements that are offered in Orchard Core. I think we can build it fully in the CMS, but in the end we would have to write a lot of the HTML ourselves.

However, we also have content that isn't that complicated. Blogposts and Podcasts have a fixed layout that's pretty basic.

For the podcasts we plan to use the Buzzsprout API to sync the episodes to the website.

For the blogposts we want Orchard to manage the content.

Setting up Orchard as a decoupled CMS

To configure Orchard, you'll need an empty website project. You can create one in Visual Studio or in the terminal with the following command:

dotnet new web -n MyWebsite

After setting up the website, add the following package to the project.

dotnet add package OrchardCore.Application.Cms.Core.Targets

Then open the Program.cs file in the project and add the following code to it.

using Microsoft.ApplicationInsights.Extensibility;
using Serilog;
using OrchardCore.Data.Migration;
using OrchardCore.Logging;
using Serilog.Events;
using Serilog.Sinks.ApplicationInsights.TelemetryConverters;
using Migrations = Aigency.Web.Migrations;

var builder = WebApplication.CreateBuilder(args);
    
builder.Services.AddOrchardCms();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseDeveloperExceptionPage();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseOrchardCore();

app.Run();

When you start the website you'll be greeted with a setup page. You can configure the website using your favorite database.

Getting rid of the setup page

While the setup page is convenient for local development, it's pretty annoying when you first deploy the website to your production environment. I would like to have the website configure itself automatically.

You can do this with Orchard Core. You'll need to modify the Program.cs file so it includes the OrchardCore.AutoSetup feature during setup.

builder.Services.AddOrchardCms().AddSetupFeatures("OrchardCore.AutoSetup");

Next you'll need to add some configuration settings to the appsettings.json file in the web project:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "OrchardCore": {
    "OrchardCore_AutoSetup": {
      "AutoSetupPath": "",
      "Tenants": [
        {
          "ShellName": "Default",
          "SiteName": "MyWebsite",
          "SiteTimeZone": "Europe/Amsterdam",
          "AdminUsername": "admin",
          "AdminEmail": "admin@domain.org",
          "AdminPassword": "<your-password>",
          "DatabaseProvider": "Sqlite",
          "DatabaseConnectionString": "",
          "DatabaseTablePrefix": "",
          "RecipeName": "Blank"
        }
      ]
    },
  }
}

When you start the application, it will skip the setup page and configure itself using the settings provided in the appsettings.json file.

For production I recommend using environment variables or configuration settings in Azure Web Apps to configure the username, password, and the connection string.

With the website started, you can go to /admin and login with your admin credentials to manage the website.

Now that we've setup the basics, it's time to have a little fun creating some content on the website.

Creating content types

Orchard Core has a nice feature called Data Migrations. With Data Migrations you can create content types, content parts, and fields. You can also use the same migrations to create plain database tables.

Let's create a blogpost content-type for the website using migrations.

First, we need to create a new migration class:

public class Migrations : DataMigration
{
    private readonly IContentDefinitionManager _contentDefinitionManager;

    public Migrations(IContentDefinitionManager contentDefinitionManager)
    {
        _contentDefinitionManager = contentDefinitionManager;
    }

    public int Create()
    {
        _contentDefinitionManager.AlterPartDefinition("SocialMetadata", part =>
        {
            part.WithDisplayName("Social media metadata");

            part.WithField("Excerpt", field => field
                .OfType(nameof(TextField))
                .WithDisplayName("Excerpt")
                .WithEditor("TextArea"));

            part.WithField("CoverImage", field => field
                .OfType(nameof(MediaField))
                .WithDisplayName("Cover image"));
        });

        _contentDefinitionManager.AlterTypeDefinition("Post", type =>
        {
            type.Draftable();
            type.Creatable();

            type.WithPart(nameof(PublishLaterPart));
            type.WithPart(nameof(TitlePart));
            type.WithPart("SocialMetadata").WithDescription("Metadata used to render social media cards");
            type.WithPart(nameof(HtmlBodyPart), part => part.WithEditor("Trumbowyg"));
        });

        return 1;
    }
}

The migration class contains the following pieces:

  • First, we need to create a class called Migrations that derives from DataMigration
  • Next, we create a method Create that returns the version 1
  • Then, we define a new content part SocialMetadata with a couple of fields
  • After that, we create a new content-type Post with a title, body, and the social metadata that we created earlier

If you're interested in the details of migrations I recommend reading the following two articles:

After adding the migration class we need to explain to Orchard Core how to run the migrations. Modify the Program.cs to include the following code:

builder.Services
    .AddOrchardCms()
    .AddSetupFeatures("OrchardCore.AutoSetup")
    .EnableFeature("OrchardCore.Contents")
    .EnableFeature("OrchardCore.ContentTypes")
    .EnableFeature("OrchardCore.Media")
    .ConfigureServices(services => 
    { 
        services.AddDataMigration<Migrations>(); 
    });

First, we need to enable additional features for the tenant so we can manage content. Then, we can configure tenant services. In the ConfigureServices method call we need to add the data migration.

When you boot the website, it will now automatically configure itself and create the content-type that we defined in the migration.

We can now render the content in a Razor Page or a MVC controller view.

Rendering content

When we configured Orchard Core, we automatically got support for Controllers with views and Razor Pages. To render content we can add a new Razor Page by creating a file Pages/Index.cshtml.

In this file we're going to make a really basic content page that loads the 5 latest published posts and render the title of those posts.

In the Razor Page, add the following content:

@page
@using OrchardCore
@inject IOrchardHelper Orchard;
@{
    ViewBag.Title = "Home";

    var latestPosts = await Orchard.GetRecentContentItemsByContentTypeAsync("Post", 5);
}
<ul>
    @foreach(var post in latestPosts)
    {
        <li>@post.As<TitlePart>().Title</li>
    }
</ul>

This code performs a couple of steps:

  • First, we inject the IOrchardHelper so we can interact with the CMS part
  • Next, we load the latest posts from the database
  • Finally, we loop over the posts and render the title part

This is obviously very basic, but it demonstrates quite well how you can combine artisanal HTML with content coming from the CMS.

Where to next

I hope you've got a sense of what OrchardCore can offer as a decoupled CMS. If you're interested in learning more, I can highly recommend checking out the documentation on the Orchard Core website.

Enjoy!