How to avoid placing domain logic in controller? - c#

On PRO ASP.NET MVC book:
It is certainly possible to put domain
logic into a controller, even though
you shouldn’t, just because it seems
expedient at some pressured moment.
Just a contrived example, if the application doesn't allow negative order, where to put the changing of quantity to 1? If we follow the principle that domain logic shouldn't be placed in controller, this is certainly not advisable to use:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult PlaceOrder(Order order)
{
if (ModelState.IsValid)
{
order.Submit();
return View("Thanks", order);
}
else
{
if (order.Quantity <= 0)
{
ModelState.Remove("Quantity");
order.Quantity = 1;
}
return View(order);
}
}
So the following code is the right code that adheres to MVC principle, i.e. it follows separation of concerns, if it's domain logic you should not see its code in controllers. So this is how I tried placing the domain logic in Model:
public class Order : IDataErrorInfo
{
public int OrderId { set; get; }
public int ProductId { set; get; }
public int Quantity { set; get; }
public string Error { get { return null; } }
public string this[string propName]
{
get
{
if (propName == "Quantity" && Quantity <= 0)
{
Quantity = 1;
return "0 or negative quantity not allowed, changed it to 1";
}
else
return null;
}
}
}
Controller (sans the domain logic):
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult PlaceOrder(Order order)
{
if (ModelState.IsValid)
{
order.Submit();
return View("Thanks", order);
}
else
{
// Response.Write(order.Quantity.ToString()); // this was changed in Model
return View(order); // but the View didn't reflect that fact
}
}
The only problem with that approach, the Model(Order) can't influence the ModelState, and such, the program always display whatever is last entered by the user.
What's the best approach so I can still avoid placing domain logic in controller and the View is still able to reflect the values of Model's properties?

Validation is not controllers task. You can Put all required logic in different module, and just propogate requests there.

Ah, but the business layer can influence model state. Check out this tutorial on validating with a service layer. It's also a great intro to repository and Inversion of Control.
The general approach is to create a wrapper for the model state that implements a simple interface for adding errors to the model state. Your business layer acts against the interface - thus it has no ties to your modelstate. Your unit tests can implement a fake wrapper that also implements that same interface.
It looks like your specific example is changing the user's invalid input to valid input. My suggestion would be to simply leave the invalid input and use AddModelError to reflect that when the controller returns the view.

Related

MVC - data calculations best practice - viewmodel vs. controller

