I've got a C# MVC application that I break up in the following way:
View -> Controller -> Service -> Repository
I use the thin controller practice with each view having a unique view model that's returned from the relevant service.
Quick Example:
View: /NewAppointment/Step1
Its controler would look like this:
public ActionResult Step1()
{
return View(_appointmentService.Step1GetModel() );
}
And the appointment service layer would look like this:
public Step1Model Step1GetModel()
{
return new Step1Model();
}
Thus I have several different service layers in use through out my application, each implementing a distinct interface.
My question comes in when I need to have one service layer interact with another service layer. In this case, is it better practice to pass an interface reference to the service call, or should I let the controller handle collecting all the data and then pass the relevant results back to the service?
Example:
Say I want to populate my view model with the customer's information by default. The two ways I see of doing this are:
Pass an customer interface reference to the appointment service, and then let the appointment service call the appropriate GetCustomer method in the customer service...
In Code:
private ICustomerService _customerService;
private IAppointmentService _appointmentService;
public ActionResult Step1()
{
var viewModel = _appointmentService.Step1GetModel( _customerService );
return View(viewModel);
}
OR
Let the controller handle the logic of getting the customer, then pass that result to the appointment service.
In Code:
private ICustomerService _customerService;
private IAppointmentService _appointmentService;
public ActionResult Step1()
{
var customer = _customerService.GetCustomer();
var viewModel = _appointmentService.Step1GetModel( customer );
return View(viewModel);
}
I'm torn as to which would be better practice. The first keeps the controller nice and thin, but creates an inter-service dependency between the appointment service and the customer service. The second puts more logic into the controller, but keeps the services totally independent.
Anyone have thoughts as to which would be better practice?
Thanks~
Thinking about his purely conceptually I don't think it makes sense for your services to know anything about your view models. One of the main reasons to have a controller in the first place is to separate out your view logic from your business logic, but if your services are returning view specific data then they're inherently tied to your business logic.
Ideally I'd expect the method to look like this:
public ActionResult Step1()
{
var customer = _customerService.GetCustomer();
var appointment = _appointmentService.GetAppointmentFor(customer);
var viewModel = new Step1ViewModel(customer, appointment);
return View(viewModel);
}
To answer your question more directly though, I think it's fine for your services to know about each other, they're part of the same conceptually layer.
Also, one more thing...
It sounds like you have a lot of parallel class hierarchies what with having services, repositories and controllers. It might make more sense to use something like the unit of work pattern and a powerful ORM to do something like:
public MyController(IUnitOfWork unitOfWork)...
public ActionResult Step1()
{
var customer = unitOfWork.Find<Customer>();
var viewModel = new Step1ViewModel(customer.Appointment);
return View(viewModel);
}
After all, the value of your application is in the model, not in the services.
Related
My project got Web API Controller, Services and Repositories. Controller got an Update method like:
public IActionResult Update(CreateCollaboratorViewModel collaboratorViewModel)
{
//Is it good to set values here in Controller or in Service layer ?
AdminCollaborators collaborator = new AdminCollaborators();
collaborator.Description = collaboratorViewModel.Description;
collaborator.ModifiedBy = _myContext.CurrentUserId;
var output = _collaboratorService.UpdateCollaborator(collaborator, _myContext.CurrentUserId);
return Ok(new WebApiResultValue(true, output, "update successful."));
}
Service
public AdminCollaborators UpdateCollaborator(AdminCollaborators collaborator, Guid actorUserId)
{
collaborator.ModifiedBy = actorUserId;
collaborator.ModifiedOn = DateTimeHelper.Instance.GetCurrentDate();
_collaboratorRepository.UpdateCollaborator(collaborator,actorUserId);
return _collaborationRepository.SaveChanges();
}
Normally Services are supposed to implement business logic (if im not wrong). Please advice should I update the properties values in Controller or Services.
Thanks
This is a common result of implementing DDD-ish architctures. When domains are too simple, you end up with many layers doing the same thing with more or less level of abstraction each one.
BTW, you go this route because you've determined that some day you'll want to be able to put more complicated things in the right place. Otherwise, you would need to do a massive refactor to turn a non-layered project into a n-layered one.
Anyway, updates should be done in the service layer. Probably, your service layer should look as follows:
collaboratorService.Update(collaboratorId, updateCollaboratorDto);
Where updateCollaboratorDto should be a DTO which should come with the data you want to update on your domain object.
As of the mapping betweeen a DTO and domain object, you should use AutoMapper to map them all automatically.
Note that you're in a WebAPI/RESTful API world and you're talking about view models. I would rename them replacing the ViewModel sufix to Dto.
I'm trying to build a simple MVC application with VS and Entity Framework, i have few questions.
I want to add some default values to my model, i can do that by
including default values to constructor like this:
public Worker()
{
WorkerActive = true;
}
But default controller code is like this, and it's not returning anything
public ActionResult Create()
{
return View();
}
If i change that to this, it works but i'm not sure if i'm doing something wrong:
public ActionResult Create()
{
return View(new Worker());
}
Are there any problems here?
I have a combobox with all workers in it, i want to show some
records based on the selection. For example, i want to show all
records where WorkerId=ComboboxValue. I can do this easily
by using this:
workers = m.Workers.Where(w => w.BranchId == curUser.BranchId).ToList<Worker>();
But it's in a view. Is using
statements like where in view a bad practice? I can add a new method
to controller like getUsersByBranch(BranchId) and use that.
What's the right way to do it?
Thanks
1) I'd argue that your models should be as stupid as possible, just properties and metadata. Your controller can certainly have logic in it to manipulate the model, though. That's what it's for - to return the model to the view, however you see fit:
public ActionResult Create()
{
var model = new Worker { WorkerActive = true };
return View(model);
}
Plus, you won't have to worry about needing different default values in a different controller.
2) The view is 'supposed' to be pretty dumb too. But as with all best practices, it really comes down to the overhead of refactoring and the potential gain. No, that code probably shouldn't be in your view. Ideally, if it's required by the view, it'd be a property of some sort on your model, that you controller has set up.
The logic with the 'best practice' of simple views is that it can get overly convoluted very quickly if you keep doing this, leading to spaghetti code. But like I said, you should try things and see if you like them sometimes, instead of simply going along blindly with best practices.
by 'property on your model' I mean:
public class CreateModel
{
public List<User> UsersInBranch { get; set; }
}
then your controller can fill it in, like above. Keeps your view cleaner, and lets the controller perform it's intended functionality. With MVC and Razor, logic in your view is not really in your view (in my mind), because it's still running server side. It feels like mixing server and client side operations to me.
public ActionResult Create()
{
return View(new Worker());
}
No problems in here, but Worker is a Entity? Maybe you should separate infrastructure (ef mapping) code from presentation (mvc).
workers = m.Workers.Where(w => w.BranchId == curUser.BranchId).ToList<Worker>();
Don't do this in your View. It would be better if you move this code to repository. Take a look at the good paper from Martin Fowler about this pattern:
http://martinfowler.com/eaaCatalog/repository.html
So is next example of Controller valid? Or logic like this should be somewhere else?
As i understand we need to use DTO to transfer data between layers, so if we pass JsonResult or ViewModel from BussinesLogic layer, it will mistake?
Then this example right, and logic dedicated to ViewModel creating can be in controller?
[HttpPost]
[ValidateAntiForgeryToken]
public JsonResult UploadImage(HttpPostedFileBase file)
{
var result = UploadedImageHandler.UploadFile(file);
JsonResult json;
if (result != null)
{
var uploadImageViewModel = new UploadedImagesViewModel
{
foo = result.foo
//here some values from result goes to ViewModel
};
var uploadResult = new UploadResultViewModel
{
Preview = new PreviewViewModel
{
bar = result.bar
//etc.
},
UploadedImage = uploadImageViewModel
};
json = new JsonResult
{
Data = uploadResult,
ContentType = "text/html"
};
}
else
{
json = new JsonResult
{
ContentType = "text/html"
};
}
return json;
}
Looks correct to me.
Both ViewResult and JsonResult are things specific to the presentation layer, not the actual business logic, and thus rightfully belong in the controller.
Some additional (theoretical) food for thought: Technically, under pure MVC principles, the controller is not even supposed to be aware what kind of view it is rendering (json or html), and that part is technically supposed to be handled by another MVC Action Filter. But in most real-world scenarios (in the .NET world) this kind of patter is very rarely used, and what you have above is most common (hence we even have stuff like JsonResult, etc). So it is arguably not very important. Even if you were to architect it that way, however, that Action Filter would still be in the web layer (MVC project), not in the business layer.
But yes, any logic dedicated to ViewModels should always be in the controller (the "web"/presentation layer) and never in the business layer. The business layer should not even be aware that ViewModels exist (in an ideal case, the business layer would be a separate assembly completely unaware of your Web MVC assembly, and wouldn't even see those classes). From the business layer, you would then pass back a "business object" (also known as a "domain" object), which you would then convert into a ViewModel (which is specific only to the presentation) inside your controller and pass that into the view.
Which of the following is the correct, or at least the best one:
Create a method to retrieve data in controller:
public ActionResult Index()
{
var list = _context.MyClass.Take(10);
return View(list);
}
or use context directly:
public ActionResult Index()
{
var list = MyClass.MethodWrapperToGet(10);
return View(list);
}
My concern with the first is that the database is too exposed; making it too easy for developers to misuse.
It really depends on the size of your project. For something small or a quick prototype I'd go with the option where controllers access the DbContext directly.
public ActionResult Index()
{
var list = _context.MyClass.Take(10);
return View(list);
}
I personally prefer separating concerts. In other words, I would create a service class that hands the controller exactly the data that it needs. Remember that the Controller should not know how to execute tasks but instead what needs to be executed after what.
This of course, does not mean you have to implement the repository pattern. Your service class could access the DbContext directly if you would like to.
Ideally you use a variation of exposing _context where you could pass that context through Dependency Injection so you can Unit Test your controller.
Static calls are very hard to test, at least in .Net
I am doing big project in Web Forms and entered a big mess of code(can be solved with little refactoring), so I decided to take a peek at mvc, seems like everyone favores it over web forms.
I have dll file with all LINQ to SQL classes and methods for existing sql db and I started teaching myself by reacreating this project in mvc.I first recreated my homepage from webforms to razor, so far so good and I recreated one of the user controls to partial view and looped it.
Partial view is strongly typed with one of L2S class, the thing is there is some raw data in it.Like for example My model for partial view is my L2S class PostDetails: it consist od some data ready from output like: Title, Permalink, ViewsNumber etc. but it also cointains some raw data like UserId(I need to call method from dll to get username),DateTimeCreated(on which I also need to call method to get time difference), In webforms I would do this in codebehind but I'm not sure where to do it in mvc, maybe in controller and pass it in ViewData.I am also asking this for future, not just this case.
You should perform those actions in the controller. The controller is exactly what it sounds like, it controls the data flow between the model and the view.
Here is an example using your PostDetails:
PostDetailsModel
String Title {get;set;}
String Permalink {get;set;}
Int ViewNumber {get;set}
Int UserId {get;set}
DateTime DateTimeCreated {get;set;}
GetDetailsView: this will be requested by your user, and will be a visual representation of the PostDetailsModel (however you want to format that). When this View is requested, a call is made to your controller....
PostDetailsController
//This method will (by default) come from calling [BASEURL]/PostDetails/GetDetails
public ActionResult GetDetails()
{
var details = new PostDetailsModel();
details.UserId = GetUserId();
details.ViewNumber = GetViewNumber();
....
//By default this looks for a view in the PostDetails folder
//by the name of your method (GetDetails)
return View(details);
}
Notice how the controller is the router between the model and the view, basically. A note, however, it would be better to fill your model from methods contained within some sort of business layer (however you implement that). Something like var details = BL.GetDetails();
Also, when the user makes requests to save data, then you can do that with another method that takes the data (whether it be the PostDetailsModel or an int or...) and does whatever it needs to do, then it can redirect back to the display action (or wherever you need it to go)
There is a wealth of information on MVC with a simple google search. Here is Microsoft's overview, but the wikipedia article is very succinct if you just want the basics
In MVC, All your requests will be handled by an action method in a controller. and then controller returns a view. So you can get the data in your controller (or a different layer which will be called from the controller) and pass that data to your view.
Strongly typed views are a clean way of doing things. Create a ViewModel for your scenario. Mostly ViewModels looks similar to the Entities. Ex : For Displaying the details about a customer, i will create a viewModel called "CustomerViewModel"
public class CustomerViewModel
{
public string CustomerId { set;get;}
public string FirstName { set;get;}
}
Then in my CustomerController, I will have a get method for the customer
public class CustomersController : Controller
{
public ActionResult Details(int id)
{
CustomerViewModel objCustomer=new CustomerViewModel;
objCustomer.FirstName="Samuel";
//Instead of hardcoding the values here , you can get it
// from the database using the id and assign to the properties
return View(objCustomer);
}
}
And you will have a view called "Details.chtml" in your Views\Customer
folder which is strongly typed to your CustomerViewModel
#model CustomerViewModel
<div>
<h2>#Model.FirstName</h2>
<p>#Model.CustomerId</h2>
</div>
This can be accessed like http://yourdomain.com/Customer/Details/25
Personally i prefer to keep my controller actions thin. so i write the GetFromDatabase code in a seperate service layer and i just call that method from my action method
I think that you'll find this article very useful:
MVC Overview
It explains in detail, as to what each component should be used for:
Models. Model objects are the parts of the application that implement
the logic for the application s data domain. Often, model objects
retrieve and store model state in a database. For example, a Product
object might retrieve information from a database, operate on it, and
then write updated information back to a Products table in SQL Server.
Views. Views are the components that display the application s user
interface (UI). Typically, this UI is created from the model data. An
example would be an edit view of a Products table that displays text
boxes, drop-down lists, and check boxes based on the current state of
a Products object.
Controllers. Controllers are the components that handle user
interaction, work with the model, and ultimately select a view to
render that displays UI. In an MVC application, the view only displays
information; the controller handles and responds to user input and
interaction. For example, the controller handles query-string values,
and passes these values to the model, which in turn queries the
database by using the values.