Problem with strongly typed partial view - asp.net-mvc

I've a problem with Partial View.
I am developing a blog in asp.net mvc and I would make in my masterpage a list of categories, last post, last comments.
I think that the best solution is to use strongly typed partial view, and in each partial view pass the necessary model.
MY problem is that the model in View.. in any view (connected to the masterpage's contentplaceholder) enter in conflict with the models in partial views and I get an error like this:
The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Blog.Models.Articoli]' but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Blog.Models.Categorie]'.
I found on web a dirty solution that consist of to pass togheter the model of any view, some viewdata, one for every model to pass in partial view. But this solution don't respect DRY Principle..because you must repeat this code for each action!
So, my question is: Can I create a model that contain also partial view's model?
If, yes, in that way?
It Exist another solution more simple?
Thanks for help

How about the View Model Pattern?
I've created wrapper classes that are passed to my views rather than whatever object I would normally use
public class MyCreateUserView
{
public User CreatingUser { get; set; }
public MyPartialViewObject Blah { get; set; }
}
In your view write:
public ActionResult CreateUser()
{
MyCreateUserView createUser = new MyCreateUserView()
{
CreatingUser = GetUserFromSomewhere(),
Blah = GetPartialViewObject();
}
return View(createUser);
}
Then your page header looks like so:
<%# Page Language="C#" Inherits="ViewPage<MyCreateUserView>" %>
and when you render your partial write:
<% Html.RenderPartial("../MyPartialViewObject ", Model.Blah); %>

Instead of solving that with the pattern you describe (which is generally a great pattern), I solve that with calls to RenderAction and have it return a partial view. That way the code is in one place as each call to each view does not have to worry about marshalling all the data you need. If you want to see a short discussion on how to use it, I would check Haack's blog here: http://haacked.com/archive/2009/11/18/aspnetmvc2-render-action.aspx. You can also check out the discussion on this other post here on SO: ASP.NET MVC Master Page Data

Related

In a big and complex ASP.NET MVC application is created a model of all other model classes?

I'll explain my point:
The best practice is to create views strongly typed with a Model. You only can stronly type one Model.
If you need two models in a view you can created two views and use Partial Render, but it seems not to be the very best option.
Another approach is to create another type model that encapsulates the other pieces of the model what you need; this make much more sense for me.
Then, my question is, in a complex proyect when a page needs to communicate with all the models and they are not direct realted, developers create a type that encapsulates all the other things?
For non-related parts of your view, you may use Html.Action() to invoke an action that returns a partial view.
This way, the logic of the "area" will be encapsulated in its own action and/or controller.
Update: I don't know if it's really the best practice, but I prefer composition over complex views & view models. Even for related information, I prefer to break it to smaller partial views and child actions. As I see it, it has the following flexibility:
Ability to easily move some of the partial views/child actions to a layout page
Load the partial view asynchronously via AJAX query
Reduced controller action complexity and increased maintainability.
Better support for conditioned rendering
Separation of concerns
In (4) I mean that you can easily do the following without complicating your view model:
<div class="header">
#if (loggedInUser.ShowAds) {
#Html.Action("Header", "Ads")
}
</div>
Answering the question in your comment.
Considering twitter. There's the content pane and the users box on the left.
So here's our TweetsController:
public class TweetsController: Controller {
public ActionResult Index() {
var tweets = ...;
return View(tweets);
}
}
The Tweets/Index view may look like:
#model Tweet[]
<div class="leftPane">
#Html.Action("Index", "Users");
</div>
<div class="mainContent">
#foreach var t in Model {
#t.User - #t.Text
}
</div>
Note that the left pane just calls the Index action in UsersController to display the users list.
Here's how it may look like:
public class UsersController: Controller {
public ActionResult Index() {
var users = ...;
return PartialView(users);
}
}
And here's the partial view (Users/Index):
#model User[]
#foreach var u in Model {
<img src="#u.IconUrl"/> #u.Name
}
So what will actually happen, when the Tweets view will be rendered Html.Action will put the partial view returned by UsersController.Index in the left pane.
Of course you may move this logic into a layout if this behavior is common for a number of pages.
Hope that helps.
Then, my question is, in a complex proyect when a page needs to
communicate with all the models and they are not direct realted,
developers create a type that encapsulates all the other things?
Yes some of them do, and the name for these is ViewModels