rI need some advice on where to run a calculation on data.
I have a viewmodel that contains all the fields that I need for my calculation and I created the following for one of my calculations:
public class CommissionVM
{
public int? LoanAmountLock { get; set; } // from loan table
public decimal BranchRev { get; set; } // from revenue table
public decimal BranchProcessFee { get; set; } // from revenue table
public decimal BranchGrossTotal
{
get
{
return Convert.ToDecimal(LoanAmountLock * (BranchRev/ 100) + BranchProcessFee);
}
}
}
I tried to use the Model.BranchGrossTotal in my view, but it is returning 0. I think I have an order-of-operations problem. The values LoanAmountLock, BranchRev, and BranchProcessFee are returned as the results of a query:
public ActionResult Reconcile(int? id, string RevenueLoanType)
{
var model = new CommissionVM()
{
Loan = db.Loan.FirstOrDefault(a => a.id == id ),
BranchRevenues = db.BranchRevenues.FirstOrDefault(a => a.RevenueLoanType == RevenueLoanType),
};
return View(model);
}
I originally was able to get these calculations to work by doing all the math in the controller after I populate the viewmodel with the query, but there will be about 10 calculations, and from what I understand, I shouldn't clutter up my controller with business logic.
What is the best solution for this? Do I need to create another class for the calculations? If so, how do I populate that class with my data and use it in my controller?
EDIT: I am not sure how to set up the business classes and use them in the controller. Can anyone point me in the direction of a tutorial?
You should not do the calculation in your controller nor in your view model. You should do it in the Business Layer. Think about View Models are really simple classes that contain data to be displayed to the user, that's it.
Regarding the calculation, you should convert one of the terms to decimal, not the result of the calculation. If you divide integers, you get an integer.
You could create a class and call it CommissionService for example. That class should call your Data Layer to get the data, do any extra calculation and return the data (maybe a DTO) to the controller. The controller should create View Models based on the DTO and send them to the view.
Read these articles:
1) https://msdn.microsoft.com/en-us/library/hh404093.aspx
2) http://www.asp.net/mvc/overview/older-versions-1/models-%28data%29/validating-with-a-service-layer-cs
3) http://blog.diatomenterprises.com/asp-net-mvc-business-logic-as-a-separate-layer/
4) http://sampathloku.blogspot.com.ar/2012/10/how-to-use-viewmodel-with-aspnet-mvc.html
I don't like calculations on my view models -- you can't reuse the calculation easily elsewhere and it is harder to test and debug. Create separate classes to do business logic.
Your business logic classes can either return your view models or return values you use to populate those models. The trade-off is ease of use with reusability.
I generally favor returning the value rather than a big object so my services are more reusable.
Controller
public class BranchController : Controller
{
private IBusinessService service;
public BranchController()
{
this.service = new BusinessService(db);
}
public ActionResult Reconcile(int? id, string RevenueLoanType)
{
var model = new CommissionVM
{
BranchGrossTotal = this.service.GetBranchGrossTotal(id, RevenueLoanType),
...
};
return View(model);
}
}
Service
You can make any number of these and your controllers would use them as needed. If you need a query you should pass the DbContext instance or you may have problems with related entities on separate contexts.
public interface IBusinessService
{
decimal GetBranchGrossTotal(int id, string revenueLoanType);
}
public class BusinessService : IBusinessService
{
private DbContext db;
public BusinessService(DbContext db)
{
this.db = db;
}
public decimal GetBranchGrossTotal(int id, string revenueLoanType)
{
var branch = db.Branch.First(b => b.Id == id);
// do stuff
return total;
}
}
You could fully-populate and return a view model in your GetBranchGrossTotal() if you choose.
First of all, the properties you are assigning to your CommissionVM on your controller do not match the ones declared on your model. You assign Loan and BranchRevenues, when you have only LoanAmountLock and BranchRevs available on your model.
Please notice that the Loan property is an object itself, and the LoanAmountLock must be retrieved from this object (Loan.LoanAmountLock). The same happens with the BranchRevenues object. You should assign the BranchRevs to the respective property of the BranchRevenues object as needed. If you do not do this, then the values will default to 0 and when trying to calculate the BranchGrossTotal it will obviously be 0.
Another reason, assuming that you are correctly populating your model properties, is that the FirstOrDefault method, renders null values because there is no such entity. This will result also in the BranchGrossTotal to be 0.
You are right that you do not need to clutter your controller neither with calculations nor with db access. I would create a business class ComissionBusiness and instantiate it at the top of your controller. This class would have a method which performs all calculations. You should move the Reconcile method to your new business class method and call it on the reconcile action. Something like (excuse the lack of syntax)
public MyController : Controller {
public ComissionBusiness comissionBusiness;
public MyController(){
comissionBusiness = new ComissionBusiness();
}
public ActionResult Reconcile(int? id, string RevenueLoanType)
{
var model = comissionBusiness.Reconcile(id, revenueLoanType);
return View(model);
}
}

When should I write code in the controller vs. model?

