Although the problem I'll be detailing in this question is quite specific, I guess it should help some other beginner programmers like me. I have this following situation: in the system I'm designing, the user has the option to set the values for his search in the database (instead of just routing the parameter of the controller action to the id of a object in the database, as I've done before), with the following fields:
Power Plant (Drop down list of all of the existing Power Plants)
Generating Units (List box with multiple selection that displays the generating units of the selected Power Plant)
Period (A drop down list with the available time spans, like "Last 7 days" and "Last Month")
Beginning and End Time (If instead of selecting a predefined time, the user wants to define the specific time span)
How can I put this elements on a page and search for the specified values in the database? I mean, how do I make this fields an object that I can send to the POST action, so it can compare to the database and get the values? What I've tried to do included create an editor template for this (but I couldn't understand what I was doing), and also I tried creating a controller to deal with this queries, so I could render just the query in the other pages (but I ended up with a page inside a page, in the best of "yo dawg I haerd u liek" style).
Can you guys give me some help, so I don't have to give up being a programmer and become a rapper?
It is a good example:
http://weblogs.asp.net/rajbk/archive/2010/05/08/asp-net-mvc-paging-sorting-filtering-using-the-mvccontrib-grid-and-pager.aspx
I think it is written in MVC 2, but can easily be converted to 3.
I don't quite understand from your question what entity you are filtering in your view, so i'll just call it "Entity".
in your controller you should have an entity repository (if you are unfamilier with the repository pattern you should look it up)
if you got that set up, filtering shouldn't be too difficult:
Create a view model class as followes:
public class EntityFilterViewModel()
{
string PowerPlanet {get;set;}
string GeneratingUnits {get;set;}
string Period{get;set;} // Simplification, you should use timespan or something.
DateTime BeginTime {get;set;}
DateTime EndTime {get;set;}
}
Next, Have a controller method like this:
public ActionResult Filter(EntityFilterViewModel model)
{
var result = from e in _entityRepository.Entites
where e.PowerPlanet.Equals(model.PowerPlanet) &&
e.GeneratingUnits.Equals(model.GeneratingUnits) &&
e.Periond.Equals(model.Period)
// other filters you would want...
return View("List", result); // use the overload which takes a view name and a viewmodel object
}
You should remember though to account for situations in which the user hasn't filled all the fields in the filtering form
Related
I would like to create a more complex EditorTemplate to select a customer from a list.
I'm aware of the DropDownListFor, but I would like to show cards with customer
pictures and some data not just a regular select list.
What I would like to do:
create an EditorTemplate for customer selecting, for instance... In any POCO Class
public class X{
[Key] int Id {get;set;}
[UIHint("CustomerSelector")] int Custumer_Id {get;set;}
}
And the "CustomerSelector" Editor template be able to query all clients and show them into a rich list.
What is the problem:
It's not a good idea to add querying logic from inside a view. This is against MVC pattern.
It's not very modular to query the customer list in every controller and pass it as argument to the EditorTemplate.
How can I create this EditorTemplate without mess up with the MVC pattern nor duplicate code in every controller?
Unfortunately, there is no truly good way to handle something like this. Your are correct that it's improper for database access to happen within a view. Not only does this violate MVC, but it would also require creating an additional instance of your context in the view, when you should really have just one per request.
The alternative, as you've mentioned, would be to do the query in the controller and then pass that into your view. Honestly, this is probably your best of bad options here.
Another choice I see is to use a child action. A child action allows you to confine the logic of querying the users and passing to a view in just one place. The downside is that that you would have to handle the field naming manually, because the rendering of the child actions view will be outside the scope of the form you're building. In other words, you'd have to do something like:
#Html.Action("CustomerSelect", new { fieldName = "Customer_Id" })
That's not really ideal, either, as now you've got a string that you've got to keep track of, and you'll have to be careful about actually providing the right name. For example, if this was a collection of items, then you'd actually need to pass something like "MyCollection[" + i.ToString() + "].Customer_Id". You can see that this starts to get messy quick. For this reason alone, I'd pretty much nix this as a possible solution.
One final option is to use an HtmlHelper extension. This has the same problem as an editor template would in that you're going to have to new up an instance of your context, but it's at least better in the respect that it's not being done inside a Razor view.
Right consider this scenario, I have a report and that report has comments.
Now when I display the report I want to see the comments and add more comments if required.
So hence I have 3 objects
MyReport
MyReportComment
MyReportCreateViewModel
The first two are there so I can have a report with comments, the third is one created to handle the 2 and so I can create a view.
All's well, but now I want to handle that post - this should suffice.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Details(Models.MyReportCreateViewModel ViewCreateModel)
I want to be sure, I want to bind the comment field (in the MyReportComment) to the one in ViewCreateModel.MyReportComment to avoid overposting.
How would I do that? Normally I would do this.
[Bind(Include="Title,Content")] Models.MyReport report
If it was a 'simple' view taking one simple object, but I don't see how to do this in this instance.
Right there is a simple answer here you can't. The correct day of doing this isn't to pass the complex object in at all (even though it can be done!)
Pass the id and create the object you want to then use something like this
if (TryUpdateModel(instructorToUpdate, "",
new string[] { "LastName", "FirstMidName", "HireDate", "OfficeAssignment" }))
Where the LastName, FirstMidName etc are the attribute names of the class you are trying to update.
That will all populate the errors and help out like that.
My Home Model/View/Controller (which configures the initial state of the page) is working fine.
I also, though, need to respond to changes the user makes on the page (selecting an option from a select, checking a checkbox, etc.), and have not got that to work yet.
Maybe the reason I'm having problems is that I'm trying to reuse my "Home" model, which contains not only what I need for page initialization, but some other things as well. For example, my model:
public class HomeModel
{
public DataTable Units { get; set; }
public DataTable Reports { get; set; }
public DataTable UnitReportPairEmailVals { get; set; }
public DataTable UnitReportPairGenerateVals { get; set; }
. . .
}
...contains things the page needs at first ("Units"and "Reports" and the things represented by the ellipsis dots), but also things only needed later (the other two shown).
I'm wondering if at least part of my problem with getting this data back (via an Ajax call to another method in HomeController) is because I should be using a separate Model and Controller for the Ajax call.
So I'm wondering: is Model/Controller proliferation a code smell/anti-pattern, or necessary? Should I create another Model like:
public class AJAXModel
{
public DataTable UnitReportPairEmailVals { get; set; }
}
...and a corresponding separate Controller for it?
If I have a complex Model, which is used in various scenarios, it seems that every time I pass a model back as the return value (result) of an Action, a lot of superfluous/unpopulated things will also be passed back (only the members that I'm interested in at the time being populated in the Controller, thus passing back a lot of empty/null members).
So my question is, should I create spearate Models/Controllers for each "use case", or is it okay - or even better - to combine a bunch of things into one Model/Controller pair?
There's no compelling reason to limit a Model to a single Controller or to expect that a Controller has only one Model. You could write your entire app in a single Controller (really bad idea, by the way).
Generally, the division is a logical one...a bunch of actions that talk to the same set of Models in one controller. It's more to keep your brain from melting when you open the source file as anything else.
You often have multiple Views and they tend to mach name-for-name with the Actions in your controller...but this isn't strictly enforced.
When you feel like you're getting more data in the View than necessary, this can be simplified by mapping the Model to a ViewModel to simplify the code in the View. Yes, this is MVVM...and again...the brain hurts less dealing with the simpler object in the View.
You can manually map the object in your Controller, or you can use an auto-mapper to do it. There are a number to choose from...and they make the MVVM a simpler thing to do. You don't necessarily need one. They're just helpful.
I am doing big project in Web Forms and entered a big mess of code(can be solved with little refactoring), so I decided to take a peek at mvc, seems like everyone favores it over web forms.
I have dll file with all LINQ to SQL classes and methods for existing sql db and I started teaching myself by reacreating this project in mvc.I first recreated my homepage from webforms to razor, so far so good and I recreated one of the user controls to partial view and looped it.
Partial view is strongly typed with one of L2S class, the thing is there is some raw data in it.Like for example My model for partial view is my L2S class PostDetails: it consist od some data ready from output like: Title, Permalink, ViewsNumber etc. but it also cointains some raw data like UserId(I need to call method from dll to get username),DateTimeCreated(on which I also need to call method to get time difference), In webforms I would do this in codebehind but I'm not sure where to do it in mvc, maybe in controller and pass it in ViewData.I am also asking this for future, not just this case.
You should perform those actions in the controller. The controller is exactly what it sounds like, it controls the data flow between the model and the view.
Here is an example using your PostDetails:
PostDetailsModel
String Title {get;set;}
String Permalink {get;set;}
Int ViewNumber {get;set}
Int UserId {get;set}
DateTime DateTimeCreated {get;set;}
GetDetailsView: this will be requested by your user, and will be a visual representation of the PostDetailsModel (however you want to format that). When this View is requested, a call is made to your controller....
PostDetailsController
//This method will (by default) come from calling [BASEURL]/PostDetails/GetDetails
public ActionResult GetDetails()
{
var details = new PostDetailsModel();
details.UserId = GetUserId();
details.ViewNumber = GetViewNumber();
....
//By default this looks for a view in the PostDetails folder
//by the name of your method (GetDetails)
return View(details);
}
Notice how the controller is the router between the model and the view, basically. A note, however, it would be better to fill your model from methods contained within some sort of business layer (however you implement that). Something like var details = BL.GetDetails();
Also, when the user makes requests to save data, then you can do that with another method that takes the data (whether it be the PostDetailsModel or an int or...) and does whatever it needs to do, then it can redirect back to the display action (or wherever you need it to go)
There is a wealth of information on MVC with a simple google search. Here is Microsoft's overview, but the wikipedia article is very succinct if you just want the basics
In MVC, All your requests will be handled by an action method in a controller. and then controller returns a view. So you can get the data in your controller (or a different layer which will be called from the controller) and pass that data to your view.
Strongly typed views are a clean way of doing things. Create a ViewModel for your scenario. Mostly ViewModels looks similar to the Entities. Ex : For Displaying the details about a customer, i will create a viewModel called "CustomerViewModel"
public class CustomerViewModel
{
public string CustomerId { set;get;}
public string FirstName { set;get;}
}
Then in my CustomerController, I will have a get method for the customer
public class CustomersController : Controller
{
public ActionResult Details(int id)
{
CustomerViewModel objCustomer=new CustomerViewModel;
objCustomer.FirstName="Samuel";
//Instead of hardcoding the values here , you can get it
// from the database using the id and assign to the properties
return View(objCustomer);
}
}
And you will have a view called "Details.chtml" in your Views\Customer
folder which is strongly typed to your CustomerViewModel
#model CustomerViewModel
<div>
<h2>#Model.FirstName</h2>
<p>#Model.CustomerId</h2>
</div>
This can be accessed like http://yourdomain.com/Customer/Details/25
Personally i prefer to keep my controller actions thin. so i write the GetFromDatabase code in a seperate service layer and i just call that method from my action method
I think that you'll find this article very useful:
MVC Overview
It explains in detail, as to what each component should be used for:
Models. Model objects are the parts of the application that implement
the logic for the application s data domain. Often, model objects
retrieve and store model state in a database. For example, a Product
object might retrieve information from a database, operate on it, and
then write updated information back to a Products table in SQL Server.
Views. Views are the components that display the application s user
interface (UI). Typically, this UI is created from the model data. An
example would be an edit view of a Products table that displays text
boxes, drop-down lists, and check boxes based on the current state of
a Products object.
Controllers. Controllers are the components that handle user
interaction, work with the model, and ultimately select a view to
render that displays UI. In an MVC application, the view only displays
information; the controller handles and responds to user input and
interaction. For example, the controller handles query-string values,
and passes these values to the model, which in turn queries the
database by using the values.
I have a model class :
public class YearlyChageRate
{
public int Year { get; set; }
public double Rate { get; set; }
}
and I want to check that Yeae is unique or no and in condition Year is not unique application show an error message to users.How can I check the Year filed is repeated or not?
Here is a good example:
http://tugberkugurlu.com/archive/asp-net-mvc-remote-validation-for-multiple-fields-with-additionalfields-property
And here too: MVC validation for unique
You can use Remote attribute in your model to perform check for unique value in database.
This is official example of Remote attribute: http://msdn.microsoft.com/en-us/library/gg508808(v=vs.98).aspx
And one more: http://www.a2zdotnet.com/View.aspx?Id=198
You could use the [Remote] validation attribute on your view model.
Although you can use DataAnnotations attributes for validation and the [Remote] attribute for checks against the DB, it's not a very good design choice.
Let me explain:
data access is a data-layer matter
validation is a business-layer matter
user input and feedback is a ui matter
With DataAnnotations, you're mixin 3 in 1. It can be faster, but surely not well designed.
You could try a more disciplinate approach, like this:
Have a method at business level that will take your object as a parameter, perform validation internally using a validation framework of your choiche;
This method will call the data access to persist the object only if the validation passed;
This method will always return to the UI the validated object, plus a collection of fields/errors if anything didn't validate;
When you read the output of the method in your ui, you can either display a success page if there were no errors, or redisplay the form with the validation errors returned. To do this, the use of the PRG pattern is highly recommended, as you should never display a page on a POST method. Google for the PRG pattern to learn more about it. MvcContrib has a nice ActionFilter called ModelStateToTempData to make the implementation of the PRG pattern something trivial.