After learning a bit about ASP.NET Core MVC, I have built a simple CRUD based web application. Although it is simple, I am now trying to learn how to make smaller controllers by moving business logic, and data access outside of the controller into their own layers. The problem is that the model binding in the controller is not easily passed to other layers.
Before moving all of the business and data access logic outside of the controller, the creation of the Entity worked. There is also a GetAll() method (not shown below), that uses the separate layers to fetch and display all entities storied in the database. But when trying to create an entity (seen below), the following error occurs:
InvalidOperationException: Could not create an instance of type 'MyProject.Models.Entity'. Model bound complex types must not be abstract or value types and must have a parameterless constructor.
How can a model binded object created from a View be passed into n-tier layers of a web application?
Entity.cs
namespace MyProject.Models
{
public enum EntityType { Type1, Type2 }
public class Entity
{
private readonly ApplicationDbContext context;
public Entity(ApplicationDbContext _context)
{
context = _context;
}
public int EntityId { get; set; }
public string Name { get; set; }
public DateTime Date1 { get; set; }
public EntityType Type { get; set; }
}
}
CreateEntityModel.cs
namespace MyProject.Models
{
public class CreateEntityModel
{
public string Name { get; set; }
public string Date1 { get; set; }
public int Type { get; set; }
}
}
Create.cshtml
@model CreateEntityModel
<h1>Create Entity</h1>
<form asp-controller="entity" asp-action="createentity" method="post">
<div class="form-group">
<label asp-for="Name"></label>
<input asp-for="Name" class="form-control" />
</div>
<div class="form-group">
<label asp-for="Date1"></label>
<input asp-for="Date1" class="form-control" />
</div>
<div class="form-group">
<label asp-for="Type"></label>
<select asp-for="Type">
<option selected>Choose entity type</option>
<option value="0">Type1</option>
<option value="1">Type2</option>
</select>
</div>
<button type="submit">Create</button>
</form>
EntityController.cs
namespace MyProject.Controllers
{
public class EntityController : Controller
{
private UserManager<ApplicationUser> userManager;
private readonly ApplicationDbContext context;
private EntityService entityService;
public EntityController(UserManager<ApplicationUser> _userManager,
ApplicationDbContext _context)
{
userManager = _userManager;
context = _context;
entityService= new EntityService (_userManager, _context);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> CreateEntity([Bind("Name, Date1, Type")] Entity entity)
{
if (ModelState.IsValid)
{
await entityService.Create(entity);
return RedirectToAction(nameof(Index));
}
return View("~/Views/MyView");
}
}
}
EntityService.cs
namespace MyProject.Business
{
public class EntityService
{
private UserManager<ApplicationUser> userManager;
private readonly ApplicationDbContext context;
private EntityRepository entityRepository;
public EntityService(
UserManager<ApplicationUser> _userManager,
ApplicationDbContext _context)
{
userManager = _userManager;
context = _context;
entityRepository = new EntityRepository(_context);
}
public async Task Create(Entity entity)
{
await entityRepository.Create(entity);
}
}
}
EntityRepository.cs
namespace MyProject.Data
{
public class EntityRepository
{
private readonly ApplicationDbContext context;
public EntityRepository(ApplicationDbContext _context)
{
context = _context;
}
public async Task Create(Entity entity)
{
context.Add(entity);
await context.SaveChangesAsync();
}
}
}