Without a doubt I know what the controllers and models are used for. However, I am able to write code that interacts with my db, for example adding users to a table, on either the controller or model. At what times should I write code in the controller vs. in model? Even though both work, what would be a more organized or practical way. Could you please post examples if the answer is ambiguous?Thx
For that, you should add a logic layer or logic classes. The controller should determine wants to do and can do, shuffle them in the right direction (logic layer), then determine what to show the user after the logic. Putting the logic in a separate layer will help keep your controllers lean and promote code reuse.
In the domain core, we only have models with properties. All logic is performed in a different layer, except for things like a property that returns fields concatenated in a format.
Code to access the database should be in service layer instead of keeping in Controller or Model.
Accessing Database Entities from Controller
Here is my answer for the above question, you can also read others answers why you should keep in separate layer.
namespace MyProject.Web.Controllers
{
public class MyController : Controller
{
private readonly IKittenService _kittenService ;
public MyController(IKittenService kittenService)
{
_kittenService = kittenService;
}
public ActionResult Kittens()
{
// var result = _kittenService.GetLatestKittens(10);
// Return something.
}
}
}
namespace MyProject.Domain.Kittens
{
public class Kitten
{
public string Name {get; set; }
public string Url {get; set; }
}
}
namespace MyProject.Services.KittenService
{
public interface IKittenService
{
IEnumerable<Kitten> GetLatestKittens(int fluffinessIndex=10);
}
}
namespace MyProject.Services.KittenService
{
public class KittenService : IKittenService
{
public IEnumerable<Kitten> GetLatestKittens(int fluffinessIndex=10)
{
using(var db = new KittenEntities())
{
return db.Kittens // this explicit query is here
.Where(kitten=>kitten.fluffiness > 10)
.Select(kitten=>new {
Name=kitten.name,
Url=kitten.imageUrl
}).Take(10);
}
}
}
}
ASP.NET MVC and MVC, in general, is a presentation layer pattern; thus your interaction with the database should be in a layer beyond the presentation layer, usually a data-access layer, but it could be a service layer or business layer as well.

Is this an MVC anti-pattern?

