Is ViewModel creating logic count as "unprefered logic" in controller - c#

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.

Related

Best/Logical practice for properties values update (Controller or Service layer?)

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.

Questions about good practices with MVC and Entity Framework

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

Convention for actions returning multiple View Types (html, json, partials)

I am building a website in ASP.NET MVC5. In my controllers, I have some actions that return the same data but in different formats mostly Views, partial views and Json.
For example, I would have a controller which display a list of items :
// some action returning a view
public ActionResult List()
{
var model= _repository.Items.ToViewModel();
return View(model)
}
// some action returning a partial view
[ChildActionOnly]
public ActionResult ListPartial()
{
var model= _repository.Items.ToViewModel();
return PartialView("_ListPartial", model)
}
// some action returning JSON
public ActionResult GetList()
{
var model= _repository.Items.ToViewModel();
return Json(model, JsonRequestBehavior.AllowGet);
}
How can I make a clear distinction between my actions ?
What kind of conventions should be followed to keep it clean?
Should the actions co-exist in the same controller ?
I'm not sure what you mean by "make a clear distinction between my actions". From a compiler perspective, the distinction between action methods will always depend on one of two things: the name of the action and the parameters that action takes. So, you could have two actions with the same name, but different parameters, or two actions with totally different names and the same or different parameters. From a developer perspective, you can add to the previous list: return value. Personally, I can look at any of the actions you have here and clearly see what they're doing based on that, i.e. the one that returns the model encoded as JSON, is obviously a JSON result.
As far as keeping things clean goes, again, that's a somewhat loaded question. What defines "clean"? Your methods look perfectly "clean" to me as-is. You've got a bit of code duplication, but I'd consider that acceptable in this scenario. All you're doing is retrieving a model in each. One could argue for leaving such duplicate code, as potentially each method could diverge over time, retrieving more or less parts of that model or including other related entities, etc.
However, if you want to remove the code duplication, you could factor that line out into an internal method on the controller, and then have each action call that internal method. That way, if you need to modify the line, you only need to do it in one place, but of course, if you need to make a modification just for one of these actions, you're back to where you were before.
Now, to should the actions co-exist in the same controller, this is a bit subjective as well. Since, they're so closely related in functionality, with just different return values, there's an easy argument for keeping them in the same controller. However, it's equally valid to suggest moving them into different controllers so, for example, you have all your JSON returning actions together. A lot of it boils down to personal preference.
Now, all that said, in this one particular scenario, since literally the only difference is the return value depending on the methodology being used to get the action, you can actually combine all of these into one action:
public ActionResult List()
{
var model= _repository.Items.ToViewModel();
if (Request.IsAjaxRequest())
{
return Json(model, JsonRequestBehavior.AllowGet);
}
if (ControllerContext.IsChildAction)
{
return PartialView("_ListPartial", model);
}
return View(model);
}
This is possible because your action's return value of ActionResult, is a base class that all of ViewResult, PartialViewResult and JsonResult inherit from.
ActionResult is an abstract class and all other result classes are derived from that.
Instead of user ActionReault for all method use derived class name. Like JsonResult, ViewResult , PartialViewResult

Using view models in ASP.NET MVC 3

I'm relatively new to view models and I'm running into a few problems with using them. Here's one situation where I'm wondering what the best practice is...
I'm putting all the information a view needs into the view model. Here's an example -- please forgive any errors, this is coded off the top of my head.
public ActionResult Edit(int id)
{
var project = ProjectService.GetProject(id);
if (project == null)
// Something about not found, possibly a redirect to 404.
var model = new ProjectEdit();
model.MapFrom(project); // Extension method using AutoMapper.
return View(model);
}
If the screen only allows editing of one or two fields, when the view model comes back it's missing quite a bit of data (as it should be).
[HttpPost]
public ActionResult Edit(int id, ProjectEdit model)
{
var project = ProjectService.GetProject(id);
if (project == null)
// Something about not found, possibly a redirect to 404.
try
{
if (!ModelState.IsValid)
return View(model) // Won't work, view model is incomplete.
model.MapTo(project); // Extension method using AutoMapper.
ProjectService.UpdateProject(project);
// Add a message for the user to temp data.
return RedirectToAction("details", new { project.Id });
}
catch (Exception exception)
{
// Add a message for the user to temp data.
return View(model) // Won't work, view model is incomplete.
}
}
My temporary solution is to recreate the view model from scratch, repopulate it from the domain model, reapply the form data to it, then proceed as normal. But this makes the view model parameter somewhat pointless.
[HttpPost]
public ActionResult Edit(int id, ProjectEdit model)
{
var project = ProjectService.GetProject(id);
if (project == null)
// Something about not found, possibly a redirect to 404.
// Recreate the view model from scratch.
model = new ProjectEdit();
model.MapFrom(project); // Extension method using AutoMapper.
try
{
TryUpdateModel(model); // Reapply the form data.
if (!ModelState.IsValid)
return View(model) // View model is complete this time.
model.MapTo(project); // Extension method using AutoMapper.
ProjectService.UpdateProject(project);
// Add a message for the user to temp data.
return RedirectToAction("details", new { project.Id });
}
catch (Exception exception)
{
// Add a message for the user to temp data.
return View(model) // View model is complete this time.
}
}
Is there a more elegant way?
EDIT
Both answers are correct so I would award them both if I could. The nod goes to MJ however since after trial and error I find his solution to be the leanest.
I'm still able to use the helpers too, Jimmy. If I add what I need to be displayed to the view bag (or view data), like so...
ViewBag.Project= project;
I can then do the following...
#Html.LabelFor(model => ((Project)ViewData["Project"]).Name)
#Html.DisplayFor(model => ((Project)ViewData["Project"]).Name)
A bit of a hack, and it requires the domain model to be decorated with System.ComponentModel.DisplayNameAttribute in some cases, but I already do that.
I'd love to call...
#Html.LabelFor(model => ViewBag.Project.Name)
But dynamic causes a problem in expressions.
After some trial-and-error (aka code it, then hate it) learning, my currently preferred approach is:
I use view-models only to bind input fields. So in your case, if your view is only editing two fields, then your view-model will only have two properties. For the data required to populate the view (drop-down lists, labels, etc), I use the dynamic ViewBag.
I believe that displaying the view (i.e. populating anything the view needs to display), and capturing the posted form values (binding, validation, etc) are two separate concerns. And I find that mixing the data required to populate the view with that which is posted back from the view gets messy, and creates exactly your situation more often than not. I dislike partially populated objects being passed around.
I’m not sure how this plays out with Automapper (for mapping the domain object to the dynamic ViewBag) though, as I haven’t used it. I believe it has a DynamicMap method that may work? You shouldn’t have any issues auto-mapping the posted strongly-typed ViewModel onto the Domain object.
If I understand correctly, your viewmodel probably looks very similar to your domain entity. You mentioned that the viewmodel can come back mostly empty because only certain fields were editable.
Assuming you have a view where only a few fields are available for edit (or display), these are the only fields you should make available in your viewmodel. I usually create one viewmodel per view, and let either the controller or a service handle the user's input and map it back up with the domain entity after performing some validation.
Here's a thread concerning best-practices for viewmodels that you might find useful.
Edit: You can also accept a different view model in your Edit/POST action than your Edit/GET action serves up. I believe this should work as long as the model binder can figure it out.

Is passing a service reference to another service layer bad practice?

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.

Categories