I'm new to ASP.NET MVC, so far I have read that I have if I have lets say two form in one view, the recommended thing to do, is to have a View model which will have the model associate for each form, this forms are not related in any way just are in the home page, one form is for searching a fly and the other is contact form so as you can see there is no relationship of any kind.
this my "HomePageViewModel"
public class HomePageViewModel
{
public SearchFlyViewModel SearchFly;
public ContactFormViewModel Contact;
}
, in my index file which is the homepage I have this at the top
#model Project.WebSite.Models.HomePageViewModel
now, I have a partial view inside my homepage, this partial view has the search fly form, I did it this way because I use the same form in a lot of places.
My partial view is _QuoteForm in which i have this at the top
#model Project.WebSite.Models.SearchFlyViewModel
when I tried to do this in my homepage
#Html.Partial("_QuoteForm", Model.SearchFly)
an error is showing up in runtime telling me this
The model item passed into the dictionary is of type 'Project.WebSite.Models.HomePageViewModel', but this dictionary requires a model item of type 'Project.WebSite.Models.SearchFlyViewModel'.
Which I don't understand why because I did not pass the HomePageViewModel to my partial view, I passed Model.SearchFly which is of the type SearchFlyViewModel
if someone can help figure it out what I'm missing.
thanks
The second parameter ( "The model" ) of the Html.Partial should not be null.
#Html.Partial("_QuoteForm", Model.SearchFly)
Verify
Model.SearchFly != null
Related
I am new to asp.net mvc4 and there is something i don't understand well.
Why do I have to declare the Model using #model at top of the view, if I already pass an object to the View in the controller.
Taking an example :
Controller:
public ActionResult countryDetails(int id)
{
Country country = db.Country.Find(id);
return View(country);
}
View:
#model MvcApplication2.Models.Country
#{
ViewBag.Title = "countryDetails";
}
...
The controller returns a View with an object as parameter, so the model should be already known. I'm sorry if it is obvious, but I can't figure out why this is not a "double" declaration.
Thanks for you help !
The declaration at the top will do two things for you:
It will allow intellisence to know what type you are using when you type in #Model or use any of the Html helper extensions.
It will also check at runtime that model passed in can be cast to the type the view expects.
Its not necessarily a "double declaration" as it is analogous to specifying a type to a parameter on a method. Like so
Person Someone = new Person();
RenderView(Someone);
...
void RenderView(Person model) { }
By default your view inherits from System.Web.Mvc.WebViewPage<TModel>
You can optionally override this class, it's default ASP.NET inheritance mechanism:
#inherits System.Web.Mvc.WebViewPage<List<CompanyName.MyProduct.MyCategory>>
Or you can just simplify this since MVC3 like this:
#model List<CompanyName.MyProduct.MyCategory>
This sugar syntax was made to simplify code typing.
This declaration give you some things
View automatically cast object to the preferred type
You receive type-defined 'model' property which allows you to access
to your object methods and properties
Just believe that this is a method which accepts object and cast it to the specified type that you provide
The main reason is type-safety, it allows you to work with strongly typed views with the benefit of intellisense, compiler error hints, invalid casting etc.
Also, another reason is for readability - it acts as a reminder to what sort of model it is you are actually dealing with instead of having to keep referring back to the controller.
I'd like to be able to pass a string into my partial view from the calling View - this string will be different depending on the view from which the partial view is rendered. Something like this:
#{ Html.RenderPartial("PartialViews/_BreadcrumbsPartial", "New Item");}
Or
#{ Html.RenderPartial("PartialViews/_BreadcrumbsPartial", Model.Name);}
How can I access this second parameter from within the partial view, since I haven't labeled that parameter? I'd like to avoid passing the whole model in if possible, and just reference that string directly.
Your Partial Must bind to a string
example, at top place this:
#model string
To access the value in your partial, use #Model in place of string param
You could use TempData (or possibly ViewData) which should be accessible in subsequent views. However, I believe you can also pass variables directly, maybe via query string.
Please see this question as well asp.net mvc parameter from page to a partial view
I just noticed that on one page of my site, where I pass a ViewModel to my View page, NHProf is giving the following warning:
This statement executed from the view, which can result in bad performance and/or brittle behaviour.
It then links to this page: http://nhprof.com/Learn/Alerts/QueriesFromViews
My ViewModel consists of just 2 properties:
public IEnumerable<Photo> Photos { get; set; }
public Photo SelectedPhoto { get; set; }
I assign the photos to this ViewModel within my Controller as follows:
PhotoViewModel myViewModel = new PhotoViewModel();
myViewModel.Photos = entity.Photos;
My View obviously inherits this type, and aside from outputting a header (which makes use of the SelectedPhoto object), it just loops through each of the Photos rendering some content for each of them.
NHProf shows the 'problem' query as being where it retrieves the collection of Photos that I'm looping through in my view, though I'm not explicitly telling it to go off and get those records from within my view - I've passed those records within the Photos property of my ViewModel.
I have other pages where I don't need to pass a ViewModel and I simply pass IEnumerable<Photo> to the View, and then render the markup exactly the same as I do in the problem view, and NHProf gives no warnings (as there shouldn't be) in that scenario.
I'm thinking maybe it's related to Lazy Loading, and because my collection is part of a ViewModel, when I go to loop through the Photos property within the ViewModel type, it goes to get those records at that point?
Does anyone have any idea what is happening here? The site functions perfectly, but NHProf just sees that it's doing something from where it shouldn't be doing it?!
You haven't shown how your Photos collection is being populated, but I assume it's as simple as viewModel.Photos = entity.Photos. If that's correct (or something similar), then you're just assigning the lazy-loaded entity collection to your view model.
There are several ways to tackle this, but they're all essentially the same: you need to trigger the loading of your collection before you populate your view model. The easiest way to do it is to just stick a .ToArray() or equivalent onto the collection you're assigning; that'll force a fetch.
You are right. It is related to Lazy loading. Try to load Photos eagerly. And check their relations. Maybe they have some with eager loading, you don't need, or you are trying to use associated entity in your view.
Im starting with MVC2 and i have a simple question:
If i have a typed view with a form inside, and this textbox created with lambda expressions:
<%: Html.TextBoxFor(e => e.Name)%>
When i submit this form the default model binder take the request form, takes the model typed to the view, serialize the data posted (as a this model) and pass it to an action of my controller.
To try to explain myself better, lets imagine that i have a url like localhost/edittestmodel/ID/1 and i have in my controller action the following code:
public ActionResult Edit(int id)
{
TestModel testmodel=new TestModel();
testmodel.Name="texttorenderintotextbox";
//whats the class that place the testmodel properties into the view?
return View(testmodel);
}
What's the responsable class for place the Name property of my testmodel object into the textbox
<%: Html.TextBoxFor(e => e.Name)%>
Thanks in advance.
Best Regards.
Jose.
It's the TextBoxFor helper method that's responsible for generating the input field from the lambda expression.
View's don't have anything to do in POST request and model binding
When you have strong type views, model type is barely used to have the simplicity of code intellisense in view's code (so you can use lambda expressions like in your example).
But when you POST data back, nothing gets checked against the view. It gets checked against controller action parameters though. And if there's a parameter with a certain custom model binder type, that particular model binder is used to process incoming data.
But to answer your question: TextBoxFor checks your strong type view's model and generates particular textbox with correct name attribute. So data from it will be posted back under the correct form field name.
To go even deeper. It's the view engine that parses view's ASPX code and runs all server side scripts including Html.TextBoxFor() call.
What I'm trying to do is rather basic, but I might have my facts mixed up. I have a details page that has a custom class as it's Model. The custom class uses 2 custom objects with yet another custom object a property of one of the 2. The details page outputs a fair amount of information, but allows the user to post a comment. When the user clicks the post button, the page gets posted to a Details action that looks something like this:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Details(VideoDetailModel vidAndComment) { ....}
The only fields on the form that is posted are CommentText and VideoId. Here is what the VideoDetailModel looks like.
public class VideoDetailModel
{
public VideoDetailModel()
{
Video = new VideoDTO();
Comment = new CommentDTO();
}
public VideoDetailModel(VideoDTO vid)
{
Video = vid;
Comment = new CommentDTO();
}
public VideoDTO Video { get; set; }
public CommentDTO Comment { get; set; }
}
VideoDTO has a few properties, but the ones I need are VideoId. CommentDTO's pertinent properties include CommentText (which is posting correctly) and a UserDTO object that contains a userId property. Everything other than the CommentText value is not being posted. I also have the following line on the ascx page, but the model value never gets posted to the controller.
Html.Hidden("Model.Video.VideoId", Model.Video.VideoId);
I'm really not sure what I'm missing here. I suppose if I added more form fields for the properties I need, they would get posted, but I only need 1 form entry field for the CommentText. If I could get the same Model objects value that were sent to the page to post with the page, that would help.
I'll be happy to make any clarifications needed here. I'm just at loss as to what's going on.
UPDATE
Okay, it looks like the solution is rather simple. I think using the RenderPartial in the middle of a form is problematic somehow to how the form gets written in html. I can't really put my finger on why things went bonkers, but if I do my RenderPartials before my form and then begin my form with the text entry field and the hidden VideoId, the default ModelBinder works just fine. I was beginning the form, writing the hidden VideoId, rendering several partial views, create my CommentText field, and then closed the form out. The CommentText field would get bound just fine. The hidden VideoId would not. Maybe I missed a rule somewhere about using RenderPartial.
For completeness, the partial view I was rendering took a Comment object and just wrote out it's CommentText data. Several of these objects would exist for a single Video object. All of this data was in a custom type and passed into the View (the main view) as it's Model. This partial view did not have a form and did not have any data entry fields.
I'd need to see more of your view page code to really give a thorough answer here but for the one snippet you posted:
Html.Hidden("Model.Video.VideoId", Model.Video.VideoId);
Should really be:
Html.Hidden("Video.VideoId", Model.Video.VideoId);
or
Html.Hidden("vidAndComment.Video.VideoId", Model.Video.VideoId);
Either way will work but I tend to prefer the first if your controller action only takes a single parameter. The default model binder will be (in your example) looking for a method parameter named "Model" or failing that will look for a property "Model" on your VideoDetailsModel class. Since neither of those exist, it can't bind "Model.Video.VideoId" to anything.
Is there any Model Binding Security implemented in your mvc site? To explain what I mean, take a look at this page and read the section near the end titled "Model Binding Security". Note that this can be within your code OR in your global.asax file.