I’m very new to any kind of .NET web development (thus far I’ve worked primarily with Winforms and services.) I’ve started to work on an existing MVC3 project with two other developers. I’m conceptually familiar with MVC, and am trying to catch up on how it’s used in this project.
We have an AccountDto class to represent Accounts. There is a Response class that is inherited by another class for each Entity, i.e. AccountResponse:
public class Response
{
[DataMember]
public bool IsSuccess{get;set;}
[DataMember]
public string DisplayMessage { get; set; }
[DataMember]
public string DetailedMessage { get; set; }
[DataMember]
public ErrorType ErrorType { get; set; }
public Response(){
this.IsSuccess=true;
this.ErrorType = ErrorType.None;
}
}
public partial class AccountResponse : Response
{
[DataMember]
public IList<AccountDto> AccountList { get; set; }
}
There’s an AccountService which will return an AccountResponse to the Controller, with a list of the AccountDto object:
public AccountResponse GetAccountByAccountId(Int64 accountId)
{
_logger.Info("Executing GetAccountByAccountId()");
AccountResponse response = new AccountResponse();
try
{
Account item = AccountPersistence.GetAccountByAccountId(accountId);
AccountDto dto = Mapper.Map<AccountDto>(item);
response.AccountList = new List<AccountDto>() { dto };
response.IsSuccess = true;
}
catch (Exception ex)
{
response.IsSuccess = false;
response.ErrorType = ErrorType.GeneralFault;
response.DetailedMessage = ex.ExceptionMessageBuilder();
response.DisplayMessage = "System Failure: Failed to get Account by AccountId";
_logger.Error(ex);
}
return response;
}
I was told the Response thing is implemented to be able to handle success/failure messages. So in a controller, there’s code like the following (doesn’t happen to do anything special if a failure):
public ActionResult ToBeCalled(int id)
{
AccountDto dto = null;
var response = _accountService.GetAccountByAccountId(Convert.ToInt64(id));
if (response.IsSuccess)
{
dto = response.AccountList[0];
return View(dto);
}
return View(dto);
}
This made sense to me though I wasn’t sure where the success/error messages were going to be utilized. However, they now want to switch from using the DTO in views to using the Response, so success/failure will have to be handled in the views:
public ActionResult ToBeCalled(int id)
{
var response = _accountService.GetAccountByAccountId(Convert.ToInt64(id));
return View(response);
}
This seems off to me – instead of coding against a DTO as the model, I have to do something like the following for each page:
#{
if (Model.IsSuccess)
{
var account = Model.AccountList.FirstOrDefault();
if (account != null)
{
#Html.HiddenFor(x => account.AccountNumber)
}
}
The controllers’ ActionResult / HttpPost methods then have to also parse the DTO from these Response objects. This seems like an anti-pattern to me; are approaches like this normal?
Apologies if this is too lengthy, please migrate if it belongs on Code Review or another site.
I agree with you that this would be an anti-pattern. The View is supposed to be quite ignorant, especially of logic like this.
I can see why this would be tempting, if the difference between success and failure is a minor part of the UI, but imagine if that were to change. A view has little ability (without unnecessary nesting of partials) to switch to an entirely different view. It has no ability to issue a redirect or other error codes. In the event that you decide to change your UI, you may have to go back and rewrite your Controller yet again.
If the reasoning behind moving the logic to the view was to remove the response.IsSuccess logic from the Controller (and to be honest, that seems fine to me; it's pretty much the same as the classic Model.IsValid), you could consider another approach: refactor your Response class to inherit from ActionResult. Then you could move that logic into the ExecuteResult() method and it would be separate from your Controller.
Just use the coalesce operator and you can get rid of a whole lot of cruft (like that strange Response base class (which should be marked abstract if it continues to exist)) and avoid null-checking.
public ActionResult ToBeCalled(int id)
{
var response = _accountService.GetAccountByAccountId(id) ??
new AccountResponse();
return View(response);
}
Better yet, migrate that logic into your service class so that it guarantees return of an object (it doesn't necessarily make sense for a repository to do this when there's no backing entity, but it does for a service).
Either way, you don't need to include unsightly null-checking or if/else logic on your view. Move as much logic to places that you can test it as you can and you'll be happier.

Why controllers run first in the ASP.NET MVC?

I want to improve current implementation of the ASP.NET MVC Framework.
Current code:
routes.MapRoute(null, "I-want-to-fly", new { controller = "Airport", action = "Fly" });
public class AirportModel
{
public List<Plane> Planes { get; private set; }
public List<Pilot> Pilots { get; private set; }
public void AddFly(Plane plane, Pilot pilot, Passenger passenger)
{
// . . .
}
}
public class AirportController
{
private AirportModel model;
[HttpGet]
public ViewResult Fly(string from, string to)
{
var planes = return (from p in model.Planes
where p.CityFrom == from && p.CityTo == to
select p).ToList();
return View(planes);
}
[HttpPost]
public ActionResult Fly(Plane plane, Passenger passenger, DateTime time)
{
if (!(ModelState.IsValid && plane.TimeOfDeparture == time))
return View();
var pilot = (from p in model.Pilots
where p.Free && p.CanAviate(plane.Id)
select p).First();
model.AddFly(plane, pilot, passenger);
return RedirectToAction("Succeed");
}
}
My proposal:
routes.MapRoute(null, "I-want-to-fly", new { model = "Airport", action = "Fly" });
public class AirportModel
{
private List<Plane> planes;
private List<Pilot> pilots;
private void AddFly(Plane plane, Pilot pilot, Passenger passenger)
{
// . . .
}
[HttpGet]
public ViewResult Fly(string from, string to)
{
var planes = return (from p in model.Planes
where p.CityFrom == from && p.CityTo == to
select p).ToList();
return View(suitablePlanes);
}
[HttpPost]
public ActionResult Fly(Plane plane, Passenger passenger, DateTime time)
{
if (!(ModelState.IsValid && new PlaneController().CanFly(plane, time)))
return View();
var pilot = (from p in pilots
where p.Free && p.CanAviate(plane.Id)
select p).First();
AddFly(plane, pilot, passenger);
return RedirectToAction("Succeed");
}
}
public static class PlaneController
{
public static bool CanFly(Plane plane, DateTime time)
{
return plane.TimeOfDeparture == time; // it will be more complex
}
}
You see, in such way we don't need excessive count of controllers and their methods. Model would create controller only by perforce: mostly to verify user input (not input validation, business validation).
What do you think, can this idea have a continuation? Or, what is wrong with it?
Thanks for your replies!
UPDATE: I noticed, that we need to replace implementations of controller and view as a result of changing the model's state (mostly). So, if model causes to change the implementation, why model cannot do it?
UPDATE 2: It seems to me I explained incorrectly. I don't want model to do all work, of course no! I try to say, that not controller should decide what to do with model and what view is the most suitable for this user request.
Doesn't it strange, that model doesn't know how to visualize itself, but some controller knows?
Doesn't it strange, than we need controller for the GET request, where there is nothing to control?
I try to remove those strangenesses.
UPDATE 3: I understand that it cannot be applied anywhere. The main question is: can it improve some part of current implementations of MVC ? Mostly I'm interested in ASP.NET MVC -- can we
remove redundant controllers or some its methods
work directly with models
using this idea? Is it possible and what are the problems of this idea?
Found problems:
More strong connection between model and view/controller -- but currently I don't think it's a problem. Actually it shows that views and controllers were created in help for the major element -- model.
UPDATE 4: I changed the code, showing "before/after". Maybe this example will be better.
Doesn't this just violate the whole idea of MVC? Your model is separated from your controller and your view. In this way (the way you propose) you would not be able to replace your model by another implementation, or your controller for that matter.
updated I:
You could of course let your model do the part of the controller as well, but from that moment on you're not talking about the MVC design pattern anymore. For MVC, the model does and should not now about the view. That's the controllers job.
The controller receives user input and initiates a response by making calls on model objects. A controller accepts input from the user and instructs the model and viewport to perform actions based on that input.
In the MVC pattern, the Model isn't just fixed to your database model, it could be a combination of your database model and a repository pattern as well, where you implement your business logic.
The biggest problem I see with your proposal is that it makes code non-reusable. I get a model that is tightly coupled with it's views which I really don't want if I want to reuse the model in whatever way I might want to.
Update II
I think your are being mislead by the actual word Controller, I had that thought for a while and your latest comment sort of confirms this for me
Controllers are some objects, that check correspondence of user input to business-logic.
Controllers act upon user input, they might check the user input but their responsibility for checking validity stops there. Business logic goes in the Model (again, the Model as defined by the MVC pattern, not the model as in datamodel). Their main purpose is deciding what View to display.
Also from one of your latest comments:
How do you think, if [asp.net mvc] would be developed in my way, would it solve problem of redundant controllers?
Asp.Net MVC follows the MVC design pattern. Your proposal does not. It seem more like a ModelControlled View pattern, just to coin a name. Also, there are no redundant controllers, the controllers are no problem, they are an integral part of the solution.
And an effort to simplistically clarify what I mean with a code example:
namespace DataProject.Model
{
public class AirportModel
{
public List<Plane> Planes { get; set; }
public List<Pilot> Pilots { get; set; }
public List<Passenger> Passengers { get; set; }
public List<Flight> Flights { get; set; }
}
}
namespace SomeProject.Repository
{
public class AirportRepository
{
private DataProject.Model.AirportModel model;
//constructor sets the model somehow
public bool AddFlight(Plane plane, List<Passenger> passengers, DateTime time)
{
//Business logic
if (plane.TimeOfDeparture != time) return false;
var pilot = (from p in model.Pilots
where p.Free &&
p.CanAviate(plane.Id)
select p).FirstOrDefault();
//More Business logic
if (pilot == null) return false;
//Add plane, pilot and passenger to database
model.Flights.add(new Flight{Pilot = pilot, Plane = plane, Passengers = passengers});
//Even here you could decide to do some error handling, since you could get errors from database restrictions
model.Save();
return true;
}
public List<Planes> GetPlanes(string from, string to)
{
return (from p in model.Planes
where p.CityFrom == from && p.CityTo == to
select p).ToList();
}
}
}
namespace MVCApp.Controllers
{
public class AirportController
{
private SomeProject.Repository.AirportRepository repository;
[HttpGet]
public ViewResult Fly(string from, string to)
{
var viewModel = repository.GetPlanes(from, to);
return View(viewModel);
}
[HttpPost]
public ActionResult Fly(Plane plane, List<Passenger> passengers, DateTime time)
{
if (!ModelState.IsValid) return View();
if (!repository.AddFlight(plane, pilot, passenger)) return View();
return RedirectToAction("Succeed");
}
}
}
No offense intended but how exactly is this an improvement?
So you've made a class called a PersonModel that isn't really doing "model things" at all - it is doing the work that Controllers do - you've got it handling gets and posts and calling out for the display of Views and then you've got a static "Controller" that really controlling nothing and is concerning itself with business logic. Honestly, I don't get how this is an improvement.
A concrete example of is you've got a controller checking whether Age >= 18, which is a very "business rules" thing for a controller to be doing. That's not the purpose of a controller. That's the job of a model object - to concern itself with things like business logic. Controllers, as one person put it, are more of an electronic curator. In your example, you've relegated it to something far less than a curator.
There are distinct roles that objects play in an MVC application. Views show us stuff and provide us with ways to interact with the application. Controllers handle the input coming from the View and serve up views that are needed. Models provides a place to put data and the logic and business rules that the model encompasses. Services handle things like persisting data to some store, like a DB.
You can do everything in one class without controllers at all but you want "separte of concerns"
So the controller is responsible for the http request and validation and the model is responsible only for the data.
You are the programmer then you could agree or disagree with MVC pattern.
But the pattern which you described doesn't support the separation of concern and it breaks out the whole idea about MVC
This has nothing to do with MVC.
This is 'MVNothing'
:)
Just kidding *_^

