Stop Writing Plugins Like Itโ€™s 2011: Modern Architecture Guide

๐ŸŒŸ Modern Dataverse Plugin Architecture (2025 Edition)

A Clean, Testable, Maintainable, and DI-Friendly Template for Power Platform Developers

A complete, ready-to-use architecture template you can drop into your next Dataverse / …


This content originally appeared on DEV Community and was authored by Mohamed ELgharably

๐ŸŒŸ Modern Dataverse Plugin Architecture (2025 Edition)

A Clean, Testable, Maintainable, and DI-Friendly Template for Power Platform Developers

A complete, ready-to-use architecture template you can drop into your next Dataverse / Dynamics 365 project.

๐Ÿ”ฅ Why This Article?

Most Dataverse plugins still follow the old 2011 pattern:

  • Logic inside Execute()
  • Hard-coded field names
  • No testability
  • Zero separation of concerns
  • Hard to extend
  • Not reusable outside plugins
  • Difficult to maintain

This article gives you a modern, scalable, testable plugin architecture with:

โœ” Clean separation

โœ” Supports multi-project structure

โœ” Minimal DI (no heavy libraries)

โœ” Test-friendly

โœ” Reusable in Azure Functions / Custom APIs

โœ” NuGet-based plugin deployment

โœ” No system-specific logic

โœ” Perfect as a starter template

๐Ÿงฑ Architecture Overview

/PluginSolution
โ”‚
โ”œโ”€โ”€ Core
โ”‚   โ”œโ”€โ”€ Interfaces
โ”‚   โ”œโ”€โ”€ Models
โ”‚   โ””โ”€โ”€ Enums
โ”‚
โ”œโ”€โ”€ Infrastructure
โ”‚   โ”œโ”€โ”€ Repositories
โ”‚   โ””โ”€โ”€ Services
โ”‚
โ”œโ”€โ”€ Plugins
โ”‚   โ”œโ”€โ”€ PluginBase.cs  (from CLI template)
โ”‚   โ””โ”€โ”€ SamplePlugin.cs
โ”‚
โ””โ”€โ”€ Startup
    โ””โ”€โ”€ PluginFactory.cs

๐Ÿ— Layer Explanation

1. Core Layer (Pure, CRM-agnostic)

Contains:

  • Interfaces
  • Lightweight models
  • Enums
  • Zero dependency on Microsoft.Xrm.Sdk Benefits:
  • 100% testable
  • Reusable in Azure Functions / Custom APIs
  • Pure C# domain layer
2. Infrastructure Layer

Contains:

  • Repositories
  • Dataverse operations
  • FetchXML logic
  • Business services This layer knows about Dataverse so the rest of the system doesnโ€™t have to.
3. Plugins Layer

Responsible for:

  • Orchestration
  • Extracting context
  • Mapping Entity โ†’ Core Model
  • Calling services The plugin stays thin and easy to reason about.
4. Startup / Factory Layer (Minimal DI)

Instead of heavy DI (which causes sandbox issues), we use a simple factory pattern:

  • No dependency conflicts
  • No BCL async interface issues
  • No slow DI container startup
  • No Microsoft.Extensions.* packages needed Small. Fast. Compatible with Sandbox.

โšก Modern Deployment: PAC CLI + .nupkg Package

In 2025, plugins should not be deployed as DLLs.
Microsoft now provides:

pac plugin init --outputDirectory . --skip-signing

This command:

  • Creates a structured plugin project
  • Includes PluginBase + ILocalPluginContext
  • Supports NuGet packaging
  • Removes need for manual DLL signing

๐ŸŽฏ Why --skip-signing?

Because NuGet-based plugin deployment does not require strong naming.
Benefits:

  • No shared signing keys
  • No assembly conflicts
  • Smooth CI/CD
  • Faster team collaboration

๐Ÿงฉ Minimal DI (Factory Pattern)

Heavy DI causes:

  • Slow plugin execution
  • Version conflicts
  • Sandbox restrictions
  • Hard-to-debug runtime errors

So we use:

Plugin โ†’ Factory โ†’ Services โ†’ Repositories

This gives you DI benefits without DI overhead.

๐Ÿงฉ Optional: Using Early-Bound Classes (Highly Recommended)

Although the template in this article uses a lightweight EntityModel for simplicity,
the architecture is fully compatible with Early-Bound classes

Note:

The Power Platform CLI can now generate Early-Bound classes for you automatically using:

pac modelbuilder build --outputDirectory Models

Just drop the generated models into a separate project and reference it from your Plugin + Infrastructure layers.

๐Ÿ“ Template Code (Copy/Paste)

A completely generic, reusable template.

๐Ÿ“ฆ Core: Model
namespace PluginTemplate.Core.Models
{
    public class EntityModel
    {
        public Guid Id { get; set; }
        public string LogicalName { get; set; }
        public IDictionary<string, object> Attributes { get; set; }
    }
}
๐Ÿ“ฆ Core: Interface
namespace PluginTemplate.Core.Interfaces
{
    public interface IEntityValidationService
    {
        void Validate(EntityModel model, Guid userId);
    }
}
๐Ÿ“ฆ Infrastructure: Repository Template
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using PluginTemplate.Core.Interfaces;

namespace PluginTemplate.Infrastructure.Repositories
{
    public interface ISampleRepository
    {
        Entity RetrieveEntity(Guid id);
    }

