-
-
Notifications
You must be signed in to change notification settings - Fork 225
Modules
Huy Nguyen edited this page Apr 5, 2025
·
2 revisions
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.
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
-
Use the Mixcore CLI to create a new module:
dotnet new mixcore-module -n MyModule
-
The CLI will create the basic structure and necessary files.
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 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 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 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 are used for rendering UI:
@model MyModule.Models.MyViewModel
<div class="container">
<h1>@Model.DisplayName</h1>
<p>@Model.Summary</p>
</div>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");
}
}Configure your module in appsettings.json:
{
"MyModule": {
"Setting1": "Value1",
"Setting2": "Value2"
}
}Declare dependencies on other modules:
[ModuleDependency(typeof(OtherModule))]
public class Module : IModule
{
// Module implementation
}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);
}
}-
Separation of Concerns
- Keep controllers thin
- Move business logic to services
- Use models for data transfer
-
Error Handling
- Use try-catch blocks
- Log exceptions
- Return appropriate HTTP status codes
-
Performance
- Use async/await
- Implement caching where appropriate
- Optimize database queries
-
Security
- Validate input
- Use proper authorization
- Sanitize output
- Visit our Community Forum
- Check the Troubleshooting Guide
- Contact Support for enterprise assistance