Passing correct model to partial view - c#

I have been looking at this error for quite some time, and can't seem to figure out what I might have done wrong.
I have a partial view which is added like this:
<% Html.RenderPartial("~/Views/ForumPosts/ForumPostCreateForm.ascx", ViewData.Model); %>
And the top of the partial view looks like this:
<%# Control Language="C#" AutoEventWireup="true" Inherits="System.Web.Mvc.ViewUserControl<xxxx.Web.Controllers.ForumThreadsController.ForumThreadFormViewModel>" %>
The error I receive is the following:
The model item passed into the dictionary is of type 'xxx.Core.ForumThread', but this dictionary requires a model item of type 'xxx.Web.Controllers.ForumThreadsController+ForumThreadFormViewModel'.
If am not mistaken both takes the model called ForumThread, but apparently I must have missed something.

You must need to insure about what you are going to pass model into your partial view ,
try to pass a new object of model into partial view

If am not mistaken both takes the
model called ForumThread...
According to the code you posted, the partial view takes a xxxx.Web.Controllers.ForumThreadsController.ForumThreadFormViewModel. Either change the top of your partial view, or find some way to pass a ForumThreadFormViewModel along on a ForumThread object.
Another solution would be to use RenderAction to allow an action to generate the ForumThreadFormViewModel you want.

Please, make sure that your Model is of type xxxx.Web.Controllers.ForumThreadsController.ForumThreadFormViewModel
To check this, look at the point in your controller where its returning the View.
The object that you are putting into the method should be of type ForumThreadFormViewModel

Related

Null Object Exception in MVC Partial View

I have a partial view called _News that when called by itself works as expected.
When I call it from another view using the following code:
<div>
#html.Partial("_News");
</div>
It throws this error:
Object reference not set to an instance of an object
At this line of code in the view:
#foreach (var item in Model) {
Where the view is referencing the model. I realise this means that the view is not being passed the model from the Controller but I am perplexed as to why.
The Controller is called NewsController and is located in Controllers. The View is called _News and is located in Shared Views. The view calling the partial view is the default home/index page.
If your partial needs to access data from the model, you need to pass the model into the Partial() method:
#Html.Partial("_News", Model)
MSDN: http://msdn.microsoft.com/en-us/library/system.web.mvc.html.partialextensions.partial%28v=vs.108%29.aspx
EDIT:
Per your comment below, I think you're actually after this: http://haacked.com/archive/2009/11/17/aspnetmvc2-render-action.aspx - this lets you call a controller action and render the result into the current view.
Could your partial model be a subset or a property of your main views' model? I say could because, to Tieson's point, you can deal with almost any discrepancy between the model the partial wants and the model the view wants... BUT if the model your partial wants is so far disparate from the model your view wants then I will often take that as a possible smell that my two models are not flushed out thoroughly/correctly (basically: "Am I trying to represent too many things or unrelated things on the same page?") .
Additionally, if you can make the model of your partial be a property of the main view's model such that you can pass the model into the partial like this:
#Html.Partial("_News", Model.SomePropertyThatFulfillsTheDataSourceOfThePartial)
then if and when you need to submit the form, this would make model binding much easier as well.

ASP.NET MVC 3 View Engine does not recognise PartialView with .cshtml

The below image shows the Partial View GetMovieTypes.cshtml living in the Shared folder
I call the partial view using the line #Html.Partial("GetMovieTypes.cshtml") in the Index View of EmployeeController
Issue is I get Server Error when I call the Employee Controller with Index Action
The partial view '_GetMovieTypes.cshtml' was not found or no view
engine supports the searched locations. The following locations were
searched:
~/Areas/Staff/Views/Employee/GetMovieTypes.cshtml.cshtml
But when I rename the PartialView to GetMovieTypes.cshtml.cshtml it works fine
Why is the ViewEngine forcing me to add the .cshtml extension twice
Remove the .cshtml portion:
#Html.Partial("GetMovieTypes")
You simply need to call
#Html.Partial("GetMovieTypes")
Dot is not recognized as extension separator by MVC binding. So if you write
"GetMovieTypes.cshtml" it searches for exactly that name, plus cshtml extension.
you should change your code call into
#Html.Partial("_GetMovieTypes")
as that's the name of your View, I do that all the time.
there is no need to mention the extension, that's only if you are calling from your Controller.
my own example:
You need to remove the .chtml extension:
#Html.Partial("GetMovieTypes")
You can also pass the model you havbe in the "parent" view like this:
#Html.Partial("GetMovieTypes", MovieTypesModel)
With this method, your view and its partial have the same model and information
*Maybe I'm wrong but I think you have an underscore in the name of the view too, so you should call it like this:
#Html.Partial("_GetMovieTypes", MovieTypesModel)