    public class SampleRepository : ISampleRepository
    {
        private readonly IOrganizationService _service;

        public SampleRepository(IOrganizationService service)
        {
            _service = service;
        }

        public Entity RetrieveEntity(Guid id)
        {
            return _service.Retrieve(
                "xyz_customtable",
                id,
                new ColumnSet("xyz_textfield"));
        }
    }
}
๐Ÿ“ฆ Infrastructure: Service Template
using PluginTemplate.Core.Interfaces;
using PluginTemplate.Core.Models;

namespace PluginTemplate.Infrastructure.Services
{
    public class EntityValidationService : IEntityValidationService
    {
        public void Validate(EntityModel model, Guid userId)
        {
            // Add validation logic (optional)
        }
    }
}
โš™๏ธ Factory (Minimal DI)
using Microsoft.Xrm.Sdk;
using PluginTemplate.Core.Interfaces;
using PluginTemplate.Infrastructure.Repositories;
using PluginTemplate.Infrastructure.Services;

namespace PluginTemplate.Startup
{
    public static class PluginFactory
    {
        public static IEntityValidationService CreateValidationService(
            IOrganizationService service,
            ITracingService tracing)
        {
            var repository = new SampleRepository(service);

            return new EntityValidationService();
        }
    }
}
๐Ÿ”Œ Plugin Template
using System;
using Microsoft.Xrm.Sdk;
using PluginTemplate.Startup;
using PluginTemplate.Core.Models;
using PluginTemplate.Core.Interfaces;

public class SamplePlugin : PluginBase
{
    public SamplePlugin(string unsecure, string secure)
        : base(typeof(SamplePlugin)) { }

    protected override void ExecuteDataversePlugin(ILocalPluginContext ctx)
    {
        var context = ctx.PluginExecutionContext;
        var tracing = ctx.TracingService;
        var org = ctx.OrgSvcFactory.CreateOrganizationService(context.UserId);

        if (!(context.InputParameters["Target"] is Entity target))
            return;

        var model = new EntityModel
        {
            Id = target.Id,
            LogicalName = target.LogicalName,
            Attributes = target.Attributes
        };

        var service = PluginFactory.CreateValidationService(org, tracing);
        service.Validate(model, context.UserId);
    }
}

๐Ÿ“ Architecture Diagram

+-----------------------+
|        Plugins        |
|  (thin orchestration) |
+-----------+-----------+
            |
            v
+-----------+-----------+
|        Factory         |
|   (minimal DI layer)  |
+-----------+-----------+
            |
            v
+-----------+-----------+
|     Infrastructure    |
| Repositories/Services |
+-----------+-----------+
            |
            v
+-----------+-----------+
|      Core Layer       |
|  Interfaces + Models  |
+-----------------------+

โœจ Benefits of This Architecture

๐Ÿ”น 1. Testable

Core + Infrastructure can reach 100% test coverage.

๐Ÿ”น 2. Clean Separation

Plugin โ†’ Service โ†’ Repository.

๐Ÿ”น 3. Reusable

The same services can be used in:

  • Plugins
  • Custom APIs
  • Azure Functions
  • Virtual Tables
๐Ÿ”น 4. Minimal Dependencies

No need for:

  • Microsoft.Extensions.DependencyInjection
  • Async Interfaces
  • External DI frameworks


This content originally appeared on DEV Community and was authored by Mohamed ELgharably


Print Share Comment Cite Upload Translate Updates
APA

Mohamed ELgharably | Sciencx (2025-11-28T13:03:54+00:00) Stop Writing Plugins Like Itโ€™s 2011: Modern Architecture Guide. Retrieved from https://www.scien.cx/2025/11/28/stop-writing-plugins-like-its-2011-modern-architecture-guide-4/

MLA
" » Stop Writing Plugins Like Itโ€™s 2011: Modern Architecture Guide." Mohamed ELgharably | Sciencx - Friday November 28, 2025, https://www.scien.cx/2025/11/28/stop-writing-plugins-like-its-2011-modern-architecture-guide-4/
HARVARD
Mohamed ELgharably | Sciencx Friday November 28, 2025 » Stop Writing Plugins Like Itโ€™s 2011: Modern Architecture Guide., viewed ,<https://www.scien.cx/2025/11/28/stop-writing-plugins-like-its-2011-modern-architecture-guide-4/>
VANCOUVER
Mohamed ELgharably | Sciencx - » Stop Writing Plugins Like Itโ€™s 2011: Modern Architecture Guide. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2025/11/28/stop-writing-plugins-like-its-2011-modern-architecture-guide-4/
CHICAGO
" » Stop Writing Plugins Like Itโ€™s 2011: Modern Architecture Guide." Mohamed ELgharably | Sciencx - Accessed . https://www.scien.cx/2025/11/28/stop-writing-plugins-like-its-2011-modern-architecture-guide-4/
IEEE
" » Stop Writing Plugins Like Itโ€™s 2011: Modern Architecture Guide." Mohamed ELgharably | Sciencx [Online]. Available: https://www.scien.cx/2025/11/28/stop-writing-plugins-like-its-2011-modern-architecture-guide-4/. [Accessed: ]
rf:citation
» Stop Writing Plugins Like Itโ€™s 2011: Modern Architecture Guide | Mohamed ELgharably | Sciencx | https://www.scien.cx/2025/11/28/stop-writing-plugins-like-its-2011-modern-architecture-guide-4/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.