I am relatively new to MVC. I am trying to just display the contents of a remote SQL Server table on a page. It is READ ONLY, and nearly everything I find online is utilizing the Entity Framework or something similar which is overkill for what I am after. I just need to print all the rows from a table out to a view.
So my questions are:
should I just hack the sqlconn and everything into the view that I want the data printing out to?
Or should I add the sql in that view's controller?
Create a model and somehow get that data back into the view?
I know step #3 is the 'correct' way to do it, however I am looking for something simple and quick. :)
Thanks everyone!
You say EF is overkill, but that's the easiest way to do this. Maybe use Linq to SQL, since that's more lightweight. This is all there is to it:
Generate the EF / L2S entity classes
Instantiate the database context in the controller, and get all records
Return the IEnumerable records to the view
In the view, use #Html.DisplayForModel()
Here's a simple example. Note that returning the database entity classes is considered bad practice, you should map / automap them to a View Model type class first.
Home Controller
public ActionResult Index()
{
MyEntityModel[] items = MyDatabaseContext.GetAllRows();
return View(items);
}
Home/Index View
#model IEnumerable<MyEntityModel>
#foreach (MyEntityModel item in Model)
{
#Html.DisplayFor(m => item)
}
Without EF / L2S it's almost as easy, but you'd have to create your own entity / wrapper class for the database records and populate them manually.
There are also scaffolding projects for MVC that will generate repository and controller classes, as well as Razor views. See for example MVC Scaffolding on NuGet.
Once you get used to forcing yourself to use Entity Framework for even your "small" applications then and only then will you truly understand that is it the simplest way.
Sure, if you come from a background of memorized ADO.NET dataset/datatable/datareaders etc.. then sure you have projects with "canned" operations that you port over and modify but it is truly just old and cost you more time in the long run.
Use EF
Use multiple projects in a solution
Use a repository pattern if you can, it pays off in dividends for reasons you will discover
Keep your controllers "skinny"
Dont' use a "ViewModel" just to use / do it.
The SOC of having View and Controller are critical, but the Models folders does not need to be used, you can wire things up without it if you want, just pay attention to where your "model" is and abiding by SOLID principle etc..
Related
I have an asp.net-mvc site that pretty much is a CRUD app but I also do some adds & updates outside the webview (upload from spreadsheets, etc). Based on this article, I am trying to get as much of the logic outside the MVC project into a seperate shared project so i can reuse the same code in all scenarios and I am trying to isolate and seperate my "read" viewModels that are binding to UIs for display from the "edit" viewModels that represent what is being posted to the server on a form post.
I have a number of projects in the solution (domainobjects, importexport,etc) that are shared with other solution plus the MVC project has the following directories in the MVC project
Controllers
Views
ViewModels
Scripts
EditViewModels
My ViewModels folder represents the objects that I am binding to my views (a container object that usually includes:
A domain object and
A bunch of IEnumerable of SelectListItem to populate UI dropdowns, etc
something like this:
public class OrderViewModel
{
public Order MyOrder {get;set;}
public IEnumerable<SelectListItem> OrderTypes {get;set;}
public IEnumerable<SelectListItem> Sizes {get;set;}
}
My EditViewModels folder represents the objects that i am posting from forms to the server so they are usually simpler flat objects with just primatives that i then populate a domain object with before adding or updating my database like this:
public class OrderEditViewModel
{
public int Id {get;set;}
public int OrderTypeId {get;set;}
public int SizeId {get;set;}
}
My main question is when i have a method in my Controller class that usually looks like this (simplified):
public ActionResult Update(OrderEditViewModel order)
{
var existingOrder = _repository.GetOrder(order.Id);
existingOrder.Name = order.Name;
existingOrder.Size = _repository.GetSize(order.SizeId);
existingOrder.Price = order.Price;
_repository.Save(existingOrder);
return Json( Result = "Success");
}
I am trying to figure out how to get as much code as possible outside the MVC project but that forces me to move all of my classes in the EditViewModel outside of the MVC project so those objects can be reused.
Does anyone see anything wrong with having these "Post" data structure classed outside the MVC projecdt. Given its a "viewmodel" class it feels wrong to move it away from the view but I don't see any other way to share this code outside of the MVC project. Maybe the "viewModel" name here is just wrong possibly?
Your View Models are specific to your views, and should not be relevant to anything else. They contain things which nothing else should care about, such as your select lists. As such, they should stay in your UI.
The article appears to me to be creating a situation in which the business logic depends on the UI (or at least the UI Model.. ie View Model), and I think that is the wrong approach. The UI should be able to consume the business logic without the business logic being aware what the UI is. It could be a web site, a fat client, a mobile client, a web service, etc... By making this logic depend on your view models, you now are making any future services that are not web based depend on those.
This is, however, a simple CRUD app, and in simple CRUD apps you can often take a lot of shortcuts because it's just not worth the extra engineering effort. I wouldn't normally pass a domain object to the view directly in the View Model. But in this case it's probably the best choice.
If you want to do it "right", however, then you need to create more separation of concerns. Your domain and ui layers need more separation. You create separate view and domain models, and then map between them. This prevents the business layer from knowing anything about the UI.
I would probably create a service layer that handles your logic. For instance:
_orderService.UpdateOrder(order.Id, order.Name, order.Price);
In my case, i make a difference between read(view-)models and write-models.
Read models are very specific to the view, they can contain select lists and formatted and localized content. You should not move this models outside of your ui-project. Of course you can make a separate assembly with your models, or you can make one assembly per module, but you should never consume these models from your domain layer.
Write models - in my opinion - are not that specific to your UI. Instead they represent the data that is required by the command (e.g. SaveUserCommand). They can contain validation attributes, so your domain layer can validate them easily and they can be shared by domain layer and UI. In my project I have one class per command (e.g. SaveUserCommand, EditUserCommand, DeleteUserCommand) and related models (SaveUserModel, EditUserModel). Somebody will comment, that the they also contain some UI-specific code (e.g. the IClientValidateable itnerface for attributes or the attributes itself) and at least the IClientValidateable interface is a problem that I am willing to ignore to reduce the number of models. My experience with this approach (I also tried others) shows, that these models are very easy and it very easy to bind to these models.
Sometimes you will also have the problem, that you want to show some additional information in the edit-view. Instead of adding all this information to the viewbag, I will have another model, for example:
class UserEditModel
{
string Password;
}
UserEditViewModel
{
DateTime Modified;
UserEditModel Edit;
}
So my advice:
Create write-models that have all the data and validation logic that is specific to your use cases.
Create view models that contain all data you want to display and try not to use the ViewBag.
If you have a form, add the write-model to your view model. The write-model has all the data that will be sent back to your server via POST and then directly to your domain layer.
I use four "layers" in two assemblies
{application}.app assembly with three namespaces, just a regular class library project.
1) {application}.model for domain model
2) {application}.data for data using repository pattern
3) {application}.services for all business logic
{application}.WebUI assembly for the UI, this is the MVC project
Controllers only call services and services get and update data through the repositories.
There is an services API for every operation your app has to do, i.e.
OrderServices.Update (existingOrder)
OrderServices.Approve (existingOrder)
Services layer only know domain models, and controllers just assemble the viewmodels, using the domain models gotten from services, to send them to the views and prepare the domain models using the viewmodels gotten from the views to send them to the appropiate service.
This way you can eventually create an {application}.WebAPI or whatever that uses the same {application}.app assembly reusing all of the buissiness logic and keeping viwemodels where they belong (the WebUI project)
Hope this helps.
Best regards.
You could use a service architecture of your project , where all function and db queries are in this files and which you could using just by adding this code
IOrderService<Order> service = new OrderEntityService();
and use it like
service.Create(Order) or service.Update();
Whats strange to me is you're taking care and effort to layer out your app as much as possible, but you're still letting your MVC controller contain a lot of your logic. You're trying to share the objects and models, but the logic to add a new OrderEditViewModel is not shared, its stuck within that controller.
What I try and do is create a "helper" or "logic" class for each of my controllers. That logic or helper class is then injected into my controllers and wrapped in an interface. My controller can save, edit and remove items through my helper class, but has no knowledge of how its actually doing that.
I have then shared these logic classes along with the models to other projects, allowing a lot of code re-use. The problem is just ensuring that none of the "HTTP'ness" of the controllers sneaks into your logic classes, as these must be usable in a console or winforms application. So you have to be pretty strict and wrap a lot of things like HTTPSession or HTTPContext into interfaces that can then have non HTTP implementations..
Well, I understand your situation and also tends to a DDD (Domain Driven Design) solution as #MystereMan suggests.
I have an approach that sepparates the "Models" in 3 categories:
ViewModels: Have all the information necessary to display content data in the UI
RequestModels: Have all the information necesssary to send data, post/get/etc.)
AutoBindModels: Have all the information that is injected my MVC binding model (cookies, sessions, etc..)
And the most important, for all that classes I use as DTO/POCO's, actually they have no UI dependent code just properties/calculated properties and could be easily in any other project to be referenced by an UI project.
You could also create a Controller class that act as a Service outside ASP.MVC project and extend or inject it in your MVC controller.
Hope it helps...
I never reuse (Edit)ViewModels objects (this is not entirely true, I often share one EditViewModel between Create and Update but not always).
I design my ViewModels for specific Views. Therefore, I don't have to compromise my ViewModels when the UI changes (it changes all the time).
I take this as far as creating two distinct ViewModels even if they are identical. I'm done refactoring shared ViewModels..
I would answer yes to your question.
Hope it helps.
OrderEditViewModel and OrderViewModel are both 'ViewModels' end of the day. IMO, they may stay together in the same project even in your same 'ViewModels' folder. You may though create a sub folder under ViewModels for your 'EditViewModels'.
Now as you want to clean/tidy up the controller actions, you may want to use AutoMapper or ValueInjecter. You are mapping domain entity and view models manually. That is a tiresome job. With AutoMapper you can do something like:
var customerInfo = Mapper.Map<CustomerViewModel, CustomerInfo>(customerViewModel);
Looking through the project we are working on (ASP MVC 3.0), I have seen this part of code in one of my ASPX views:
var groups = Model.GroupBy(t => new { t.OrganizationUnitName, t.OrganizationUnitId, t.ServiceTermDate }).OrderBy(m =>m.Key.ServiceTermDate).ThenBy(m => m.Key. OrganizationUnitId);
foreach (var group in groups){
var data = group.Select(t => new
{
t.PersonFullName,
t.ServiceTermStatusName,
t.VisitTypeName,
SubType = ControllerHelper.LocalizedPersonSubType(t.PersonSubTypeName),
t.MedicalServiceName,
t.PersonId,
t.ServiceTermId,
t.Phone,
CountryName = t.Name,
PersonUniqueNumber = t.GetUniqueIdentifyingNumber(),
}).OrderBy(m => m.HoursFromMinutesFrom);
foreach(var item in data){%>
...............
//render table and table rows, for sample
<tr>
<td><%= item.PersonFullName%></td>
</tr>
..............
<%}%>
<%}%>
<%}%>
I am not sure this is best coding practice, shouldn't LINQ statement be placed in controller helper (or somewhere else) instead in view directly? And if I'm right, how that could be done utilizing best coding practices?
Thank you in advance
It seems that LINQ which is performed directly in the view is not only at the wrong place but also it raise another interesting question: if we place it into service layer or controller or controller helper, then how it would be passed in this case - anonymous type IGrouping to strongly typed view?
Personally, I wouldn't use LINQ in the view. Do this in the controller for unit testing purposes.
If there is logic being performed, in a larger application I'd even move it out to a services assembly which would contain all of your LINQ queries.
Your view should be as basic as possible. Any ordering, grouping or sorting should be done in your controller (preferably with the help of a helper method which is re-usable for different actions across the application).
The philosophy of ASP.NET MVC (and I'd say of the MVC paradigm in general) is:
Put as little code as possible in the view. Ideally, you should just
reference data in the model class, perhaps with some loops or
conditional statements.
Do not put complex application logic in the controller methods.
Ideally, these methods should just collect the input data from the user
(if any), perform all the appropriate security and data validations, then pass the data to an application logic (or business logic)
class, then redirect to the appropriate view with the new model data
obtained from the logic class. (I once read that a controller method should have no more than 10 lines of code; maybe this is a bit exagerated but you get the point)
So I would say: not only the view should be LINQ free; the controller should be like this too.
Yes you can do it on View but i prefer to use Business logic work done through
controller rather than on View.
View is just used to display the GUI that must be as basic and simple to reduce the complexity of the GUI.
To make application code consistent, maintainable and reusable put these type of logic on Business Logic Classes except writing on Controller or view.
MVC is about abstraction of concerns.
The code you have posted above is breaking the most important rule of MVC. The view is the view, it has no business logic or data access code. It simply displays data that it is given to it in a nice way that can allow for presentation and user interaction. Think of the view as something you could give to a designer who knows nothing of asp.net.
The problem you have above is a perfect candidate for a ViewModel. The "Model" variable that is being used here is wrong, since you are taking it and then changing it to display something different. If the domain model doesn't fit then the controller should create a ViewModel that looks exactly as the view expects. There are a few ways of doing this. But one way is for example:
public ActionResult DoSomething()
{
List<DomainModel> modelCollection = getListOfDomainModels();
// Perform ViewModel projection
var viewModelList = modelCollection
.GroupBy(t => new { t.OrganizationUnitName, t.OrganizationUnitId, t.ServiceTermDate })
.OrderBy(m =>m.Key.ServiceTermDate)
.ThenBy(m => m.Key. OrganizationUnitId)
.Select(p => new MyViewModel()
{
FullName = t.PersonFullName,
StatusName = t.ServiceTermStatusName,
// etc ...
});
return View("DoSomethingView", viewModelList);
}
Now your Model variable will contain the correct model for the view.
Depending on your project's size and requirements you can make this alot better by performing the whole query in another layer outside of the controller and then projecting to a ViewModel inside your controller.
You should not be doing it in either the View or the Controller. Thus without giving you to much to chew at a a time you will want to have Separation of concerns (SOC) and keep it DRY (Don't repeat yourself) otherwise it becomes a maintenance nightmare.
If you put that code in the view (which is the worst place for it). 1. What happens if you want to use same or similar code elsewhere? 2. How will you step through debugging your code in this manner?
This is the equivalent of placing sql queries in a ASP.NET webforms .aspx file, not even in the code behind .aspx.cs file. Not using your model or a repository pattern and putting the code in the controller is another bad idea as a controller ActionResult has a Single Responsibility (SRP) of handling request, by smothering it with this code you have introduced an anti-pattern. Keep the code clean in organized areas. Don't be afraid to add class library projects. Look up the Repository pattern and eventually get to the point of doing unit testing and using DI (Dependency Injection) not just for unit test, but for a loosely coupled / highly cohesive application.
I like the way model binding in django works: you send stuff that you need in a Json-like way:
'param1': val,
'param2': val
In ASP.NET MVC you can't do it primarily because C# is a static language. You can use ViewData but it's ugly and not recommended.
So I had to create dozens of ViewModels for every view: IndexViewModel, AboutViewModel, etc. And today I got an idea: why not just create one Model class and have Visual Studio generate all necessary fields? It's almost like in django.
return View(new Model
{
Param1 = "asd",
Param2 = "sdf"
});
Param1 & Param2 are not members of the Model class, but Visual Studio will automatically generate them.
Now my question is, is it gonna work? The thing is that there will be a lot of fields in this Model class. And when we pass it to a view, only a small percentage of fields made for that view in particular will be used. Is it gonna be bad performance wise?
Thanks
If you have all these properties on your ViewModel which aren't used (i.e null or whatever) it isn't really going to impact performance. What it will impact however, is your design.
Generally speaking, one model to rule them all as you are proposing is a bit evil and goes against separation of concerns. ViewModel's should be very simple and should be tailored to the view. ViewModel's shouldn't really provide the view with more or less data than what the view needs in order to render.
Consider this....
You have a generic model with 15 properties on it and you only set a handful of them. Somebody else designs a new view and looks at the model, they may not know which of those properties are sent and under what conditions they are set. Consequently they may be attempting to display data that does not exist. This isn't a very clean approach.
I would stick to individual view models and where there is common functionality between views, create an abstraction or base ViewModel from which other view models can extend.
Edit: One other thing you could do is use the new MVC 3 (still in preview) syntax (dynamic) for setting ViewData properties directly as if they were properties.
So rather than doing
ViewData["FirstName"] = "Bob";
You can do
ViewModel.FirstName = "Bob";
This gives you dynamic variables automatically in MVC 3.
Have a look a Clay the 'malleable' object model being used by the Orchard Project.
http://weblogs.asp.net/bleroy/archive/2010/08/16/clay-malleable-c-dynamic-objects-part-1-why-we-need-it.aspx
http://weblogs.asp.net/bleroy/archive/2010/08/18/clay-malleable-c-dynamic-objects-part-2.aspx
There's no reason it shouldn't work.
You can even skip the Model class and create an anonymous type with just the members you need.
return View(new { Amount = 108, Message = "Hello" });
The problem using anonymous types is that you're giving up on auto-completion in the view since you won't be able to type the view according to the model.
Just use dynamic
Say I have an object that gets some data from HttpPost and some from the database. I think I want to allow the ModelBinder to go to the database/repository for the that data missing from the post. In practice, is this a good or bad idea?
I've decided to edit my original answer given my thinking on these types of things has evolved since early 2010.
In my original answer, I basically expressed that, while my instincts told me you shouldn't do this, I was uncomfortable saying we shouldn't without being able to articulate why.
Now, I'd recommend against this on the grounds that the responsibility of a Model Binder is to translate a user request into a Request Model and that retrieving data outside of what can be derived from the request goes beyond this scope of responsibility.
I would say a bad idea. The idea of the model binder is that it takes the parameters from the request and creates your model from those. If your model binder, behind the scenes, fills in some of the details from the database this breaks the paradigm. I'd much rather expose the database call in my controller by explicitly fetching the required extra data from the database directly. Note that this could be refactored into a method if used frequently.
I think this is perfectly fine and use this technique all the time.
The only arguments against are very pedantic and amount to arguing over philosophy. IMHO you can put "fill in missing posted data" code into you MVC app as a method in your base controller vs. method in you ActionFilter vs method in you ModelBinder. It all depends on who get what responsibility. To me the model binder can do a lot more than simply wire up some properties from posted values.
The reason I love doing database calls in my modelbinder is because it helps clean up your action methods.
//logic not in modelbinder
public ActionResult Edit( KittyCat cat )
{
DoSomeOrthagonalDatabaseCall( cat );
return View( new MODEL() );
}
vs.
//logic in model binder
public ActionResult Add( KittyCat cat )
{
return View( new MODEL() );
}
It violates the way MVC is supposed to work. ModelBinder is for binging Models from the data that comes from the view. Populating missing info from the database is something that is supposed to be handled by the controller. Ideally, it would have same data layer/repository class that it uses to do this.
The reason it should be in the controller is because this code is business logic. The business rules dictate that some data may be missing and thus it must be handled by the brains of the operation, the controller.
Take it a step further, say you want to log in the DB what info the user isn't posting, or catch an exception when getting the missing data and email admins about it. You have to put these in your model binder this way and it gets more and more ugly with the ModelBinder becoming more and more warped from its original purpose.
Basically you want everything but the controller to be as dumb and as specialized as possible, only knowing out how to carry out its specific area of expertise which is purely to assist the controller.
I would say, no.
Here's why: It would create a dependency on your database for testing your controller actions that would not be easy to abstract out.
I would say it is ok. The argument that creates dependency to database is a false argument for 2 reasons:
1- Database access should be abstracted via repository interfaces. Repository interfaces are part of the domain model and their implementation is part of the infrastructure/data access layer. So there is no dependency to the database.
2- Model Binders and Controllers are both part of presentation layer implemented using ASP.NET MVC Framework. If Controllers are allowed to access database using repository interfaces, how come Model Binders are not allowed?
Also, there are situations that you'd "better" fill the missing data in your model from Model Binders. Consider the scenario where you have a drop-down list on your view. The first time the view is loaded, the drop-down list is populated. The user submits the form but the validation fails. So you'll need to return the form again. At this stage, you'll have to re-populate the list in the Model for the drop-down list. Doing this in Controller looks ugly:
public ActionResult Save(DocumentViewModel viewModel)
{
if (!ModelState.IsValid)
{
viewModel.Categories = _repository.GetAll();
return View(viewModel);
}
}
I believe the initialization of Categories here is ugly and like a code smell. What if you had a few properties that needed to be filled out from database? What if you had more than 1 action that had DocumentViewModel as an argument? You'd have to repeat this ugly step over and over. A better approach is to fill all the properties of the model using the Model Binder and pass it to the Controller. So the object that is passed to the controller is in a "consistent" state.
And what do you put in your View?
A recent blog from Scott Hanselman about using a special model binder for easier testing led me to think about the following:
What do you put in your controller logic building the view model, and what should be put in the view? what he does is this:
var viewModel = new DinnerFormViewModel {
Dinner = dinner,
Countries = new SelectList(PhoneValidator.Countries, dinner.Country)
};
return View(viewModel);
Now, I use the same way of passing data to my view, but I am unsure about how he deals with the Countries property. You could argue both sides:
Wrapping the Countries list in the SelectList prepares the data for the view, much like you create a viewmodel DTO to pass your data.
On the other hand, it somehow feels like you're specifically manipulating the data to be used in a dropdown list, limiting the way the view deals with your data from the controller.
I feel this is a bit of a gray area on the separation of concerns between the view and the controller, and I can't really decide which way to go. Are there any best practices for this?
PS: To keep it simple, let's assume the default ASP.NET MVC context, so basically your out of the box project. Default view engine and all that jazz.
In MVC (at least this flavor of it), one of the controller's responsibilities is to prepare the data for the view. So I think it is perfectly acceptable to prepare a specific model for the views consumption that implies it will be used in a drop-down. In this case the controller is just making it easier for the view and in fact prevents awkward code from having to otherwise be trickling into the view. It also keeps one from having those magic strings in the ViewData like VieData["Countries"].
So to sum up, while it may seem that there is some gray area in terms of responsibilities, ultimately that is the job of the controller: to interact with the view and to transform the domain model into other models that are easier to consume by the view.
Some suggest that having one all-encompassing view model per view is ideal (dubbed Thunderdome Principle).