PartialView ViewBag data not available in the parent View when using Html.Action()

Seems like a simple issue but I'm obviously missing something.
I have a ViewBag that I created in a partialView.
The PartialView is being rendered by going through
#Html.Action()
In fact that's the ActionMethod inside of which ViewBag variables are being set.
Once set they're available inside of the partial View, however when we come back to the parent where Html.Action() is being called from ViewBag variables are not longer available.
Any idea how come ? How can I access the ViewBag variables that were assigned inside of the Html.Action() action method ?
P.S.
I saw the following question:
Can't access ViewBag in a partial view in ASP.NET MVC3
...From that I gathered that ViewBag variables are passed when you simply render a partial view ( #Html.Partial() ) but they're not when you render a partial view though another Action Method.
Help please ?
According to this SO post Does a child action share the same ViewBag with its "parents" action?, a child action's ViewData/ViewBag is not accessible from its parent action. This sort of makes sense since information stored in ViewData/ViewBag does not survive redirects, and internally the child action is probably redirecting back to the parent action after it finishes executing. You want to store your data in a location that can survive a single redirect, so try using TempData instead and see if it works.

Re-using a partial view (ascx) across different Controllers and Views

Let's assume I have 2 Controllers, TopicsController and PostsController.
For each controller, I have a couple of views (Index & Details).
The Topic (Index) view inherits System.Web.Mvc.ViewPage<IEnumerable<MessageBoard.Models.Topic>>
The Topic (Details) view inherits System.Web.Mvc.ViewPage<MessageBoard.Models.TopicFormViewModel>
I'm using a TopicFormViewModel because I'm sending additional data along with the Model.
The Post (Details) view just inherits System.Web.Mvc.ViewPage<MessageBoard.Models.Post>
Now, I've created a partial view (CreatePost.ascx) which is (obviously :p) used to create a new Post. I want to be able to re-use this control on all of the views you see above.
Update
I've tried rendering the partial view using <% Html.RenderPartial("New"); %> from my Topics/Index.aspx View, but that results in an exception
The model item passed into the dictionary is of type 'System.Data.Linq.Table`1[MessageBoard.Models.Topic]', but this dictionary requires a model item of type 'MessageBoard.Models.Post'.
Now the problem is that my partial view (CreatePost.ascx) accepts a System.Web.Mvc.ViewUserControl<MessageBoard.Models.Post> and I'm not sure how to pass that from all my views above.
I'm also unsure know how to submit the .ascx values to a certain URL (i.e. /Topics/1/CreatePost), how do I tell the submit button to post to that URL?
Thanks in advance,
Marko
Ciao Marko,
Now the problem is that my partial
view (CreatePost.ascx) accepts a
System.Web.Mvc.ViewUserControl
and I'm not sure how to pass that from
all my views above.
I am not sure I understand what do you mean by "how to pass that from all my views above" but I am sure that you dont have to pass an instance of Post from your views. What is going on is that from your views you will invoke a controller action that creates the Post model object and then bind it to the CreatePost.ascx partial.
I'm also unsure know how to submit the
.ascx values to a certain URL (i.e.
/Topics/1/CreatePost), how do I tell
the submit button to post to that URL?
You have two options:
Inside your CreatePost.ascx partial you are probably using a form.
<% using (Html.BeginForm("action", "controller", FormMethod.Post, new {} )) { %>
If you use in the way I am showing you can change the first and the second params respectively to the names of the Action and the Controller that would habndle your submit.
The second option is using jQuery. Simply set an ID for your form and then
$("#myForm").submit(function(event) {
//post an ajax request to the server
});
Hope this helps!
P.S. To be able to reuse your CreatePost.ascx partial place it inside the shared view folder (where your master page is).
In regards to reusing a partial view which is not in the same view folder, use the following and pass in the model required, alternatively you can define a custom route for it.
<% html.RenderPartial("~/Views/<ControllerName>/<PartialViewName>.ascx", <model>);
#Marko
Another way would be to have in the PostController an Action like the following:
[HttpGet]
public ActionResult CreatePost( int topicId ) {
PostModel pm = _manager.CreateDefaultPost();
pm.TopicID = id;
return PartialView( "CreatePost", pm );
}
Then wherever you want to create a Post you can simply call this action that returns the strong-typed view for your new post.
Even if you have a supplementary http call over the network IMO this solution has the advantage to keep the initialization code of a new Post centralized to a single place.
From the View "point-of-view" the call to the action can be done when the user press the "New Post" button and then inject the received markup inside a modal dialog or in a place of your pleasure in the current page.
Hope it helps!

ASP.NET MVC - Passing a Model referencing a different assembly from a Controller to a View using C#

Given two assemblies:
project.web
project.lib
The project.web assembly references project.lib which contains some business logic. A simple class from project.lib:
public class Person
{
public string Name;
}
In project.web.Controllers:
Using project.lib.models;
public class PersonController : Controller
{
Person person = new Person();
public ActionResult Index()
{
return View(person);
}
}
This is the part where I have some questions. In a lot of sample projects I've seen the following in the View (in this case Index.aspx):
<% #Import Namespace="project.lib.models" %>
Allowing you to use the Model object like this:
<%= Model.Name %>
I haven't gotten that to work like the examples, I've had to do:
<%= (Model as Person).Name %>
or
<%
var person = (Person)Model;
Response.Write(person.Name);
%>
Why is this thus? What is the reason for this thusness? Comments? Suggestions? My class definition looks like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace project.lib.models
{
public class Person
{
public Int64 PersonID;
public string DisplayName;
public string RealName;
}
}
Could you please post your <%# Page %> directive? It should be something like:
<%# Page Language="C#"
[...]
Inherits="System.Web.Mvc.ViewPage<project.lib.models.Person>" %>
Have you tried creating a strongly typed code-behind file for this view instead?
You'd need to update the inherits property of the view to be the code-behind file:
<%# Page Language="C#"
CodeBehind="Index.aspx.cs" Inherits="project.web.Views.People.Index" %>
and then in the code-behind:
namespace project.web.Views.People.Index {
public partial class Index : System.Web.Mvc.ViewPage<project.lib.models.Person>
{}
}
I don't think it's an issue with resolving the System.Web.Mvc.ViewPage class as then the page wouldn't load (you'd get an exception along the lines that System.Web.Mvc.ViewPage cannot be found), and you wouldn't even be able to access the Model property.
Your view may not be strongly typed. Try the following:
Copy the View markup
Delete the View
Go to the controller action that drives the View
Right click within this method, select the Add View option.
Ensure that this is a Strongly typed view and that you properly identify the type of your intended model.
Paste your View markup into the newly created view.
This should work. It doesn't look like you're missing an assembly because you're able to cast the model correctly.
It should be noted that you can do the above without the pain of deleting/restoring a View. Each view has a declaration as its first line that is similar to the following:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<DomainModel.Person>" %>
The important section to understand is the Inherits attribute, which implies that this View extends the MVC ViewPage<DomainModel.Person> class. The Model property will be of type DomainModel.Person at runtime.
Also, there are issues with previous versions of ASP.NET MVC that effectively prevent strongly-typed views from working correctly. See Problem using Add View dialog in ASP.NET MVC RC1 for strongly typed view for more detail.
EDIT: After a bit of detective work by everyone who has posted here, it looks like Visual Studio was referencing older versions of the assembly containing the Person class. Closing the development environment down, clearing out all obj/bin folders, and restarting seems to have fixed this issue.
Update 1: Note that you can be pretty certain that it isn't an issue loading/getting to the types System.Web.Mvc.ViewPage or project.lib.models.Person. As you mentioned in your question, it does work when you use:
<% #Import Namespace="project.lib.models" %>
...
<%= (Model as Person).Name %>
Using System.Web.Mvc.ViewPage<project.lib.models.Person> on the page directive and <%= Model.Name %> must work. Some extra things I would try if that doesn't work:
Remove the import directive when doing so.
Check if you have that namespace added on the web.config.
While none of those 2 above should cause any trouble, if you don't get it to work with what is mentioned before that, it would be a very weird scenario. Also note that if you did add commonly used namespaces in the web.config you can use ViewPage<Person> on the page directive.
The Model.Name you refer to doesn't have to do with importing the namespace, you get it from the type you set in the page directive.
The ViewPage class has the property T Model, which is why you get access to the Name property (you are working with the type you specified).
to do that your view should be strongly typed to your model object in your case the Person class
all you need to make it work is adding refrence to the project.lib and adding updating the page derictive :
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<Project.lib.Models.Person>" %>

Categories

Resources