← Back to list

Creating a Custom Widget in Sitefinity ASP.NET Core renderer

This guide demonstrates how to build a custom widget in Sitefinity .NET Core using a Card widget example. You’ll learn about the…

Emiliya · 2025-01-06 14:50 · 3 claps · 2.6 min read
#sitefinity #sitefinity-developer #net-core #mvc
Open on Medium ↗

Creating a Custom Widget in Sitefinity ASP.NET Core renderer

This guide demonstrates how to build a custom widget in Sitefinity .NET Core using a Card widget example. You’ll learn about the recommended architecture, implementation patterns, and how to support multiple widget views.

Required Components vs Optional Components

Required Components ⭐

  • ViewComponents folder with your ViewComponent class
  • Views folder with at least one view template
  • Service registration in Program.cs

Recommended but Optional Components

  • Models folder for business logic
  • ViewModels folder for view-specific models
  • Entities folder for widget configuration

File Structure

YourProject/
├── ViewComponents/ (⭐ Required)
│   └── CardViewComponent.cs
├── Models/
│   ├── Card/
│   │   ├── ICardModel.cs
│   │   └── CardModel.cs
├── ViewModels/
│   └── Card/
│       └── CardViewModel.cs
├── Entities/
│   └── Card/
│       └── CardEntity.cs
└── Views/ (⭐ Required)
    └── Shared/
        └── Components/
            └── Card/
                ├── Default.cshtml #Your widget's default outfit
                └── Alternate.cshtml

Step 1: Create the Entity

public class CardComparisonEntity
{
    private const string ViewSection = "View section";
    [ContentSection(ViewSection)]
    [ViewSelector]
    public string ViewName { get; set; }
}

Naming Convention: Must have “Entity” suffix Purpose: Defines widget properties for the Sitefinity backend

In ASP.NET Core widgets, public properties of the entity are persisted and exposed in the designer interface for editing pages. This separation ensures that business logic is decoupled from rendering.

Step 2: Define the ViewModel

public class CardViewModel
{
    public string ViewName { get; set; }
    // Add other properties needed for the view
}

Naming Convention: Must have “ViewModel” suffix Purpose: Data container for views

Step 3: Implement the Model Interface

public interface ICardModel
{
    Task<CardViewModel> InitializeViewModel(CardEntity entity);
}

Step 4: Implement the Model

public class CardModel : ICardModel
{
    private readonly IODataRestClient restClient;
    public CardModel(IODataRestClient service)
    {
        this.restClient = service;
    }

    public Task<CardViewModel> InitializeViewModel(CardEntity entity)
    {
        if (entity == null)
            throw new ArgumentNullException(nameof(entity));
        try
        {
            var viewModel = new CardViewModel
            {
                ViewName = entity.ViewName,
            };
            return Task.FromResult(viewModel);
        }
        catch (Exception ex)
        {
            throw new Exception("Failed to initialize CardViewModel", ex);
        }
    }
}

Naming Convention: Must have “Model” suffix Purpose: Contains business logic

Step 5: Create the ViewComponent (⭐ Required)

[SitefinityWidget(Title = "Card")]
public class CardViewComponent : ViewComponent
{
    private readonly ICardModel model;
    public CardViewComponent(ICardModel model)
    {
        this.model = model ?? throw new ArgumentNullException(nameof(model));
    }

    public virtual async Task<IViewComponentResult> InvokeAsync(IViewComponentContext<CardEntity> context)
    {
        if (context == null)
            throw new ArgumentNullException(nameof(context));
        var viewModel = await this.model.InitializeViewModel(context.Entity);
        return this.View(context.Entity.ViewName, viewModel);
    }
}

*Key Points:

  • Use the [SitefinityWidget] attribute to load the widget automatically in the Sitefinity Insert Widget dialogs.
  • Inherit from ViewComponent for the Renderer to detect and render your functionality.
  • The InvokeAsync method is required and is called automatically during page rendering.
  • Use IViewComponentContext<T> to access the widget’s entity and properties during rendering.*

Step 6: Create the Views (⭐ Required)

Create view files in the Views/Shared/Components/Card folder:

// Default.cshtml
@model Renderer.ViewModels.Card.CardViewModel
<h3>Card</h3>
<!-- Add your default view content here -->

// Alternate.cshtml
@model Renderer.ViewModels.Card.CardViewModel
<div class="alternate-view">
    <h3>Card - Alternate View</h3>
    <!-- Add your alternate view content here -->
</div>

*Naming Conventions:

  • The folder must match the widget name
  • The default view should be named Default.cshtml*

Step 7: Register the Service (⭐ Required)

Add to Program.cs or Startup.cs:

builder.Services.AddScoped<ICardModel, CardModel>();

Best Practices and Tips

Widget Flow:

Request → ViewComponent → Model → ViewModel → View → Response

Support Multiple Views:

  • Use the [ViewSelector] attribute in the entity
  • Create multiple .cshtml files in the Views folder
  • Pass ViewName from the entity to the View method

Common Pitfalls:

  • Incorrect folder structure
  • Missing required attributes
  • Incorrect naming conventions
  • Forgetting to register dependencies

Learn More

By following these steps and best practices, focusing on the required components (marked with ⭐), you can create robust and maintainable widgets in Sitefinity .NET Core. Happy coding!

Photo by Christin Hume on Unsplash

Photo by Christin Hume on Unsplash


메타데이터
post_id
9040dcb152c6
slug
creating-a-custom-widget-in-sitefinity-asp-net-core-renderer-9040dcb152c6
url
https://medium.com/@emilium/creating-a-custom-widget-in-sitefinity-asp-net-core-renderer-9040dcb152c6
canonical_url
https://medium.com/@emilium/creating-a-custom-widget-in-sitefinity-asp-net-core-renderer-9040dcb152c6
author_url
https://medium.com/@emilium
status
ok
fetched_at
2026-06-24 11:06:28