Skip to content
GholamReza Rabbal edited this page Feb 13, 2019 · 1 revision

Implement CRUD ASP.NET Core API


Install following packages

PM>Install-Package DNTFrameworkCore
PM>Install-Package DNTFrameworkCore.EntityFramework
PM>Install-Package DNTFrameworkCore.Web
PM>Install-Package DNTFrameworkCore.Web.EntityFramework

Create new entity

public class Task : TrackableEntity<int>, IAggregateRoot, INumberedEntity
{
    public const int MaxTitleLength = 256;
    public const int MaxDescriptionLength = 1024;

    public string Title { get; set; }
    public string NormalizedTitle { get; set; }
    public string Number { get; set; }
    public string Description { get; set; }
    public TaskState State { get; set; } = TaskState.Todo;
    public byte[] RowVersion { get; set; }
}

this entity marked as TrackableEntity,IAggregateRoot and INumberedEntity that I'll explain them in separate wiki page.

Implement ProjectDbContext that inherited from DbContextCore

public class ProjectDbContext : DbContextCore
{
    public ProjectDbContext(DbContextCoreDependency<ProjectDbContext> dependency) : base(dependency)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.ApplyConfiguration(new TaskConfiguration());

        base.OnModelCreating(modelBuilder);
    }

    protected override void AfterSaveChanges(SaveChangeContext context)
    {
        //if you are using https://github.com/VahidN/EFSecondLevelCache.Core as SecondLevelCache library
        this.GetService<IEFCacheServiceProvider>()
            .InvalidateCacheDependencies(context.ChangedEntityNames.ToArray());
    }
}

Create Model(s)/DTO(s)

[LocalizationResource(Name = "SharedResource", Location = "DNTFrameworkCore.TestAPI")]
public class TaskModel : MasterModel<int>, IValidatableObject
{
    public string Title { get; set; }

    [MaxLength(50, ErrorMessage = "Validation from DataAnnotations")]
    public string Number { get; set; }

    public string Description { get; set; }
    public TaskState State { get; set; } = TaskState.Todo;

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Title == "IValidatableObject")
        {
            yield return new ValidationResult("Validation from IValidatableObject");
        }
    }
}

Based-on validation infrastructure, you can validate Model/DTO with various approach, using by DataAnnotation ValidateAttribute, Implementing IValidatableObject or Implement IModelValidator that exist in DNTFrameworkCore package. Also in most cases, one Model/DTO can be enough for your requirements about Create/Edit/View an entity. However you can create ReadModel like below:

public class TaskReadModel : MasterModel<int>
{
    public string Title { get; set; }
    public string Number { get; set; }
    public TaskState State { get; set; } = TaskState.Todo;
}

Implement Service

public interface ITaskService : ICrudService<int, TaskReadModel, TaskModel, TaskFilteredPagedQueryModel>
{
}

public class TaskService : CrudService<Task, int, TaskReadModel, TaskModel, TaskFilteredPagedQueryModel>,
    ITaskService
{
    private readonly IMapper _mapper;

    public TaskService(CrudServiceDependency dependency, IMapper mapper) : base(dependency)
    {
        _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
    }

    protected override IQueryable<TaskReadModel> BuildReadQuery(TaskFilteredPagedQueryModel model)
    {
        return EntitySet.AsNoTracking().WhereIf(model.State.HasValue, t => t.State == model.State)
            .Select(t => new TaskReadModel
            {
                Id = t.Id,
                RowVersion = t.RowVersion,
                State = t.State,
                Title = t.Title,
                Number = t.Number
            });
    }

    protected override Task MapToEntity(TaskModel model)
    {
        return _mapper.Map<Task>(model);
    }

    protected override TaskModel MapToModel(Task entity)
    {
        return _mapper.Map<TaskModel>(entity);
    }
}

In DNTFrameworkCore.EntityFramework there is no dependency to AutoMapper or other mapper libraries, then you can do mapping between Entity and Model manually by implementing MapToModel and MapToEntity abstract methods.

Implement API Controller

[Route("api/[controller]")]
public class
    TasksController : CrudController<ITaskService, int, TaskReadModel, TaskModel, TaskFilteredPagedQueryModel>
{
    public TasksController(ITaskService service) : base(service)
    {
    }

    protected override string CreatePermissionName => PermissionNames.Tasks_Create;
    protected override string EditPermissionName => PermissionNames.Tasks_Edit;
    protected override string ViewPermissionName => PermissionNames.Tasks_View;
    protected override string DeletePermissionName => PermissionNames.Tasks_Delete;
}

Now you can run DNTFrameworkCore.TestAPI ASP.NET Core project and test TasksController.

Clone this wiki locally