Skip to content

Modules

Huy Nguyen edited this page Apr 5, 2025 · 2 revisions

Module Development

This guide will help you understand how to develop modules for Mixcore CMS. Modules are self-contained units of functionality that can be added to the core platform.

Module Structure

A typical module has the following structure:

MyModule/
├── Controllers/
│   └── MyController.cs
├── Services/
│   ├── IMyService.cs
│   └── MyService.cs
├── Models/
│   ├── MyModel.cs
│   └── MyViewModel.cs
├── Views/
│   └── MyView.cshtml
├── Migrations/
│   └── 20240101000000_Initial.cs
├── Module.cs
└── MyModule.csproj

Creating a New Module

  1. Use the Mixcore CLI to create a new module:

    dotnet new mixcore-module -n MyModule
  2. The CLI will create the basic structure and necessary files.

Module Class

The Module.cs file is the entry point for your module:

public class Module : IModule
{
    public string Name => "MyModule";
    public string Version => "1.0.0";

    public void ConfigureServices(IServiceCollection services)
    {
        // Register services
        services.AddScoped<IMyService, MyService>();
        
        // Register controllers
        services.AddControllers()
            .AddApplicationPart(typeof(Module).Assembly);
    }

    public void Configure(IApplicationBuilder app)
    {
        // Configure middleware
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });
    }
}

Controllers

Controllers handle HTTP requests and responses:

[ApiController]
[Route("api/[controller]")]
public class MyController : ControllerBase
{
    private readonly IMyService _myService;

    public MyController(IMyService myService)
    {
        _myService = myService;
    }

    [HttpGet]
    public async Task<IActionResult> Get()
    {
        var result = await _myService.GetDataAsync();
        return Ok(result);
    }

    [HttpPost]
    public async Task<IActionResult> Post([FromBody] MyModel model)
    {
        var result = await _myService.CreateAsync(model);
        return CreatedAtAction(nameof(Get), new { id = result.Id }, result);
    }
}

Services

Services contain business logic:

public interface IMyService
{
    Task<MyModel> GetDataAsync();
    Task<MyModel> CreateAsync(MyModel model);
    Task UpdateAsync(MyModel model);
    Task DeleteAsync(int id);
}

public class MyService : IMyService
{
    private readonly IRepository<MyEntity> _repository;

    public MyService(IRepository<MyEntity> repository)
    {
        _repository = repository;
    }

    public async Task<MyModel> GetDataAsync()
    {
        var entity = await _repository.GetByIdAsync(1);
        return MapToModel(entity);
    }

    private MyModel MapToModel(MyEntity entity)
    {
        return new MyModel
        {
            Id = entity.Id,
            Name = entity.Name,
            // Map other properties
        };
    }
}

Models

Models represent your data:

public class MyModel
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public DateTime CreatedDate { get; set; }
}

public class MyViewModel
{
    public string DisplayName { get; set; }
    public string Summary { get; set; }
}

Views

Views are used for rendering UI:

@model MyModule.Models.MyViewModel

<div class="container">
    <h1>@Model.DisplayName</h1>
    <p>@Model.Summary</p>
</div>

Database Migrations

Migrations manage database schema changes:

public partial class Initial : Migration
{
    protected override void Up(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.CreateTable(
            name: "MyEntities",
            columns: table => new
            {
                Id = table.Column<int>(nullable: false)
                    .Annotation("SqlServer:Identity", "1, 1"),
                Name = table.Column<string>(nullable: false),
                Description = table.Column<string>(nullable: true),
                CreatedDate = table.Column<DateTime>(nullable: false)
            },
            constraints: table =>
            {
                table.PrimaryKey("PK_MyEntities", x => x.Id);
            });
    }

    protected override void Down(MigrationBuilder migrationBuilder)
    {
        migrationBuilder.DropTable(name: "MyEntities");
    }
}

Module Configuration

Configure your module in appsettings.json:

{
  "MyModule": {
    "Setting1": "Value1",
    "Setting2": "Value2"
  }
}

Module Dependencies

Declare dependencies on other modules:

[ModuleDependency(typeof(OtherModule))]
public class Module : IModule
{
    // Module implementation
}

Testing

Create unit tests for your module:

public class MyServiceTests
{
    private readonly Mock<IRepository<MyEntity>> _repositoryMock;
    private readonly MyService _service;

    public MyServiceTests()
    {
        _repositoryMock = new Mock<IRepository<MyEntity>>();
        _service = new MyService(_repositoryMock.Object);
    }

    [Fact]
    public async Task GetDataAsync_ReturnsData()
    {
        // Arrange
        var entity = new MyEntity { Id = 1, Name = "Test" };
        _repositoryMock.Setup(r => r.GetByIdAsync(1))
            .ReturnsAsync(entity);

        // Act
        var result = await _service.GetDataAsync();

        // Assert
        Assert.NotNull(result);
        Assert.Equal(entity.Id, result.Id);
        Assert.Equal(entity.Name, result.Name);
    }
}

Best Practices

  1. Separation of Concerns

    • Keep controllers thin
    • Move business logic to services
    • Use models for data transfer
  2. Error Handling

    • Use try-catch blocks
    • Log exceptions
    • Return appropriate HTTP status codes
  3. Performance

    • Use async/await
    • Implement caching where appropriate
    • Optimize database queries
  4. Security

    • Validate input
    • Use proper authorization
    • Sanitize output

Next Steps

Need Help?

Clone this wiki locally