Using asp net mvc what's the best practice for creating an action that allows to create a new project whose owner is the current logged user?
// Entities
class User {
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}
class Project {
[Key]
public int Id { get; set; }
public string Name { get; set; }
[Required]
public int OwnerId;
[ForeignKey("OwnerId")]
public User Owner? { get; set; }
}
// DTO / ModeView
class ProjectModelView {
public string Name;
}
class ProjectController : Controller {
private readonly ApplicationDbContext _context;
public ProjectController(ApplicationDbContext context) {
_context = context;
}
public IActionResult Create([Bind("Name")] Project project) {
return View();
}
// 1. Using the model directly
[HttpPost]
public IActionResult Create([Bind("Name")] Project project) {
project.Owner = Session.UserId;
if (ModelState.IsValid) {
_context.Projects.Add(project);
_context.SaveChanges();
return RedirectToAction(actionName: "Index");
}
return View(project);
}
// 2. Using a dto/model view (not sure if this is considerer a model view in this case)
[HttpPost]
public IActionResult Create(ProjectModelView project) {
if (ModelState.IsValid) {
_context.Projects.Add(new Project {
OwnerId = User,
Name = project.name
});
_context.SaveChanges();
return RedirectToAction(actionName: "Index");
}
return View(project);
}
}
I looked up the asp .net documentation and I couldn't find a correct answer.
Which is more "ASP like" and correct option? Is there better ways to do it? Also, is the dto a ViewModel in this case?
CodePudding user response:
I can suggest you this improvements, hope it helps:
- Do not inject your db context into controllers - it is bad practise. What if your controller's methods will contain a lot of logic? And what if two controllers has similar methods with similar algorithm? You can add MediatR library with commands and handlers, and in handlers you can use you db context logic. Example: https://medium.com/dotnet-hub/use-mediatr-in-asp-net-or-asp-net-core-cqrs-and-mediator-in-dotnet-how-to-use-mediatr-cqrs-aspnetcore-5076e2f2880c
- No dto is not view class, you should split domain objects and view objects, you can look to Mapper Example: https://code-maze.com/automapper-net-core/
- About your question: Check the actor role: https://www.syncfusion.com/succinctly-free-ebooks/akka-net-succinctly/actors-in-asp-net-core
However I'm not sure that your question are still exists when you do a little refactoring from 1 and 2
CodePudding user response:
I use the Repository/Service pattern
, togeter with N-tier architecture
.
N-tier architecture
looks like this
ProjectName.Web/Server
, depending if youre making like an mvc application
, then its .Web
, if just a web api
, then .Server
This is the main project with controllers, automapper, views
etc.
Then three class libraries projects
ProjectName.Business
, this projects is used to store most of the helper
logic and diffrent kind of business logic
for your application, also the DTOs
or ViewModels
ProjectName.DataAccess
, data access is the project with the direct connection to the database
, this is the place where I use my repository folder
with the context
method, like put, get, post
etc. Also the DbContext
ProjectName.Models
, this project is pretty simple, it is just used for all the entities/models
you're going to use
So how is all this connected?
The projects need project references.
This is how it will go
.Models
> .DataAccess
> .Business
> .Web/Server
It goes from the bottom to the top, with the Web/Server project
as the top since this is the real application.
So how do I implement the repository pattern
into the N-Tier architecture
?
I Create a Repository folder
in the .DataAccess project.
Inside the repository create the files, for exempel if you have a model and controller
called EmployeeController.cs
and Employee.cs
Then inside the Repository folder
, to keep it clean - create a sub folder, simply called Employee
. Inside the Employee folder
, create 2 files.
EmployeeRepository.cs
and IEmployeeRepository.cs
Inside the EmployeeRepository
you need a reference to IEmployeeRepository
so your functions and methods will be available to other files.
And then just create all the context logic in the repository files.
To keep another layer between the .Web/Server
project and the database, I Create a folder inside of the .Business project
, called Service
. This is the same principle as the Repository
, create a sub folder called Employee
, with EmployeeService.cs
and IEmployeeService.cs
, call all of the methods from the repository to the service, and then you call the service methods from the IEmployeeService
to the EmployeeController
inside of the .Web/Server
project, using dependency injection
.
And there you have it, complete isolation from the dbcontext in the controllers.