I'm writing a REST API using ASP.NET Core & Entity Framework Core. My controllers so far have minimal logic, typically deferring to a service layer that handles the usual database operations.
My API will be consumed by a Discord bot, and I want to be able to automatically register users in my database when they issue a command that would essentially end up inserting a new record into one of the database tables:
[HttpPost]
public async Task<ActionResult<recordDto>> CreateRecord(CreateRecordDto recordDto)
{
var record = new Record
{
Name = recordDto.Name,
Alias = recordDto.Alias,
UserId = recordDto.UserId,
ServerId = recordDto.ServerId,
};
try
{
await _service.CreateRecord(record);
}
catch (status.ConflictException)
{
return Conflict();
}
catch (DbUpdateException)
{
throw new Exception("Error adding record.");
}
return CreatedAtAction("Test", new { id = record.Id }, record);
}
Prior to that, however I need to check whether the user is even present in the database. That's easy, as I have another service I can use to check for that condition. However I'm hesitant to place this logic into the controller as it would increase the dependencies my controller requires, and introduce more business logic which I understand the controller shouldn't be handling. Am I over thinking my design? Where exactly should this logic be handled?
Whilst I do not know what business this API is intended for, what you're showing and describing seems more like a CRUD API. I do not see any business logic here, unless you are automating a process where a business rule is something like "A user cannot be added twice".
But this doesn't take away from your question. You worry about too many dependencies and where the correct place is this logic should be handled.
It is important to understand why there are certain rules. Developers worry that if there are too many dependencies, a class has too many responsibilities and therefore becomes inflexible, difficult to test and difficult to change. This is a valid concern, but always ask yourself if it applies to your situation; will your API ever do anything else than this? Does it, therefore, need to be flexible? The adding of an extra layer does not come for free, so a simple design could be kept simple (even when breaking the "rules").
In your case I indeed think you are overthinking your design considering the dependencies. If I could give you a tip: handle the error handling somewhere else (in a filter attribute or something), so you don't have to copy that in every endpoint. But, only if you intend to have more than one!
I have a view model which should check that label of a new entity is unique (not in DB yet).
At the moment I've done it in the view model class:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if (PowerOrDuty != null)
{
if (PowerOrDuty.Identifier == null)
{
using (var db = new PowersAndDutiesContext())
{
var existingLabels = db.PowersAndDuties.Select(pod => pod.Label);
if (existingLabels.Contains(PowerOrDuty.Label))
{
yield return new ValidationResult("Cannot create a new power or duty because another power or duty with this label already exists");
}
}
}
......
Please note that this is a small internal app with small DB and my time is limited, so the code is not perfect.
I feel that DB access from view models might be a bad practice. Should view model have direct DB access? Should it be able to call a repository to get the available labels? Should validation requiring DB access be done in a controller instead?
Should view model have direct DB access?
I think this should be avoided at all cost
Should it be able to call a repository to get the available labels ?
This is not the concern of a ViewModel.
This would introduce some complexity in the testing of your ViewModel (which should almost need none) I guess it is a sign of trouble coming.
Should validation requiring DB access be done in a controller instead ?
Maybe, if by "DB" you mean "Repository". But what comes to mind is a separate custom validation class that you will be able to (un)plug, test, and reuse, in another controller for ajax validation, etc
I think that accessing DB from VM is not wrong... AFAIK it is not breaking MVC concept (since it is a presentation layer concept). Said that, it could be better if you have the Validate method provided by a Service Layer.
But all the logic related to the content of the ViewModel, it is better kept in the VM than in the Controller. Cleaner controllers is better.
Your view model should not be tied to your context, it only cares about displaying data and validating it after a submit. You can perform validation like a required field or a value in range, but you can't know if a label already exists in your database.
You can't also fetch a list of "forbidden labels" before displaying your form, in order to test your label afterwards, because that list could have changed during this time (another user updating you database).
In my opinion, validation at model level should focus on what it can validate without knowledge of the data source, and let your database notify you errors like submitting a duplicate value in a field which has an unique constraint. You'll catch exceptions coming from your database for errors like those, and manage them accordingly.
Anyway, i think there's no straightforward answer for a problem like this.
I personally like the ViewModels to be anemic -- simply classes with properties.
For custom server-side validation like this, I prefer it go either in a service, with the consumption of the service in your controller, or even behind a custom validator.
With a custom validator, you could even (optionally) execute the validation remotely. That gets a little more complex though, but I've done it using a generic remote validator that consumes an Ajax action method to perform the validation, and wire that up through both the client validator and remote validator (to ensure you have your validation logic in a single method).
But which ever way you go, I think it is more common -- and in my opinion, more clean -- to keep all logic out of your ViewModel. Even in a simple app, your ViewModel should be dumb to your database context. Ideally, only services (not necessarily web services, but just an abstraction layer) are aware of your database context.
This, to me, should be done regardless of the size of application. I think the effort and complexity (it only adds another assembly to your solution) is worth the abstraction you get. Down the road, if you happen to decide to consume your services from another application, or if you decide to swap out your database context, it's much easier with that abstraction in place.
Background
We've been migrating a large amount of legacy code & systems to ASP.NET MVC forms. I've already coded up a number of CRUD type interfaces with MVC 4, using model binding, validation, attributes etc., so I'm fairly familiar with that whole paradigm. So far, all of these forms have been on our backend administration & management applications, where it pays to have very strict input validation. We are launching our first consumer facing application in MVC and are faced with a different type of problem.
The Problem
Our legacy forms in this area are the main revenue engine for our company. Usability of the consumer experience is the rule of the day. To that end, we want our forms to be as lenient as possible - the legacy system did a number of things to automatically correct user input (in entirely custom, non standard ways each time, of course). To that end, we don't so much want input validation as we want sanitation.
Examples
We ask the user for numerical inputs which have a unit of measure implied. Common ones are currency amounts or square footage. The input label is clear that they don't need to provide these formats:
What is the approximate square footage? (example: 2000)
What is your budget? (example: 150)
People being people, not everyone follows the directions, and we frequently get answers like:
approx 2100
1500 sq. ft.
$47.50, give or take
(Okay, I exaggerate on the last one.) The model that we are ultimately storing into our business logic accepts numeric input type for these fields (e.g. int & float). We can of course use datatype validator attributes (example [DataType(DataType.Currency)] for the budget input, or just having the field type be an integer for the square footage) to clearly indicate to the user they are doing it wrong, providing helpful error messages such as:
The square footage must be numbers only.
A better user experience, however, would be to attempt to interpret their response as leniently as possible, so they may complete the form with as little interruption as possible. (Note we have an extensive customer service side who can sort out mistakes on our system afterwards, but we have to get the user to complete the form before we can make contact.) For the square footage examples above, that would just mean stripping out non-digit characters. For the budget, it would mean stripping out everything that's not a digit or a decimal point. Only then would we apply the rest of the validation (is a number, greater than 0, less than 50000 etc.)
We're stuck on the best approach to take to accomplish this.
Potential Solutions
We've considered custom attributes, custom model bindings, and a separate scrubber service class that would live between the model and the database. Here are some of the considerations we've taken into account trying to decide upon the approach.
Custom Validation Attributes
I've read a number of helpful resources on this. (They have varying degrees of relevancy and recency. A lot of stuff I found searching for this was written for MVC2 or MVC3 and is available with standard attributes in MVC4.)
Extending ASP.NET MVC’s Validation
Custom Validation Attribute in ASP.NET MVC3
A lot of questions & topics on input sanitization which were focused on Cross-site scripting attacks or database injection.
What I haven't found is anyone doing what I want to do, which would be changing the model value itself. I could obviously create a local copy of the value, sanitize it and provide a pass/fail, but this would result in a lot of duplicate code. I would still have to sanitize any input values again before saving to the database.
Changing the model value itself has 3 benefits:
It affects subsequent validation rules, which would improve their acceptance rate.
The value is closer to what will be put into the database, reducing the additional prep & mapping overhead needed before storage.
In the event of the form being rejected for another reason, it gently suggests to the user "You're trying to hard on these fields."
Is this a valid approach? Is there someone out there who has used validation attributes in this way that I just missed?
Custom Model Binding
I read Splitting DateTime - Unit Testing ASP.NET MVC Custom Model Binders which focuses on custom date time input fields with custom validation & parsing done at the model binding layer. This lives a lot closer to the model itself, so it seems like a more appropriate place to be modifying the model values. In fact, the example class DateAndTimeModelBinder : IModelBinder does exactly that in a few places.
However, the controller action signature provided for this example does not make use of an overall model class. It looks like this
public ActionResult Edit(int id,
[DateAndTime("year", "mo", "day", "hh","mm","secondsorhwatever")]
DateTime foo) {
Rather than this
public ActionResult Edit(
MyModelWithADateTimeProperty model) {
Shortly before that, the article does say
First, usage. You can either put this Custom Model Binder in charge of all your DateTimes by registering it in the Global.asax:
ModelBinders.Binders[typeof(DateTime)] =
new DateAndTimeModelBinder() { Date = "Date", Time = "Time" };
Would that be sufficient to invoke the model binding for the date time field on the single-parameter model example MyModelWithADateTimeProperty?
The other potential draw back that I see here is that the model binder operates on a type, rather than an attribute you can apply to the standard data types. So for example, each set of validation rules I wanted to apply would necessitate a new, custom type. This isn't necessarily bad, but it could get messy and cause a lot of repeated code. Imagine:
public class MyDataModel {
[Required]
public CurrencyType BudgetRange { get; set; }
public PositiveOnlyCurrencyType PaymentAmount { get; set; }
[Required]
public StripNonDigitsIntegerType SquareFootage { get; set; }
Not the ugliest model code I've ever seen, but not the prettiest either.
Custom, External scrubber class
This has the fewest questions for me, but it has the most drawbacks as well. I've done a few things like this before, only to really regret it for one of the following reasons:
Being separate from the controller and model, it is nigh impossible to elegantly extend its validation rules to the client side.
It thoroughly obfuscates what is and what isn't an acceptable input for the different model fields.
It creates some very cumbersome hoops for displaying errors back to the user. You have to pass in your model state to the scrubber service, which makes your scrubber service uniquely tied to the MVC framework. OR you have to make your scrubber service capable of returning errors in a format that the controller can digest, which is rather more logic than is usually recommended for a controller.
The Question
Which approach would you take (or, have you taken) to accomplish this type of sanitization? What problems did it solve for you? What problems did you run into?
I would take ModelBinder approach.
When form data comes in - it goes to model binders infrastructure. There you can override decimal model binder to refine input. After that you can send it to validation routines without neeed to write specific validation attributes or something like that.
Also you can use one intelligent model binder that will do type switch internaly or override ModelBinderProvider, so your code wont be bloated with ModelBinderAttribute. Here is Jimmy Bogart article about this. Also you will get some flexibility, because you can use attributes to declare if model uses strict or adaptive binding.
In overall, IMHO, validation attributes are not suposed to alter input. They should validate it. Model binders are in fact responsible for converting all weird stuff that comes in into something usable in your system and your third approach duplicates Model binder functionality)
Hope this helps and sorry for my english)
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 9 years ago.
Improve this question
tl;dr
In a good design. Should accessing the database be handled in a separate business logic layer (in an asp.net MVC model), or is it OK to pass IQueryables or DbContext objects to a controller?
Why? What are the pros and cons of each?
I'm building an ASP.NET MVC application in C#. It uses EntityFramework as an ORM.
Let's simplify this scenario a bit.
I have a database table with cute fluffy kittens. Each kitten has a kitten image link, kitten fluffiness index, kitten name and kitten id. These map to an EF generated POCO called Kitten. I might use this class in other projects and not just the asp.net MVC project.
I have a KittenController which should fetch the latest fluffy kittens at /Kittens. It may contain some logic selecting the kitten, but not too much logic. I've been arguing with a friend about how to implement this, I won't disclose sides :)
Option 1: db in the controller:
public ActionResult Kittens() // some parameters might be here
{
using(var db = new KittenEntities()){ // db can also be injected,
var result = db.Kittens // this explicit query is here
.Where(kitten=>kitten.fluffiness > 10)
.Select(kitten=>new {
Name=kitten.name,
Url=kitten.imageUrl
}).Take(10);
return Json(result,JsonRequestBehavior.AllowGet);
}
}
Option 2: Separate model
public class Kitten{
public string Name {get; set; }
public string Url {get; set; }
private Kitten(){
_fluffiness = fluffinessIndex;
}
public static IEnumerable<Kitten> GetLatestKittens(int fluffinessIndex=10){
using(var db = new KittenEntities()){ //connection can also be injected
return db.Kittens.Where(kitten=>kitten.fluffiness > 10)
.Select(entity=>new Kitten(entity.name,entity.imageUrl))
.Take(10).ToList();
}
} // it's static for simplicity here, in fact it's probably also an object method
// Also, in practice it might be a service in a services directory creating the
// Objects and fetching them from the DB, and just the kitten MVC _type_ here
}
//----Then the controller:
public ActionResult Kittens() // some parameters might be here
{
return Json(Kittens.GetLatestKittens(10),JsonRequestBehavior.AllowGet);
}
Notes: GetLatestKittens is unlikely to be used elsewhere in the code but it might. It's possible to use the constructor of Kitten instead of a static building method and changing the class for Kittens. Basically it's supposed to be a layer above the database entities so the controller does not have to be aware of the actual database, the mapper, or entity framework.
What are some pros and cons for each design?
Is there a clear winner? Why?
Note: Of course, alternative approaches are very valued as answers too.
Clarification 1: This is not a trivial application in practice. This is an application with tens of controllers and thousands of lines of code, and the entities are not only used here but in tens of other C# projects. The example here is a reduced test case.
The second approach is superior. Let's try a lame analogy:
You enter a pizza shop and walk over to the counter. "Welcome to McPizza Maestro Double Deluxe, may I take your order?" the pimpled cashier asks you, the void in his eyes threatening to lure you in. "Yeah I'll have one large pizza with olives". "Okay", the cashier replies and his voice croaks in the middle of the "o" sound. He yells towards the kitchen "One Jimmy Carter!"
And then, after waiting for a bit, you get a large pizza with olives. Did you notice anything peculiar? The cashier didn't say "Take some dough, spin it round like it's Christmas time, pour some cheese and tomato sauce, sprinkle olives and put in an oven for about 8 minutes!" Come to think of it, that's not peculiar at all. The cashier is simply a gateway between two worlds: The customer who wants the pizza, and the cook who makes the pizza. For all the cashier knows, the cook gets his pizza from aliens or slices them from Jimmy Carter (he's a dwindling resource, people).
That is your situation. Your cashier isn't dumb. He knows how to make pizza. That doesn't mean he should be making pizza, or telling someone how to make pizza. That's the cook's job. As other answers (notably Florian Margaine's and Madara Uchiha's) illustrated, there is a separation of responsibilities. The model might not do much, it might be just one function call, it might be even one line - but that doesn't matter, because the controller doesn't care.
Now, let's say the owners decide that pizzas are just a fad (blasphemy!) and you switch over to something more contemporary, a fancy burger joint. Let's review what happens:
You enter a fancy burger joint and walk over to the counter. "Welcome to Le Burger Maestro Double Deluxe, may I take your order?" "yeah, I'll have one large hamburger with olives". "Okay", and he turns to the kitchen, "One Jimmy Carter!"
And then, you get a large hamburger with olives (ew).
Option 1 and 2 are bit extreme and like the choice between the devil and the deep blue sea but if I had to choose between the two I would prefer option 1.
First of all, option 2 will throw a runtime exception because Entity Framework does not support to project into an entity (Select(e => new Kitten(...)) and it does not allow to use a constructor with parameters in a projection. Now, this note seems a bit pedantic in this context, but by projecting into the entity and returning a Kitten (or an enumeration of Kittens) you are hiding the real problem with that approach.
Obviously, your method returns two properties of the entity that you want to use in your view - the kitten's name and imageUrl. Because these are only a selection of all Kitten properties returning a (half-filled) Kitten entity would not be appropriate. So, what type to actually return from this method?
You could return object (or IEnumerable<object>) (that's how I understand your comment about the "object method") which is fine if you pass the result into Json(...) to be processed in Javascript later. But you would lose all compile time type information and I doubt that an object result type is useful for anything else.
You could return some named type that just contains the two properties - maybe called "KittensListDto".
Now, this is only one method for one view - the view to list kittens. Then you have a details view to display a single kitten, then an edit view and then a delete confirm view maybe. Four views for an existing Kitten entity, each of which needs possibly different properties and each of which would need a separate method and projection and a different DTO type. The same for the Dog entity and for 100 entities more in the project and you get perhaps 400 methods and 400 return types.
And most likely not a single one will be ever reused at any other place than this specific view. Why would you want to Take 10 kittens with just name and imageUrl anywhere a second time? Do you have a second kittens list view? If so, it will have a reason and the queries are only identical by accident and now and if one changes the other one does not necessarily, otherwise the list view is not properly "reused" and should not exist twice. Or is the same list used by an Excel export maybe? But perhaps the Excel users want to have 1000 kittens tomorrow, while the view should still display only 10. Or the view should display the kitten's Age tomorrow, but the Excel users don't want to have that because their Excel macros would not run correctly anymore with that change. Just because two pieces of code are identical they don't have to be factored out into a common reusable component if they are in a different context or have different semantics. You better leave it a GetLatestKittensForListView and GetLatestKittensForExcelExport. Or you better don't have such methods in your service layer at all.
In the light of these considerations an excursion to a Pizza shop as an analogy why the first approach is superior :)
"Welcome to BigPizza, the custom Pizza shop, may I take your order?" "Well, I'd like to have a Pizza with olives, but tomato sauce on top and cheese at the bottom and bake it in the oven for 90 minutes until it's black and hard like a flat rock of granite." "OK, Sir, custom Pizzas are our profession, we'll make it."
The cashier goes to the kitchen. "There is a psycho at the counter, he wants to have a Pizza with... it's a rock of granite with ... wait ... we need to have a name first", he tells the cook.
"No!", the cook screams, "not again! You know we tried that already." He takes a stack of paper with 400 pages, "here we have rock of granite from 2005, but... it didn't have olives, but paprica instead... or here is top tomato ... but the customer wanted it baked only half a minute." "Maybe we should call it TopTomatoGraniteRockSpecial?" "But it doesn't take the cheese at the bottom into account..." The cashier: "That's what Special is supposed to express." "But having the Pizza rock formed like a pyramid would be special as well", the cook replies. "Hmmm ... it is difficult...", the desparate cashier says.
"IS MY PIZZA ALREADY IN THE OVEN?", suddenly it shouts through the kitchen door. "Let's stop this discussion, just tell me how to make this Pizza, we are not going to have such a Pizza a second time", the cook decides. "OK, it's a Pizza with olives, but tomato sauce on top and cheese at the bottom and bake it in the oven for 90 minutes until it's black and hard like a flat rock of granite."
If option 1 violates a separation of concerns principle by using a database context in the view layer the option 2 violates the same principle by having presentation centric query logic in the service or business layer. From a technical viewpoint it does not but it will end up with a service layer that is anything else than "reusable" outside of the presentation layer. And it has much higher development and maintenance costs because for every required piece of data in a controller action you have to create services, methods and return types.
Now, there actually might be queries or query parts that are reused often and that's why I think that option 1 is almost as extreme as option 2 - for example a Where clause by the key (will be probably used in details, edit and delete confirm view), filtering out "soft deleted" entities, filtering by a tenant in a multi-tenant architecture or disabling change tracking, etc. For such really repetetive query logic I could imagine that extracting this into a service or repository layer (but maybe only reusable extensions methods) might make sense, like
public IQueryable<Kitten> GetKittens()
{
return context.Kittens.AsNoTracking().Where(k => !k.IsDeleted);
}
Anything else that follows after - like projecting properties - is view specific and I would not like to have it in this layer. In order to make this approach possible IQueryable<T> must be exposed from the service/repository. It does not mean that the select must be directly in the controller action. Especially fat and complex projections (that maybe join other entities by navigation properties, perform groupings, etc.) could be moved into extension methods of IQueryable<T> that are collected in other files, directories or even another project, but still a project that is an appendix to the presentation layer and much closer to it than to the service layer. An action could then look like this:
public ActionResult Kittens()
{
var result = kittenService.GetKittens()
.Where(kitten => kitten.fluffiness > 10)
.OrderBy(kitten => kitten.name)
.Select(kitten => new {
Name=kitten.name,
Url=kitten.imageUrl
})
.Take(10);
return Json(result,JsonRequestBehavior.AllowGet);
}
Or like this:
public ActionResult Kittens()
{
var result = kittenService.GetKittens()
.ToKittenListViewModel(10, 10);
return Json(result,JsonRequestBehavior.AllowGet);
}
With ToKittenListViewModel() being:
public static IEnumerable<object> ToKittenListViewModel(
this IQueryable<Kitten> kittens, int minFluffiness, int pageItems)
{
return kittens
.Where(kitten => kitten.fluffiness > minFluffiness)
.OrderBy(kitten => kitten.name)
.Select(kitten => new {
Name = kitten.name,
Url = kitten.imageUrl
})
.Take(pageItems)
.AsEnumerable()
.Cast<object>();
}
That's just a basic idea and a sketch that another solution could be in the middle between option 1 and 2.
Well, it all depends on the overall architecture and requirements and all what I wrote above might be useless and wrong. Do you have to consider that the ORM or data access technology could be changed in future? Could there be a physical boundary between controller and database, is the controller disconnected from the context and do the data need to be fetched via a web service for example in future? This would require a very different approach which would more lean towards option 2.
Such an architecture is so different that - in my opinion - you simply can't say "maybe" or "not now, but possibly it could be a requirement in future, or possibly it won't". This is something that the project's stakeholders have to define before you can proceed with architectural decisions as it will increase development costs dramatically and it will we wasted money in development and maintenance if the "maybe" turns out to never become reality.
I was talking only about queries or GET requests in a web app which have rarely something that I would call "business logic" at all. POST requests and modifying data are a whole different story. If it is forbidden that an order can be changed after it is invoiced for example this is a general "business rule" that normally applies no matter which view or web service or background process or whatever tries to change an order. I would definitely put such a check for the order status into a business service or any common component and never into a controller.
There might be an argument against using IQueryable<T> in a controller action because it is coupled to LINQ-to-Entities and it will make unit tests difficult. But what is a unit test going to test in a controller action that doesn't contain any business logic, that gets parameters passed in that usually come from a view via model binding or routing - not covered by the unit test - that uses a mocked repository/service returning IEnumerable<T> - database query and access is not tested - and that returns a View - correct rendering of the view is not tested?
This is the key phrase there:
I might use this class in other projects and not just the asp.net MVC project.
A controller is HTTP-centric. It is only there to handle HTTP requests. If you want to use your model in any other project, i.e. your business logic, you can't have any logic in the controllers. You must be able to take off your model, put it somewhere else, and all your business logic still works.
So, no, don't access your database from your controller. It kills any possible reuse you might ever get.
Do you really want to rewrite all your db/linq requests in all your projects when you can have simple methods that you reuse?
Another thing: your function in option 1 has two responsibilities: it fetches the result from a mapper object and it displays it. That's too many responsibilities. There is an "and" in the list of responsibilities. Your option 2 only has one responsibility: being the link between the model and the view.
I'm not sure about how ASP.NET or C# does things. But I do know MVC.
In MVC, you separate your application into two major layers: The Presentational layer (which contains the Controller and View), and the Model layer (which contains... the Model).
The point is to separate the 3 major responsibilities in the application:
The application logic, handling request, user input, etc. That's the Controller.
The presentation logic, handling templating, display, formats. That's the View.
The business logic or "heavy logic", handling basically everything else. That's your actual application basically, where everything your application is supposed to do gets done. This part handles domain objects that represents the information structures of the application, it handles the mapping of those objects into permanent storage (be it session, database or files).
As you can see, database handling is found on the Model, and it has several advantages:
The controller is less tied to the model. Because "the work" gets done in the Model, should you want to change your controller, you'll be able to do so more easily if your database handling is in the Model.
You gain more flexibility. In the case where you want to change your mapping scheme (I want to switch to Postgres from MySQL), I only need to change it once (in the base Mapper definition).
For more information, see the excellent answer here: How should a model be structured in MVC?
I prefer the second approach. It at least separates between controller and business logic. It is still a little bit hard to unit test (may be I'm not good at mocking).
I personally prefer the following approach. Main reason is it is easy to unit testing for each layer - presentation, business logic, data access. Besides, you can see that approach in a lot of open source projects.
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);
}
}
}
}
#Win has the idea I'd more or less follow.
Have the Presentation just presents.
The Controller simply acts as a bridge, it does nothing really, it is the middle man. Should be easy to test.
The DAL is the hardest part. Some like to separate it out on a web service, I have done so for a project once. That way you can also have the DAL act as an API for others (internally or externally) to consume - so WCF or WebAPI comes to mind.
That way your DAL is completely independent of your web server. If someone hacks your server, the DAL is probably still secure.
It's up to you I guess.
Single Responsibility Principle. Each of your classes should have one and only one reason to change. #Zirak gives a good example of how each person has a single reponsibility in the chain of events.
Let's look at the hypothetical test case you have provided.
public ActionResult Kittens() // some parameters might be here
{
using(var db = new KittenEntities()){ // db can also be injected,
var result = db.Kittens // this explicit query is here
.Where(kitten=>kitten.fluffiness > 10)
.Select(kitten=>new {
Name=kitten.name,
Url=kitten.imageUrl
}).Take(10);
return Json(result,JsonRequestBehavior.AllowGet);
}
}
With a service layer in between, it might look something like this.
public ActionResult Kittens() // some parameters might be here
{
using(var service = new KittenService())
{
var result = service.GetFluffyKittens();
return Json(result,JsonRequestBehavior.AllowGet);
}
}
public class KittenService : IDisposable
{
public IEnumerable<Kitten> GetFluffyKittens()
{
using(var db = new KittenEntities()){ // db can also be injected,
return db.Kittens // this explicit query is here
.Where(kitten=>kitten.fluffiness > 10)
.Select(kitten=>new {
Name=kitten.name,
Url=kitten.imageUrl
}).Take(10);
}
}
}
With a few more imaginary controller classes, you can see how this would be much easier to reuse. That's great! We have code reuse, but there's even more benefit. Lets say for example, our Kitten website is taking off like crazy, everyone wants to look at fluffy kittens, so we need to partition our database (shard). The constructor for all our db calls needs to be injected with the connection to the proper database. With our controller based EF code, we would have to change the controllers because of a DATABASE issue.
Clearly that means that our controllers are now dependant upon database concerns. They now have too many reasons to change, which can potentially lead to accidental bugs in the code and needing to retest code that is unrelated to that change.
With a service, we could do the following, while the controllers are protected from that change.
public class KittenService : IDisposable
{
public IEnumerable<Kitten> GetFluffyKittens()
{
using(var db = GetDbContextForFuffyKittens()){ // db can also be injected,
return db.Kittens // this explicit query is here
.Where(kitten=>kitten.fluffiness > 10)
.Select(kitten=>new {
Name=kitten.name,
Url=kitten.imageUrl
}).Take(10);
}
}
protected KittenEntities GetDbContextForFuffyKittens(){
// ... code to determine the least used shard and get connection string ...
var connectionString = GetShardThatIsntBusy();
return new KittensEntities(connectionString);
}
}
The key here is to isolate changes from reaching other parts of your code. You should be testing anything that is affected by a change in code, so you want to isolate changes from one another. This has the side effect of keeping your code DRY, so you end up with more flexible and reusable classes and services.
Separating the classes also allows you to centralize behavior that would have either been difficult or repetitive before. Think about logging errors in your data access. In the first method, you would need logging everywhere. With a layer in between you can easily insert some logging logic.
public class KittenService : IDisposable
{
public IEnumerable<Kitten> GetFluffyKittens()
{
Func<IEnumerable<Kitten>> func = () => {
using(var db = GetDbContextForFuffyKittens()){ // db can also be injected,
return db.Kittens // this explicit query is here
.Where(kitten=>kitten.fluffiness > 10)
.Select(kitten=>new {
Name=kitten.name,
Url=kitten.imageUrl
}).Take(10);
}
};
return this.Execute(func);
}
protected KittenEntities GetDbContextForFuffyKittens(){
// ... code to determine the least used shard and get connection string ...
var connectionString = GetShardThatIsntBusy();
return new KittensEntities(connectionString);
}
protected T Execute(Func<T> func){
try
{
return func();
}
catch(Exception ex){
Logging.Log(ex);
throw ex;
}
}
}
Either way is not so good for testing. Use dependency injection to get the DI container to create the db context and inject it into the controller constructor.
EDIT: a little more on testing
If you can test you can see if you application works per spec before you publish.
If you can't test easily you won't write your test.
from that chat room:
Okay, so on a trivial application you write it and it doesn't change very much,
but on a non trivial application you get these nasty things called dependencies, which when you change one breaks a lot of shit, so you use Dependency injection to inject a repo that you can fake, and then you can write unit tests in order to make sure your code doesn't
If I had (note: really had) to chose between the 2 given options, I'd say 1 for simplicity, but I don't recommend using it since it's hard to maintain and causes a lot of duplicate code.
A controller should contain as less business logic as possible. It should only delegate data access, map it to a ViewModel and pass it to the View.
If you want to abstract data access away from your controller (which is a good thing), you might want to create a service layer containing a method like GetLatestKittens(int fluffinessIndex).
I don't recommend placing data access logic in your POCO either, this doesn't allow you to switch to another ORM (NHibernate for example) and reuse the same POCO's.
I'm new to MVC / MVP and learning it by creating a Winform application.
I have to some extent created the Models, Presenters and Views... Now where do my validations fit.
I think the initial datatype validation (like only numbers in Age field), should be done by view. Whereas the other validations (like whether age is within 200) should be done by model.
Regarding datatype validation, my view exposes the values as properties
public int? Age
{
get
{
int val;
if (Int32.TryParse(TbxAge.Text, out val))
{
return val;
}
return null;
}
set
{
TbxAge.Text = value;
}
}
I can perform validation seperately, but how do I inform presenter that validation is still pending, when it tries to access the property Age ?. Particularly when the field is optional.
Is it good to throw a validationpending exception, but then the presenter must catch it at every point.
Is my understanding correct, or am I missing something.
Update (for the sake of clarity) : In this simple case where the age field is optional, What should I do when the user typed his name instead of a number. I cant pass null as that would mean the field has been left empty by the user. So how do I inform the presenter that an invalid data has been entered...
Coming from the MVP side (I believe it's more appropriate for WinForms) the answer to your question is debatable. However the key for my understanding was that at anytime you should be able to change your view. That is, I should be able to provide a new WinForms view to display your application or hook it upto a ASP.NET MVC frontend.
Once you realise this, the validation becomes aparant. The application itself (the business logic) should throw exceptions, handle errors and so forth. The UI logic should be dumb. In other words, for a WinForms view you should ensure the field is not empty, or so forth. A lot of the properties for the controls allow this - the properties panel of Visual Studio. Coding validation in the GUI for the likes of throwing exceptions is a big no no. If you were to have validation on both the view and the model you'd be duplicating code - all you require is some simple validation such as controls not being empty for example. Let the actual application itself perform the actual validation.
Imagine if I switched your view to a ASP.NET MVC front end. I would not have said controls, and thus some form of client side scripting would be required. The point I'm making is that the only code you should need to write is for the views - that is do not try to generalise the UI validation across views as it will defeat the purpose of separating your concerns.
Your core application should have all your logic within it. The specalised view logic (WinForms properties, Javascript etc...) should be unique per view. Having properties and interfaces that each view must validate against is wrong in my opinion.
If your "view exposes the values as properties", I suspect that you are missing something. The principal distinction between MVP/MVC and some of the other UI decoupling patterns is that they include a model, which is intended to be the main container for data shared by the view and presenter or controller.
If you are using the model as a data container, the responsibility for validation becomes quite clear. Since only the presenter (or controller) actually does anything besides display the data, it is the one responsible for verifying that the data is in an acceptable state for the operation which it is about to perform.
Addition of visual indicators of data validation problems to an editor form/window during editing is certainly nice to have. However, it should be considered more or less equivalent to view "eye candy", and it should be treated as an add-on to the real validation logic (even if it is based on shared metadata or code). The presenter (or controller) should remain the true authority for data validity, and its validation code should not be hosted in the view.
I believe view validation is only relevant in javascript as the view does not run any code on post, only the controller does.
But I would also not ever trust javascript validation as a malicious user could bypass it or an ignorant user might have JS disabled so repeat any JS validation in serverside code in the controller.
The view might have means to display any errors though .