I got this line of code from a book. I don't understand how would some one know that controller.List().ViewData.Model could be typecasted as IList??
var people = controller.List().ViewData.Model as IList<Person>;
What you have is a call to an ASP.NET MVC controller but instead of using this to render a view, you're accessing the ViewData directly.
Typically in ASP.NET MVC you'll create a typed view for your views which will inherit from System.Web.Mvc.ViewPage<T> and in this case it would be System.Web.Mvc.ViewPage<IList<Person>>. Once you've created this typed view, within the view you know that ViewData.Model is of type IList<Person>.
Calls like the one you posted are commonly used in unit testing the controllers. In this case you directly call the controller method and get back the ViewResult which has the data inside it. When writing the unit test, you know that ViewData.Model is of type IList<Person> 'cause that's the contract--that's what the unit test is for, to verify that the controller generated a model of the right type and has the right data.
You would have to know the object model, in most cases you are familiar with the framework you are using and the IDE offers many helpful tools to assist with object investigation.
Related
I decided to try avoid view models and pass dynamic data to views, here is the test code I wrote in my controller:
dynamic model = new ExpandoObject();
var user = unitOfWork.UserRepository.Get().First();
model.Title = "Dynamic test";
model.User = user;
return View(model);
And in View:
#Model.Title
#Model.User.UserName
I like this method more because I don't have to write ViewModel class for every controller action, and also don't have to change ViewModel every time I decide to pass a new property to View.
The only downside I see is lack of intellisense in Views, because they are not strongly typed any more, but that doesn't seem as a big problem.
My question is, is there any other downsides of using this approach instead of ViewModels, because I am just starting a new project in my company, and I don't want to regret later if I use this approach...
I believe that the main advantage of creating view models is readability and resuseability of the code.
If I go to your piece of controller which you pasted, technically I can understand it, but I don't know what the model is about from business perspective. Of course you can name it more descriptive, but I don't believe it resolve the issue.
Second thing is reuseability, so I can imagine a lot of situation when multiple views can use the same model or some part of models and in this case you need to copy & paste code which creates you dynamic model or create some helper function which do this for you.
Basically I believe that it will be very painful when those dynamic models need to be changed e.g you removed some property in controller, but you forgot to do the same in some of the views. You won't be informed by compilator that something is wrong.
Additionally without strongly typed view model I believe there is no way to create attribute based model validation (which is very common business case)
The code in View,
#{
var MyModel = Entity.Employees.Select(t=>
new {t.FullName, t.Department.DepartmentName}));
}
#foreach (var e in MyModel ) {
<div> Name: #e.FullName - #e.DepartmentName </div>
}
Controller is empty
public ActionResult Index()
{
return View();
}
I am new to Asp.net MVC. Here is something I learned from book.
Controller retrieves Model data, pass it to View
View consumes Model data
Use Strongly-typed model whenever possible
In controller, when model data is from EF/LinQ query, the type is often anonymous, not strongly-typed when passing to view. On the other side, I want to avoid generating one-time-used strongly-typed model.
Above code retrieves model data from View, it's anonymous-but-strongly-typed. seems I can get benefits from both side.
My question is: Should I populate model data from a view? If No, Why?
I found this helpful: it passes dynamic data between controller and view, it's fluent, but not strongly-typed
No, you should not.
You can read any of the articles online that tell you why MVC is a good pattern. You'll find that you have more opportunities for code reuse, unit-testability, etc.
If you're not using the controller to pass a view model to the view, then you're not really following MVC. You might as well be using Razor Web Pages.
Think of Skinny Controllers, Fat Models and Dumb Views.
Views should contain as little logic as possible. As the view model is created specifically for a view, the only responsibility of the view is to render itself using the view model's data that was created in the controller. If there are a lot of decisions, conversions or other logic in your view, then you are not really using the MVC pattern properly.
So as to your question: create your model in the controller, not in the view.
Thanks for all the good answers, they are right.
But my recent experience tends to say Yes... Only In Certain Case,
My project has a number of grid pages. The sole purpose is displaying some grid data. it is often
Not reused elsewhere.
Not needed a Unit Test.
Often asked to add/delete/change columns
Unit Test -- the Grid data is directly from an entity framework, basically a SQL query, There is no need to unit test a SQL query. (a stored procedure may need).
Change Handling -- it literally takes minutes to make an entity query change, bind to an column, right click the cshtml file & publish to production, all in one file. Asp.net will dynamically compile it.
Performance -- the project is a line of business application. Application performance has not been an issue, whereas programmer's productivity is importance, this approach does not lose any strongly-typed checking, auto-completion, etc.
I'm learning asp.net mvc and found something interesting:
It seems that I can't explicitly define a View's Model from within the View with error message saying that it has no setter.
#{ this.Model = "Hello" } //error
Then I looked at the source code in WebViewPage.cs and a View's Model property is actually like this:
public object Model {
get {
return ViewData.Model;
}
}
Thus the error.
But it's interesting how I can do this: #{ ViewData.Model = "hello"; } and actually be able to use the #model statement, resulting to "hello"
I think I'm looking too much into it, but why is this so?
beginner at C# and ASP.NET
The rule is Separation of Concern...In MVC, a Controller supplies a Model to a View and it will always be the controller that can set/assign a Model to a view....which the Views can use...this is by design...play by rules is what I would say...and If you are learning MVC its great and I would strongly recommend you to read
Stevens Sandersons MVC book
Things like ModelBinders and what not sometimes need to change the model in context, so they need the setter. Another reason is to facilitate unit testing.
However, you would seldom need to do this yourself in views, so abuse it at your own risk.
It is the "pit of success" theory of API design. You aren't supposed to alter the Model property in your view, so they make it harder to do so. But since there may be cases where you have no choice, they don't make it impossible.
There is no magic here. In the first case (as you pointed out), there is not property setter for a Model property. So, you cannot assign anything. And that makes sense -- why do you need to re-assign model from within view?
In the second case you hack/bypass that constraint using ViewData.Model directly. Since it's of Object type, you can assign anything.
(BTW, I assume in the first code snippet you assign "Hello", not 'Hello')
I realize that the best practice is to use strongly typed Views and pass in all needed data in a ViewModel, but I am curious if there are situations where it is actually considered "best practice" to pass data in the ViewBag/ViewData.
In what scenarios is the ViewBag/ViewData preferred for passing data to a view?
update
It's great to hear the various uses everyone has come up with for ViewBag/ViewData. We may never arrive at a "best practice" but it will be great to see the different solutions people have come up with that rely on the ViewBag/ViewData.
I use them rarely, for bits of information that are totally unrelated to the model or view model that I'm passing to the view, again, most of the times I use a view model
I prefer to use some DTO instead of using viewbag. Using DTO make you strong type your viewdata.
Hope this helps.
I typically will use a strongly typed view for displaying any content but will often set ViewBag.Member to the currently logged in member so that it can be used in the main Layout in addition to the specific view.
I have an attribute called PopulateMemberContext which populates ViewBag.Member and I add that attribute to my base controller so that every view will always have the necessary data.
"Right" or "Wrong" I don't know - but it works wonderfully.
i can't say about best practice but i mostly use it when using Editor Templates. e.g if i want to display a dropdown list for editing certain field i make following editor template
<%:Html.DropDownList("GetIDHere", new SelectList((IEnumerable<someModel>)ViewData["xyz"]),"select Author")%>
Then you put UIHint attribute on BookID field of your model for instance
public class Book
{
public int BookID{get;set;}
[UIHint("mytemplate")]
public int AuthorID{get;set;}
}
in such cases, i assume, its particularly fine and clean to use ViewData. this is the way Telerik asp.net mvc projects have coded in their demo projects demo
I was wondering the best practice for unit-testing controller actions that utilize model binding.
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult AddProduct(Product product)
{
}
I was wondering how you invoke the controller's method for unit testing. If you try something like this...
public void Catalog_AddProduct()
{
CatalogController controller = new CatalogController();
// some mocking for controller context, setting form values etc...
controller.AddProduct(// ?);
}
Some might suggest removing Product as a parameter but, I also have another AddProduct controller action that is used for just HTTP-Gets. The only solution I could think of is maybe accepting a namevalue collection (form data) and just using UpdateModel/TryUpdateModel.
I also want to test the model binding itself is working properly so I'd like to put the responsibility of creating the new product to the model binder.
I'm not sure I understand the problem, why can't you just do this:
[TestMethod()]
public void AddProductTest()
{
CatalogController target = new CatalogController(/*testing variables*/);
target.AddProduct(new Product { /* product details for testing */ });
// Test the results
}
Though I think perhaps I'm not understanding the problem. Using the form post variables is a good approach however, this will work really well when you need to do edits of the product and after a while you might find it's much easier to have all your actions take the form post variables and update your model. One thing worth pointing out with the TryUpdateModel and UpdateModel is that we have run into a bug with the Entity Framework, if you try to update an entitiy framework model that is complex it can sometimes throw exceptions. But it's really easy to write your own model updater as we've done.
EDIT:
I'm not sure you'll be able to, or that you need to, test the model binding itself. The model binding is part of the MVC framework and outside the scope of the test for the controller, I wouldn't concern myself with it and assume that it will work within the context of your test.
If you really need to test the model binding, the only way that I know is to pass in the form post variables and then use the TryUpdateModel method.
Now you just provided a ValueProvider to the controller.