What is the better way/place for validation?

In my asp.net mvc application i have service layer, which operated with business object, pass its to repository layer and return to controller. No i can't decide where i need to validate object. First place - use data annotation validation with attribute of component model annotation in business objects class, for example:
[AcceptVerbs("POST")]
public ActionResult Edit(Source src)
{
if(!ModelState.IsValid){
return View("EditSource", src);
_sourceService.SaveSource(src);
return RedirectToAction("Index");
}
[MetadataType(typeof(Source.MetaSource))]
public class Source
{
private class MetaSource
{
[Required]
public string Name { set; get; }
[Required]
public string Url { set; get; }
}
public int? ID { set; get; }
public string Name { set; get; }
public string Url { set; get; }
public Source()
{
ID = null;
}
Second way - validate objects in service layer, by passing validation dictionary to service layer, for example:
[AcceptVerbs("POST")]
public ActionResult Edit(Source src)
{
if (!_sourceService.ValidateSource(src)){
return View("EditSource", src);
_sourceService.SaveSource(src);
return RedirectToAction("Index");
}
public bool ValidateSource(Source srcToValidate)
{
if (string.IsNullOrEmpty(srcToValidate.Name))
_validationDictionary.AddError("Name", "Name is required.");
else
if (srcToValidate.Name.Trim().Length == 0)
_validationDictionary.AddError("Name", "Name is required.");
if (string.IsNullOrEmpty(srcToValidate.Url))
_validationDictionary.AddError("Url", "Url is required.");
else
if (srcToValidate.Url.Trim().Length == 0)
_validationDictionary.AddError("Url", "Url is required.");
return _validationDictionary.IsValid;
}
I think of create client side validation, and add localization to validation errors, also i need create custom rules with calls to database, etc. What pros and cons of this 2 way, or maybe I need choose another way ?
The asp.net website offers guidance for three cases:
Validating with a service layer
Simple validation
Using IDataErrorInfo
These are probably worth reading before making any decisions.
Definitely worth reading up on the various options - choose whichever you think best suits your needs and style.
However, you will almost certainly end up creating a validation function on your service at some point to cope with business rules, so that may be the tie-breaker :-)
Heres a few extra links which may be useful too:
xVal Validation Framework
Data Annotations Model Binder Sample

Categories