# Features Overview
# A Feature
A Feature is an action that a user or client can request to the application (e.g. OrderPlace, UserList, ProductShow, OrderDiscount, etc)
# Naming
A Feature is named: {FeatureGroup}{Action}
:
Feature Group | Action | Feature Name |
---|---|---|
Orders | Place | OrderPlace |
Orders | Discount | OrderDiscount |
Products | Show | ProductShow |
# Location
Miru organizes features using Feature Folders:
Features are located in /src/{AppName}/Features/{FeatureName}.cs
Instead of group files by artifact type (e.g. Controllers, ViewModels, Views, etc), it is grouped by Feature. Every artifact related to the Feature goes inside the Feature's folder:
# Structure
A Feature is a class named after its Feature Group and Action. For example, Place an Order:
public class OrderPlace
{
}
A Feature can have many components (e.g. Query, Command, Handler, Validator, Controller, Mailable, Job, etc). All these components can be placed inside the class as subclasses:
public class OrderPlace
{
public class Command
{
}
public class Handler
{
}
public class Controller
{
}
public class Mailable
{
}
public class Query
{
}
}
# Request & Response
Every Feature must have a Request
class that represents the input data to be handled. Miru uses MediatR, which contains an IRequest
interface to represent a request.
In this example, OrderPlace doesn't return a response:
public class OrderPlace
{
public class Command : IRequest
{
}
}
When a Feature return information, the IRequest
needs to be of a TResponse
:
public class OrderShow
{
public class Query : IRequest<Result>
{
}
public class Result
{
}
}
# Feature Types
A Feature's Request can be a Query, to ask for information, or a Command, to change some information.
# Query
Query is a Request that ask the application for some data without making changes:
public class OrderShow
{
public class Query : IRequest<Result>
{
public long OrderId { get; set; }
}
}
# Command
Command is a Request that changes data in the application:
public class OrderApplyDiscount
{
public class Command
{
public long OrderId { get; set; }
public decimal Discount { get; set; }
}
}
# Mediator
The Mediator
from MediatR, is the object responsible to receive an IRequest
and find its Handler
passing through a pipeline of Behaviors
.
await _mediator.Send(new OrderPlace
{
Customer = customer,
Items = items
})
If the IRequest
returns a Response
:
var result = await _mediator.Send(new OrderShow
{
Id = orderId
})
# Handler
A Handler is an object that will process the Request:
public class OrderApplyDiscount
{
public class Command : IRequest
{
public long OrderId { get; set; }
public decimal Discount { get; set; }
}
public class Handler : IRequestHandler<Command, Unit>
{
private readonly DbContext _db;
public Handler(DbContext db)
{
_db = db;
}
public async Task<Unit> Handle(Command command, CancellationToken ct)
{
var order = await _db.Orders.ByIdAsync(command.OrderId);
order.ApplyDiscount(command.Discount);
return Unit.Value;
}
}
}
# Other Handlers
Depending of the concern and the library being used, is possible to add other Handlers. An example within Miru is Validation:
Not Found: D:\Projects\Miru/samples/Mong/src/Mong/Features/Accounts/AccountLogin.cs
# Create A Feature
A Feature can be created using miru make:feature
. It's required to choose one of these templates:
Template | Flag | Description |
---|---|---|
New | --new | Add an Entity |
Edit | --edit | Retrieve to edit an Entity |
Show | --show | Show an Entity |
List | --list | List Entities |
All above | --all | Creates new , edit , show , and list |
miru make:feature Orders Order New --new
The files that will be created depends on the template type. For example, --new
creates these files:
/src/{AppName}/Features/Orders/OrderNew.cs
/src/{AppName}/Features/Orders/New.cshtml
/src/{AppName}/Features/Orders/_New_.js.cshtml
/tests/{AppName}.Tests/Features/Orders/OrderNewTest.cs
/tests/{AppName}.PageTests/Pages/Orders/OrderNewPageTest.cs
# Create All Actions
To create at once all actions (new
, edit
, show
, list
) for a Feature, use miru make:feature:all
:
miru make:feature:all Products Product