Need advice on how to structure asp mvc razor page

I have one page that will contain a lot data.
Outline of the page is on the image.
For output I have used "razor" engine.
Now I wonder will I get something if I refactor my code so each section
which data comes from database will be partial view?
On this page I need about 20 value objects to display all needed data.
I have made one "ViewModel" class that contains all data I need and set that
viewModel class as razor page model. Is this the right way how I should do this or
there is some smarter way?
public class MyViewModelClass{
public ValueObjectx x;
public ValueObjecty y;
public ValueObjectz z;
public List<ValueObjectT> tList;
public List<ValueObjectG> gList;
public List<ValueObjectS> sList;
}
In a scenario like this I would typically have each section as a partial view. Each section is responsible for it's own layout and ViewModel. This prevents the tendency to have a super view which has to know about too many things in order to render.
I would not use one ViewModel for all the data. I would only use the ViewModel for the data that might actually be posted back to the server. For all the other data, like lists, I would put it on the ViewBag. Like:
public ViewResult SomeAction()
{
var model = GetYourModelData();
ViewBag.TList = GetTList();
ViewBag.GList = GetGList();
ViewBag.SList = SList();
return View(model);
}
You could put all the lists in a separate helper object if you use them a lot.
Note that this is not a "this is how you should do it answer", it is more a description of what works for me. But as I see it the model of the view is one thing and the actual data, as data in drop downs etc., on the view is another thing and should be put in the ViewData property, but the ViewBag is just a dynamic wrapper around the ViewData property. You can then use the properties on the ViewBag as input to your partial views that should make up each of your sections.

ASP.NET MVC partial view that updates without controller

I have a partial view that shows a list of Categories. I'd like to put that partial view on any page, but I'd like to have it to call to the service and get a list of categories by itself without me having to do that in every controller action. Something like webforms in which you can put a code-behind on it.
For eg.
Actions
public ActionResult Index()
{
JobListViewModel model = new JobListViewModel();
model.Categories= jobService.GetCategories();
return View(model);
}
public ActionResult Details(int id)
{
Job job = jobService.GetJob(id);
return View(job);
}
I created a partial that will take the model.Categories model and display a list. As you can see, the Index page will work fine, but I do not want to call it again in the Details page. Is there a way to make my partialview call to the GetCategories() service by itself?
Use Html.RenderAction - that gives the partial view its own controller action.
You should also mark you partial action with the attribute [ChildActionOnly].
DVark,
As noted in the accepted answer, for your scenario, RenderAction is the most appropriate.
I thought I'd link a little article that distils my thinking on the topic (i.e. when to use RenderPartial vs RenderAction):
http://cbertolasio.wordpress.com/2010/09/21/mvc-html-renderaction-vs-html-renderpartial/
hope it helps
[edit] - as an aside. a year or so ago, i got myself into a few scrapes by not appreciating the power of RenderAction, in favour of RenderPartial. as a result, i had littered the shared view space with lots of partialviews in order to access them from a variety of sources. the moral of the story: know your 'territory' before planting your flag.

Asp.Net MVC - Strongly Typed View with Two Lists of Same Type

I have a View strongly typed to an Item class. In my controller I need to send two different List. Is there an easier way to do this other than creating a new class with two List.
What I am ultimately trying to do is have on my homepage 10 items ordered by Date, and 10 items ordered by Popularity.
WHAT I DID
I actually went with a combination of the two answers. I strongly-typed my View to the new class I created with the two lists. I then strongly-typed two partial views to the each one of the lists. May seem like overkill, but I like how it turned out.
"creating a new class with two Lists" is the way to go. It's called a view model and once you embrace it, the power of strongly-typed views really opens up. It can be this simple:
public class IndexViewModel
{
public List<Item> Newest { get; set; }
public List<Item> Popular { get; set; }
}
There are two general philosophies to this. The first is to take the approach John Sheehan stanted. You create a custom view model with both lists and pass that to your strongly typed view.
The second is to consider the lists as "ancillary" data and put them in ViewData like jeef3 stated. But, when you render the lists, you use a strongly typed partial.
ViewData["Newest"] = Newest;
ViewData["Popular"] = Popular
By that I mean in your main view, you'd call RenderPartial(...) but pass in the view data key you used.
And your partial would look like:
<%# ViewUserControl Inherits="System.Web.Mvc.ViewUserControl<List<Item>>" %>
...
This gives you strongly typed access to that view data from within your partial.
It's what John suggested or not having a strongly typed view and adding them to the ViewData:
ViewData["Newest"] = Newest;
ViewData["Popular"] = Popular
Another option would be Strongly Typed Partial views.
You should make a model that includes both lists specifically for the view.
Typically in the little MVC I have done, I have made a model for each view even if they just passed along identically data that was served up for by data or business layer just to keep the separation between the two parts very strict. This setup is a little more work and not needed in many simple cases but it does keep things cleaner in my opinion.

