Accessing Database Entities from Controller [closed] - c#

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.

Related

What is the best way to refactor presentation code out of my domain objects in an ASP.NET MVC solution?

I have just taken over an ASP.NET MVC project and some refactoring is required, but I wanted to get some thoughts / advice for best practices.
The site has an SQL Server backend and here is a review of the projects inside the solution:
DomainObjects (one class per database table)
DomainORM (mapping code from objects to DB)
Models (business logic)
MVC (regular ASP.NET MVC web setup)
---- Controllers
---- ViewModels
---- Views
---- Scripts
The first "issue" I see is that while the Domain objects classes are pretty much POCO with some extra "get" properties around calculated fields, there is some presentation code in the Domain Objects. For example, inside the DomainObjects project, there is a Person object and I see this property on that class:
public class Person
{
public virtual string NameIdHTML
{
get
{
return "<a href='/People/Detail/" + Id + "'>" + Name + "</a> (" + Id + ")";
}
}
}
so obviously having HTML-generated content inside the domain object seems wrong.
Refactor Approaches:
My first instinct was to move this to the ViewModel class inside the MVC project, but I see that there are a lot of views that hit this code so I don't want to duplicate code in each view model.
The second idea was to create PersonHTML class that was either:
2a. A wrapper that took in a Person in the constructor or
2b. A class that inherited from Person and then has all of these HTML rendering methods.
The view Model would convert any Person object to a PersonHTML object and use that for all rendering code.
I just wanted to see:
If there is a best practice here as it seems like this is a common problem / pattern that comes up
How bad is this current state considered because besides feeling wrong, it is not really causing any major problems understanding the code or creating any bad dependencies. Any arguments to help describe why leaving code in this state is bad from a real practical sense (vs. a theoretical separation of concerns argument) would be helpful as well as there is debate in the team whether it's worth it to change.
I like TBD's comment. It's wrong because you are mixing domain concerns with UI concerns. This causes a coupling that you could avoid.
As for your suggested solutions, I don't really like any of them.
Introducing a view model. Yes, we should use view models, but we
don't want to pollute them with HTML code. So an example of using a
view would be if you've got a parent object, person type, and you
want to show the person type on the screen. You would fill the view
model with the person type name and not a full person type object
because you only need the person type name on the screen. Or if
your domain model had first and last name separate, but your view
calls for FullName, you would populate the view model's FullName and
return that to the view.
PersonHtml class. I'm not even sure what that would do. Views are what represent the HTML in an ASP.NET MVC application. You've got two options here:
a. You could create a display template for you model. Here's a link to a Stack Overflow question to display templates, How to make display template in MVC 4 project
b. You could also write a HtmlHelper method that would generate the correct HTML for you. Something like #Html.DisplayNameLink(...) Those would be your best options. Here's a link for understanding HtmlHelpers https://download.microsoft.com/download/1/1/f/11f721aa-d749-4ed7-bb89-a681b68894e6/ASPNET_MVC_Tutorial_9_CS.pdf
I've wrestled with this myself. When I had code in views that were more logic based than HTML, I created an enhanced version of the HtmlBuilder. I extended certain domain objects to automatically print out this helper, with it's contents based off of domain functions, that could then just be printed onto a view. However, the code becomes very cluttered and unreadable (especially when your trying to figure out where it came from); for these reasons, I suggest removing as much presentation/view logic from the domain as possible.
However, after that I decided to take another look at Display and Editor Templates. And I've come to appreciate them more, especially when combined with T4MVC, FluentValidation, and custom Metadata Providers, among other things. I've found using HtmlHelpers and extending the metadata or routing table to much more cleaner way of doing things, but you also start playing with systems that are less documented. However, this case is relatively simple.
So, first off, I would ensure you have a route defined for that entity, which is looks like you would with the default MVC route, so you can simply do this in a view:
//somewhere in the view, set the values to the desired value for the person you have
#{
var id = 10; //random id
var name = "random name";
}
//later:
#name ( #id )
Or, with T4MVC:
#name ( #id )
This means, with regards to the views/viewmodels, the only dependency these have is the id and name of the Person, which I would presume your existing view models ought to have (removing that ugly var id = x from above):
<a href="#Url.Action("People", "Detail", new { id = Model.PersonId } )">
#Model.Name ( #Model.PersonId )
</a>
Or, with T4MVC:
<a href="#Url.Action( MVC.People.Detail( Model.PersonId ) )">
#Model.Name ( #Model.PersonId )
</a>
Now, as you said, several views consume this code, so you would need to change the views to conform to the above. There are other ways do it, but every suggestion I have would require changing the views, and I believe this is the cleanest way. This also has a feature of using the route table, meaning that if the routing system is updated, then the updated url would print out here without worries, as opposed to hard coding it in the domain object as a url (that is dependent on the route system to have been set up in a specific manner for that url to work).
One of the my other suggestions would be to build a Html Helper, called Html.LinkFor( c => model ) or something like that, but, unless if you want it to dynamically determine the controller/action based off the type, that is kind of unnecessary.
How bad is this current state considered because besides feeling wrong, it not really causing any major problems understanding the code or creating any bad dependencies.
The current state is very bad, not only because UI code is included in domain code. That would be already pretty bad, but this is worse. The NameIdHTML property returns a hardcoded link to the person's UI page. Even in UI code you should not hardcode these kind of links. That is what LinkExtensions.ActionLink and UrlHelper.Action are for.
If you change your controller or your route, the link will change. LinkExtensions and UrlHelper are aware of this and you don't need any further changes. When you use a hardcoded link, you need to find all places in your code where such a link is hardcoded (and you need to be aware that those places exist). To make matters even worse, the code you need to change is in the business logic which is in the opposite direction of the chain of dependencies. This is a maintenance nightmare and a major source of errors. You need to change this.
If there is a best practice here as it seems like this is a common problem / pattern that comes up.
Yes, there is a best practice and that is using the mentioned LinkExtensions.ActionLink and UrlHelper.Action methods whenever you need a link to a page returned by a controller action. The bad news is that this means changes at multiple spots in your solution. The good news is that it's easy to find those spots: just remove the NameIdHTML property and the errors will pop up. Unless you are accessing the property by reflection. You will need to do a more careful code search in this case.
You will need to replace NameIdHTML by code that uses LinkExtensions.ActionLink or UrlHelper.Action to create the link. I assume that NameIdHTML returns HTML code that should be used whenever this person is to be shown on an HTML page. I also assume that this is a common pattern in your code. If my assumption is true, you can create a helper class that converts business objects to their HTML representations. You can add extension methods to that class that will provide the HTML representation of your objects. To make my point clear I assume (hypothetically), that you have a Department class that also has Name and Id and that has a similar HTML representation. You can then overload your conversion method:
public static class BusinessToHtmlHelper {
public static MvcHtmlString FromBusinessObject( this HtmlHelper html, Person person) {
string personLink = html.ActionLink(person.Name, "Detail", "People",
new { id = person.Id }, null).ToHtmlString();
return new MvcHtmlString(personLink + " (" + person.Id + ")");
}
public static MvcHtmlString FromBusinessObject( this HtmlHelper html,
Department department) {
string departmentLink = html.ActionLink(department.Name, "Detail", "Departments",
new { id = department.Id }, null).ToHtmlString();
return new MvcHtmlString(departmentLink + " (" + department.Id + ")");
}
}
In your views you need to replace NameIdHTML by a call to this helper method. For example this code...
#person.NameIdHTML
...would need to be replaced by this:
#Html.FromBusinessObject(person)
That would also keep your views clean and if you decide to change the visual representation of Person you can easily change BusinessToHtmlHelper.FromBusinessObject without changing any views. Also, changes to your route or controllers will be automatically reflected by the generated links. And the UI logic remains with the UI code, while business code stays clean.
If you want to keep your code completely free from HTML, you can create a display template for your person. The advantage is that all your HTML is with the views, with the disadvantage of needing a display template for each type of HTML link you want to create. For Person the display template would look something like this:
#model Person
#Html.ActionLink(Model.Name, "Detail", "People", new { id = Model.Id }, null) ( #Html.DisplayFor(p => p.Id) )
You would have to replace your references to person.NameIdHTML by this code (assuming your model contains a Person property of type Person):
#Html.DisplayFor(m => m.Person)
You can also add display templates later. You can create BusinessToHtmlHelper first and as a second refactoring step in the future, you change the helper class after introducing display templates (like the one above):
public static class BusinessToHtmlHelper {
public static MvcHtmlString FromBusinessObject<T>( this HtmlHelper<T> html, Person person) {
return html.DisplayFor( m => person );
}
//...
}
If you were careful only to use links created by BusinessToHtmlHelper, there will be no further changes required to your views.
It's not easy to provide a perfect answer to this issue. Although a total separation of layers is desirable, it often causes a lot useless engineering problems.
Although everyone is ok with the fact that the business layer must not know to much about the presentation/UI layer, I think it's acceptable for it to know these layers do exist, of course without too many details.
Once you have declared that, then you can use a very underused interface: IFormattable. This is the interface that string.Format uses.
So, for example, you could first define your Person class like this:
public class Person : IFormattable
{
public string Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
// reroute standard method to IFormattable one
return ToString(null, null);
}
public virtual string ToString(string format, IFormatProvider formatProvider)
{
if (format == null)
return Name;
if (format == "I")
return Id;
// note WebUtility is now defined in System.Net so you don't need a reference on "web" oriented assemblies
if (format == "A")
return string.Format(formatProvider, "<a href='/People/Detail/{0}'>{1}</a>", WebUtility.UrlEncode(Id), WebUtility.HtmlDecode(Name));
// implement other smart formats
return Name;
}
}
This is not perfect, but at least, you'll be able to avoid defining hundreds of specified properties and keep the presentation details in a ToString method that was meant speficially for presentation details.
From calling code, you would use it like this:
string.Format("{0:A}", myPerson);
or use MVC's HtmlHelper.FormatValue. There are a lot of classes in .NET that support IFormattable (like StringBuilder for example).
You can refine the system, and do this instead:
public virtual string ToString(string format, IFormatProvider formatProvider)
{
...
if (format.StartsWith("A"))
{
string url = format.Substring(1);
return string.Format(formatProvider, "<a href='{0}{1}'>{2}</a>", url, WebUtility.UrlEncode(Id), WebUtility.HtmlDecode(Name));
}
...
return Name;
}
You would use it like this:
string.Format("{0:A/People/Detail/}", person)
So you don't hardcode the url in the business layer. With the web as a presentation layer, you'll usually have to pass a CSS class name in the format to avoid hardcoding style in the business layer. In fact, you can come up with quite sophisticated formats. After all, this is what's done with objects such as DateTime if you think about it.
You can even go further and use some ambiant/static property that tells you if you're running in a web context so it works automatically, like this:
public class Address : IFormattable
{
public string Recipient { get; set; }
public string Line1 { get; set; }
public string Line2 { get; set; }
public string ZipCode { get; set; }
public string City { get; set; }
public string Country { get; set; }
....
public virtual string ToString(string format, IFormatProvider formatProvider)
{
// http://stackoverflow.com/questions/3179716/how-determine-if-application-is-web-application
if ((format == null && InWebContext) || format == "H")
return string.Join("<br/>", Recipient, Line1, Line2, ZipCode + " " + City, Country);
return string.Join(Environment.NewLine, Recipient, Line1, Line2, ZipCode + " " + City, Country);
}
}
Ideally, you will want to refactor your code to use view models. The view models can have utility methods for simple string formatting e.g.
public string FullName => $"{FirstName} {LastName}"
But strictly NO HTML! (Being a good citizen :D)
You can then create various Editor/Display templates in the following directories:
Views/Shared/EditorTemplates
Views/Shared/DisplayTemplates
Name the templates after the model object type, e.g.
AddressViewModel.cshtml
You can then use the following to render display/editor templates:
#Html.DisplayFor(m => m.Address)
#Html.EditorFor(m => m.Address)
If the property type is AddressViewModel, then the AddressViewModel.cshtml from the EditorTemplates, or DisplayTemplates directory will be used.
You can further control the rendering by passing in options to the template like so:
#Html.DisplayFor(m => m.Address, new { show_property_name = false, ... })
You can access these values in the template cshtml file like so:
# {
var showPropertyName = ViewData.ContainsKey("show-property-name") ? (bool)ViewData["show-property-name] : true;
...
}
#if(showPropertyName)
{
#Html.TextBoxFor(m => m.PropertyName)
}
This allows for a lot of flexibility, but also the ability to override the template that is used by applying the UIHint attribute to the property like so:
[UIHint("PostalAddress")]
public AddressViewModel Address { get; set; }
The DisplayFor/EditorFor methods will now look for the 'PostalAddress.cshtml' template file, which is just another template file like AddressViewModel.cshtml.
I always break down UI into templates like this for projects that i work on, as you can package them via nuget and use them in other projects.
Also, you could also add them to a new class library project, and have them compiled into a dll, which you can just reference in you MVC projects. I have used RazorFileGenerator to do this previously (http://blog.davidebbo.com/2011/06/precompile-your-mvc-views-using.html), but now prefer using nuget packages, as it allows for versioning of the views.
I guess you need to have a plan before you change it. Yes, projects that you mentioned don't sound correct, but that does not mean the new plan is better.
First, existing projects (this will help you see what to avoid):
DomainObjects containing database tables? that sounds like DAL. I'm assuming that those objects are actually stored in the DB (e.g. if they are entity framework classes) and not mapped from them (e.g. using entity framework and then mapping results back to thse objects), otherwise you have too many mappings (1 from EF to data objects, and 2 from data objects to Models). I've seen that done, very typical mistake in layering. So if you have that, don't repeat that. Also, don't name projects containing data row objects as DomainObjects. Domain means Model.
DomainORM - Ok, but I'd combine it with the data row objects. Makes no sense to keep the mapping project separate, if it's tightly coupled with data objects anyway. It's like pretending you can replace one without the other.
Models - good name, it could mention Domain too, that way nobody would name other projects with this very important word.
NameIdHTML property - bad idea on business objects. But that's a minor refactoring - move that into a method that leaves somewhere else, not inside your business logic.
Business objects looking like DTOs - also bad idea. Then what's the point of the business logic? my own article on this: How to Design Business Objects
Now, what you need to target (if you are ready to refactor):
Business logic hosting project should be platform independent - no mention of HTML, or HTTP, or anything related to a concrete platform.
DAL - should reference business logic (not other way around), and should be responsible for mapping as well as holding the data objects.
MVC - keep thin controllers by moving logic out to business logic (where the logic is really a business logic), or into so called Service layer (a.k.a. Application logic layer - optional and exists if necessary to put application specific code out of controllers).
My own article on layering: Layering Software Architecture
Real reasons to do so:
Reusable business logic on potentially several platforms (today you are web only, tomorrow you can be web and services, or desktop too). All different platforms should be using same business logic ideally, if they belong to the same bounded context.
Manageable complexity long run, which is the well known factor for choosing something like DDD (domain driven) vs data-driven design. It comes with learning curve, so you invest into it initially. Long-run, you keep your maintainability low, like receiving premiums perpetually. Beware of your opponents, they will argue it's completely different from what they've been doing, and it will seem complex to them (due to learning curve and thinking iteratively to maintain the good design long run).
First consider your goal and Kent Beck's points about Economics of Software Development. Probably, the goal of your software is to deliver value and you should spend your time on doing something valuable.
Second, wear your Software Architect's hat, and make some kind of calculation. This is how you back up the choice to spend resources on this or to spend on something else.
Leaving code in that state would be bad, if within the next 2 years it were going to:
increase the number of unhappy customers
reduce your company's revenue
increase the number of software failure/bugs/crashes
increase cost of maintenance or change of your code
surprise developers, causing them to waste hours of time in a misunderstanding
increase the cost of onboarding new developers
If these things are unlikely to happen as a result of the code then don't waste your team's life on straightening pencils. If you can't identify a real negative cost-consequence of the code, then the code is probably okay and it's your theory that should change.
My guess would be “The cost of changing this code is probably higher than the cost of problems it causes.” But you are better placed to guess actual cost of problems. In your example the cost of change might be quite low. Add this to your option 2 refactor list:
————————————————————————————————————
2c. Use extensions methods in the MVC app to add presentation know-how to domain objects with minimal code.
public static class PersonViewExtensions
{
const string NameAndOnePhoneFormat="{0} ({1})";
public static string NameAndOnePhone(this Person person)
{
var phone = person.MobilePhone ?? person.HomePhone ?? person.WorkPhone;
return string.Format(NameAndOnePhoneFormat, person.Name, phone);
}
}
Where you have embedded HTML, the code in #Sefe's answer — using extension methods on the HtmlHelper class – is pretty much what I would do. Doing that is great feature of Asp.NetMVC
———————————————————————————————————————
But this approach should be the learned habit of the whole team. Don't ask your boss for a budget for refactoring. Ask your boss for a budget for learning: books, time to do coding katas, budget for taking the team to developer meetups.
Do not, whatever you do, do the amateur-software-architecture-thing of thinking, “this code doesn't conform to X, therefore we must spend time and money changing it even though we can show no concrete value for that expense.”
Ultimately, your goal is to add value. Spending money on learning will add value; spending money on delivering new features or removing bugs may add value ; spending money on rewriting working code only adds value if you are genuinely removing defects.

Dealing with Exceptions,Errors discussion and explanation

I have read various topics about Exceptions, Errors, Error Codes etc.
I've searched an answer through stackoverflow's questions, but I still have some misunderstandings...
So while reading my question please lets think more about delivering better results to the customer, instead of following "theoretical" patterns which may not work in a true life scenario. So Let's go:
Some specifications, to add transparency to our situation:
3 Layers (DataAccess -> Service -> UI)
Repository Pattern
ORM - NHibernate
IoC - Castle Windsor
User Interface Framework - ASP.NET MVC3
The scenario:
Suppose we have a service interface:
public interface IProductService
{
// Just get the products from DB
IList<Products> GetAllProducts();
// Makes a conversion between product's current UM and requested 'toUnitMeasure'
double ConvertUnitMeasureTo(Product product, UnitMeasure toUnitMeasure);
}
Now lets analyze what things may happen, for the both methods:
GetAllProducts(); :
The resulted list could be empty.
The DB may throw an SqlException.
ConvertUnitMeasureTo(Product product, UnitMeasure toUnitMeasure); :
The product might be not found in the DB.
The toUnitMeasure might be not found either.
product's current unit measure might not be convertible to toUnitMeasure (eg: MASS to LENGTH)
some sort of ArithmeticException's etc.
Ok so far so good. Lets take a look at the controller:
[HttpPost]
public ActionResult Index(ProductViewModel model)
{
if(ModelState.IsValid)
{
// At this point, some of the (above enumerated) situations may occur.
// Some of them are Exceptions while another
// are unpleasant but 'expected' situations.
var result = _productService.ConvertToUnitMeasure(model.Product, model.UnitMeasure);
}
}
QUESTION:
How to treat all those situations inside the Controller? while:
Delivering a (localized) answer to the client.(eg: HardCoding the message inside a CustomException.Message, is not suited for my case)
Being able to distinguish each situation that may occur, in order to take a specific action for it (eg: if The toUnitMeasure might be not found either. to make an RedirectToAction("CreateUnitMeasure","UnitMeasure"));
Keeping the Controller 'thin' as possible. Eg: Avoid to implement the conversion method inside the Controller, instead of the Service Layer, through separating the ConvertUnitMeasureTo(..) into smaller service methods. (hope no explanation needed)
Your answer is valuable for me so please do not hesitate to express yourself.Thank you very much for attention.

DDD and Repository pattern where to put behavior concerning CRUD

I try to put as much business logic as possible in my Domain Model.
Every time MyEntity is updated, I want two things to happen:
Send a message to the user who created it
Check if the changes apply to certain business rules
If the entity is not a child of an aggregate root.
Normally I would get the specific entity from the repository. Change the entity, and persist it
back to the DB using MyRepository.Save()
In this case I'd have to put the business logic in my application or in the DAL, not in the Domain Model. I'm trying to avoid using a business logic layer unless absolutely necessary, but I can't seem to fit this in unless I make a method called MyEntity.Update() or something like that but I have a feeling that is not the right way to do it.
First let me state, I am not against Repository patterns. I recently used one successfully on a project.
I would say exercise caution ... and if you can't encapsulate the requirements in your objects your OO approach might need to be looked at again. Introducing a Data Access layer for the purposes of doing other things seems to be a code smell. I have used a Service Layor to receive requests and manage transactions and versioning however not for additional things like validation and so on. Potentially your service layor could look like the following.
public enum UpdateResult
{
Success,
NoMyEntityFound,
StaleData,
InvalidRequest
}
public class MyService
{
...
...
public UpdateResult Update(...)
{
...Start Tran
...Load var m = MyEntity
...do the bare minimum here
...m.Update()
...Commit Tran
return UpdateResult.Success;
}
}
Having said all that a cautionary tail on repositories
http://ayende.com/blog/3955/repository-is-the-new-singleton

Creating a large form with multiple dropdowns and text fields in ASP.NET MVC

In my continuing journey through ASP.NET MVC, I am now at the point where I need to render an edit/create form for an entity.
My entity consists of enums and a few other models, created in a repository via LINQtoSQL.
What I am struggling with right now is finding a decent way to render the edit/create forms which will contain a few dropdown lists and a number of text fields. I realize this may not be the most user-friendly approach, but it is what I am going with right now :).
I have a repository layer and a business layer. The controllers interface with the service layer.
Is it best to simply create a viewmodel like so?
public class EventFormViewModel
{
IEventService _eventService;
public IEvent Event { get; private set; }
public IEnumerable<EventCampaign> Campaigns { get; private set; }
public IEnumerable<SelectListItem> Statuses { get; private set; }
// Other tables/dropdowns go here
// Constructor
public EventFormViewModel(IEventService eventService, IEvent ev)
{
_eventService = eventService;
Event = ev;
// Initialize Collections
Campaigns = eventService.getCampaigns().ToSelectList(); //extn method maybe?
Statuses = eventService.getStatus().ToSelectList(); /extn for each table type?
}
So this will give me a new EventFormViewModel which I'll bind to a view. But is this the best way? I'd essentially be pulling all data back from the database for a few different tables and converting them to an IEnumerable. This doesn't seem overly efficient, but I suppose I could cache the contents of the dropdowns.
Also, if all I have is methods that get data for a dropdown, should I just skip the service layer and go right to the repository?
The last part of my question: For the ToSelectList() extension method, would it be possible to write one method for each table and use it generically even if some tables have different columns ("Id" and "Name" versus "Id" and "CampaignName").
Forgive me if this is too general, I'm just trying to avoid going down a dead-end road - or one that will have a lot of potholes.
I wouldn't provide an IEventService for my view model object. I prefer to think of the view model object as a dumb data transfer object. I would let the controller take care of asking the IEventService for the data and passing it on to the view model.
I'd essentially be pulling all data
back from the database for a few
different tables and converting them
to an IEnumerable
I don't see why this would be inefficient? You obviously shouldn't pull all data from the tables. Perform the filtering and joining you need to do in the database as usual. Put the result in the view model.
Also, if all I have is methods that
get data for a dropdown, should I just
skip the service layer and go right to
the repository?
If your application is very simple, then a service layer may be an unneeded layer of abstraction / indirection. But if your application is just a bit complex (from what you've posted above, I would guess that this is the case), consider what you will by taking a shortcut and going straight to a repository and compare this to what you will win in maintainability and testability if you use a service layer.
The worst thing you could do, would be to go through a service layer only when you feel there is a need for it, and go straight to the repository when the service layer will not be providing any extra logic. Whatever you do, be consistent (which almost always means: go through a service layer, even when your application is simple. It won't stay simple).
I would say if you're thinking of "skipping" a layer than you're not really ready to use MVC. The whole point of the layers, even when they're thin, is to facilitate unit testing and try to enforce separation of concerns.
As for generic methods, is there some reason you can just use the OOB objects and then extend them (with extension methods) when they fail to meet your needs?

Save Me on a Business Object

I've commonly seen examples like this on business objects:
public void Save()
{
if(this.id > 0)
{
ThingyRepository.UpdateThingy(this);
}
else
{
int id = 0;
ThingyRepository.AddThingy(this, out id);
this.id = id;
}
}
So why here, on the business object? This seems like contextual or data related more so than business logic.
For example, a consumer of this object might go through something like this...
...Get form values from a web app...
Thingy thingy = Thingy.CreateNew(Form["name"].Value, Form["gadget"].Value, Form["process"].Value);
thingy.Save();
Or, something like this for an update...
... Get form values from a web app...
Thingy thingy = Thingy.GetThingyByID(Int32.Parse(Form["id"].Value));
Thingy.Name = Form["name"].Value;
Thingy.Save();
So why is this? Why not contain actual business logic such as calculations, business specific rules, etc., and avoid retrieval/persistence?
Using this approach, the code might look like this:
... Get form values from a web app...
Thingy thingy = Thingy.CreateNew(Form["name"].Value, Form["gadget"].Value, Form["process"].Value);
ThingyRepository.AddThingy(ref thingy, out id);
Or, something like this for an update...
... get form values from a web app ...
Thingy thingy = ThingyRepository.GetThingyByID(Int32.Parse(Form["id"].Value));
thingy.Name = Form["Name"].Value;
ThingyRepository.UpdateThingy(ref thingy);
In both of these examples, the consumer, who knows best what is being done to the object, calls the repository and either requests an ADD or an UPDATE. The object remains DUMB in that context, but still provides it's core business logic as pertains to itself, not how it is retrieved or persisted.
In short, I am not seeing the benefit of consolidating the GET and SAVE methods within the business object itself.
Should I just stop complaining and conform, or am I missing something?
This leads into the Active Record pattern (see P of EAA p. 160).
Personally I am not a fan. Tightly coupling business objects and persistence mechanisms so that changing the persistence mechanism requires a change in the business object? Mixing data layer with domain layer? Violating the single responsibility principle? If my business object is Account then I have the instance method Account.Save but to find an account I have the static method Account.Find? Yucky.
That said, it has its uses. For small projects with objects that directly conform to the database schema and have simple domain logic and aren't concerned with ease of testing, refactoring, dependency injection, open/closed, separation of concerns, etc., it can be a fine choice.
Your domain objects should have no reference to persistance concerns.
Create a repository interface in the domain that will represent a persistance service, and implement it outside the domain (you can implement it in a separate assembly).
This way your aggregate root doesn't need to reference the repository (since it's an aggregate root, it should already have everyting it needs), and it will be free of any dependency or persistance concern. Hence easier to test, and domain focused.
While I have no understanding of DDD, it makes sense to have 1 method (which will do UPSERT. Insert if record doesn't exist, Update otherwise).
User of the class can act dumb and call Save on an existing record and Update on a new record.
Having one point of action is much clearer.
EDIT: The decision of whether to do an INSERT or UPDATE is better left to the repository. User can call Repository.Save(....), which can result in a new record (if record is not already in DB) or an update.
If you don't like their approach make your own. Personally Save() instance methods on business objects smell really good to me. One less class name I need to remember. However, I don't have a problem with a factory save but I don't see why it would be so difficult to have both. IE
class myObject
{
public Save()
{
myObjFactory.Save(this);
}
}
...
class myObjectFactory
{
public void Save(myObject obj)
{
// Upsert myObject
}
}

Categories

Resources