Function in ASP.NET MVC

A function returns only one view.
what if I want to return multiple views in a function?
For example, I have this code:
Function Index() As ActionResult
Dim _news As DataTable = News.newsSelect()
Dim _announcement As DataTable = Announcement.SelectAnnouncement()
Return View()
End Function
I want to return _news and _announcement to be used in the aspx page. How would I do this?
Are you trying to show both sets at the same time? News and Announcements?
If so then why not implement either a PartialView or two PartialViews?
Then in your main view you can render them and pass the collection to the PartialViews?
There are heaps of samples on this and the one I recommend is in NerdDinner if you haven't already seen it.
I hope this helps. If you want sample code then let me know.
One simple way is just to have those two datasets sent in a ViewData element, which you can access in a field.
example:
ViewData["Elements"] = new SelectList(aElements, "Guid", "Name");
is consumed as:
<%= Html.DropDownList("Elements","Pick an element")%>
Also, I think that if you read between the lines of this blog post here you will find an elegant way of achieving what you want ;) but its a bit more involved..(only because you mentioned Views instead of just variables..
Quote:
We need to create our own implementation of IViewFactory. This
is responsible for locating and
creating an instance of an IView
(which both ViewPage and
ViewUserControl implement).
To “inject” (all you DI fans excuse me borrowing the term without
using a DI framework) our new View
Factory into every Controller we are
going to create our own
IControllerFactory implementation.
We need to configure the framework to use our new Controller
Factory.
Finally we can create two Views – an AJAX version and a pure
HTML version.
Building on that should be all you need
Good luck!
Ric
Assuming what you are trying to do is use both of those DataTables to populate some View, then my recommendation would be to create a wrapper object and then a strongly typed view based on this object.
The wrapper object would contain properties for all of the data elements that you need in order to render your view properly. In your case, it is 2 DataTable objects. I do not really know VB, so all my examples will be in C#. Here is an example of the data wrapper class...
public class IndexViewData
{
public DataTable News { get; set; }
public DataTable Announcement { get; set; }
}
You then might update the Index action in your controller as follows:
public ActionResult Index()
{
var viewData = new IndexViewData();
viewData.News = News.newsSelect();
viewData.Announcement = Announcement.SelectAnouncement();
return View(viewData);
}
Finally, you would need to create/update your view to be strongly typed. This is done by having your page inherit from the generic System.Web.Mvc.ViewPage<T> class. Just substitute the view data wrapper created earlier for T. To do this, you would set the inherits attribute of the <%# Page %> element. In your case, if we assume your root namespace is called "Foo", you might have the following page declaration in your Index.aspx view (added extra line breaks for readability):
<%# Page Title=""
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<Foo.Models.MyModelType.IndexViewData>"
%>
Once you have a strongly typed view for your view data wrapper, you can access the wrapper object in your view using the Model property. Here is an example of something you could do in your Index.aspx view
<%-- Output some random data (bad example, for demonstration only) --%>
<%= Model.News[0]["title"] %><br/>
<%= Model.Anouncement[0]["body"] %>
In reality you're probably going to do something like iterate over each row of the data table. Regardless, once you create the strongly typed view, your model object, which was passed to the view in the Index method of the controller, is available in the Model property within the view.
You can find detailed tutorials at the ASP.NET MVC site

Resources