Hi I have spent hours trying to work out how to do this one.
So lets say I have two models:
model 1 - AccountInformation
model 2 - AccountHoldersImages
One account holder can have many images. I am trying to achieve on the accountInformation create view (using Scaffolding) to include the facility to add the images at the same time of creation of the user account. Is this possible?
One account holder can have many images
In which case, AccountHoldersImages must be a part of AccountInformation.
If in different views you are using AccountHoldersImages separately, then may be you can keep the view models separate.
However, for this particular view that you are talking about, you will have to wrap the view models into a single view model as MelancialUK commented above.
Another way is to pass the models as part of ViewData[]. If it is a form, then on post you can use FormCollection parameter of your [HttpPost] action to get your images.
Related
I've become a little lost trying to figure out the correct way to share some data between some partials. I'll do my best to explain the setup:
Layouts
_Layout.cshtml - this is the main layout for the site: top navigation, footer etc.
_SectionLayout.cshtml - this is a sub-layout of _Layout.cshtml and makes the main content area of the site into a header and two lower columns - the left column is a menu, the right loads various page content
Partials
_SectionMenu.cshtml - this is the mark-up for the left hand column menu, it builds the menu based on an ViewModel that it expects to be passed which contains an enumerable list of menu items
_SectionHeader.cshtml - this is the mark-up for the section header, it builds the header similarly to the menu above
All of the above are located in the Shared folder.
A series of controllers use the _SectionLayout style to have a consistent style for areas of the site with related pages. The layout is specified on these controllers via a _ViewStart.cshtml within the Views folder for each controller. Each controller implements an ActionResult method for both _SectionMenu() and _SectionHeader(), returning appropriately populated ViewModels for the section.
The individual pages that the menu loads have been setup to do something along the lines of the following:
if (Request.IsAjaxRequest())
return PartialView();
else
return View();
So that they can be loaded either directly via a standard GET request (which loads the header, menu and layout), or as a partial to be inserted into the right hand column of the layout. Now this is all seems to work well, until I come to deciding how to load data that is shared between actions and partials within the same controller while trying to adhere to DRY where I can and cut down on code re-use. The problem is as follows:
Within a typical controller of this type, a single full load of the page will invoke three ActionResult methods: _SectionHeader(), _SectionMenu() and whatever the main action was. Often, all three of them need to access data from the same, or similar database queries. For example, a ProductController may have an Index action which shows an overview of the product information. The header will need to show the name of the product, the menu will show statistics such as the number of images. All of this data comes from a single query which returns all of the product information from the database, but how am I best able to share this data between the three actions? Some ideas I've had:
Make all the ViewModels inherit from a base view model for that controller and pass it through to the partials after opening it in the main action
Store the data in the ViewBag or ViewData
Just open the database multiple times and hope that my ORM is clever enough to realise it doesn't need to fetch it from the server multiple times within the same request
The first one seems to me to be rather complicated for what is a fairly simple ask. The second always feels like a cheap easy way out and I try to avoid it. The third, I'm not confident enough that what I'm using (Dapper) will know not to go to the server again for the same query.
To make things just a little more complex, some of the Actions for a controller may not need to load the main database query. To extend the example from above, the Images option in the menu of the Product controller may need to run an additional query to load the list of associated images, but if it is being requested as an ajax call, it really doesn't need to load the main query for the header and menu sections.
I'm comfortable with the logic for that, but does every one of the actions within a controller of this type need to look something like the following, or can DRY be leveraged here?
public ActionResult Images(int? id)
{
if (!CheckExists(id))
return HttpNotFound();
// if this is an action that doesn't normally need the shared data,
// only load it if it isn't an ajax request, as then the menu/header will require it
if (!Request.IsAjaxRequest())
LoadSharedData(); // part of the question is how I handle this part
// load the particular model for this page
var model = GetImagesModel();
if (Request.IsAjaxRequest())
return PartialView(model);
else
return View(model);
}
In a section with say 10 similar actions in it, seeing all that extremely similar code repeated tells me that I'm doing something wrong. Thanks in advance for any help. If I haven't explained something well, please ask and I'll do my best to clarify.
Just to make it clear, my question is how do you CREATE multiple objects using a single view. My ViewModel works fine, I can display multiple objects no problem.
Its been a while between .NET coding (last time I was coding in 2.0). I have created an MVC 4 project and successfully created a ViewModel (displaying data on a single view from multiple objects).
However, I cheated. I populated the database directly. I now face the question in reverse, what is the best practice for creating multiple objects from a single view?
In my example, I have a User, who has a userId. The userId is a foreign key in UserDetails.
Just trying to get back into the swing of it and wondering what you guys do?
There are 6 ways to pass multiple object in MVC
ViewModel
Partial View
ViewBag
ViewData
TempData
Tuple
Each one have there own pros and cons.you have to decide base on your issue in hand.
For more information you can refer code project article on it: How to Choose the Best Way to Pass Multiple Models in ASP.NET MVC
Let me give advantage and disadvantage of View Model
ViewModel :
Advantages
ViewModel allows us to render multiple model types in a View as a
single model.
Great intellisense support and compile time error checking on View
page.
ViewModel is good for security purpose also as Views have only what
they exactly need. Core domain models are not exposed to user.
If there is any change in core domain model, you do not need to
change anywhere in View code, just you need to modify corresponding
ViewModel.
Disadvantages
ViewModels add another layer between Models and Views so it increases
the complexity a little bit. So for small and demo applications, we
can use tuple or other ways to keep the things simple for demo.
Option 1:
The best approach is to use strongly typed views with Model or ViewModel.
For Example, you have two classes User and Education, you want to display all education details of user in a view, you can create a custom view model and pass it to view, where you view is strongly typed view model:
public class User
{
public int UserId {get;set;}
public string UserName {get;set}
-------
------
}
public class Education
{
public int UserId {get;set;}
public int DegreeId {get;set;}
public long Marks {get;set;}
---------------
--------------
}
Now create a view Model like this:
public class EducationViewModel
{
public User user {get;set;}
public List<Education> educationList {get;set;}
}
now pass the ViewModel to View and do this in View:
#model AppNameSpace.ViewModels.EducationViewModel
Tip: Create a folder named ViewModels and put all the viewmodel classes in it.
Option2:
Option 2 is to user ViewBag and pass multiple object from control to your view, ViewBag is accessible when you set some value in it in controller, you can access in the view of that action, after that it is automatically washed out, and its null if you access again it.
you can use ViewBag like this:
ViewBag.Message = "Using ViewBag";
and read value like this in View:
string Message = ViewBag.Message as string;
Option 3:
Option 3 is to store data in TempData, its once read only, means you set value in it, and when you read it, its automatically removed, TempData internally uses Session Variables.You can use TempData like this:
TempData["Key"] = "value";
now you read it in view:
string val = TempData["Key"] as string;
after reading it, it will be automatically removed, but you can keep it if you need it further like this:
TempData.Keep("Key");
Assuming a web page, where we want to display a list of movies, register movies and edit those movies.
You could create a controller, and within the controller treat the three views (Index, Create, Edit).
Or you could create two controllers, one for treating the Index and the other to address the Create and Edit. (Since Creating and Editing Model or ViewModel share)
Or you could create three controllers, one for each view.
It can be done in three ways.
But which one is right and why?
you'd want to create one controller for this, MoviesController, for example. The operations within the controller will then make sense since the URL will look like this...
Movies/Create
Movies/Edit
Movies //this will just list the movies.
The controller could then be passed a Movies repository for manipulating or listing the data.
Obviously, you can create three controllers, but this would be overkill and cause maintenance headache.
Because your business model is one , i think you have to use one controller and your required actions and views.
Controllers should be grouped logically around an object\functionality. If all of these three actions are related to Movies, then it should be MovieController with three actions\views.
Making new controller for each action will make your code a bit of mess.
You should create a controller with three actions and views (Index, Create, Edit).
How to send more than one model to the View from Controller?
This seems to be a question that is asked so many times, still there is no good answer for newbyes like me (I have not found it).
One sollution I have found is to create some "Parent" model and return collection of Parent child models. I do not want to create any parent model as both my models are not related to each other.
For example, I have two models that do not have relations between them, they are seperate models, for example, PersonModel and HardwareModel. I have two partials views, one needs PersonModel, another needs HardwareModel.
I have HomeController that returns View. This view displays both partial views. So I need to send PersonModel to _PersonPartialView. And I need to send HardwareModel to _HardwarePartialView.
How to do this?
I believe there should be an option to send Collection of unrelated models to View, but how exactly?
Edit:
Some explantions: we have complicated decisions, based on those we show one ore both partial views. You can think like dashboard. User can see one ore more "dashobard" like panels. So they could be even unrelated to each other. So the real situation is more complicated as we have more than 2 different models and different partialviews.
Maybe I should have absolutely different approach.
If the HomeView requires both PersonModel and HardwareModel, then those two combined are your model. So create eg
class HomeModel
{
PersonModel person;
HardwareModel hardware;
}
and you have your model.
Update
Based on the question update, if you have a dashboard-like page, then one option is to do away with the main view as you currently have it. Have a skeleton view, which defines the panel locations, but not their content. Then use AJAX calls to request partial views to populate the panels. That way, each partial view has its own model, separate from the others and you avoid having one view that need to know about all the models for all the partial views it might end up hosting.
We ended with putting abstract things that are part of several views, but not necessarily part of each model (e.g., cultures) into the ViewData / ViewBag. You can still access them in a strong-typed way by providing an extension method that encapsulates the view bag through a additional class. I'd suggest to put HardwareModel stuff into these, because it sounds like it's not the main thing on your web page.
public static HardwareSettings GetHardwareSettings (this HtmlHelper html)
{
// simplified; add lazy instantiation...
return (HardwareSettings) html.ViewData["hardware"];
}
This is for sure the best you can do. If this doesn't fit your problem, I suggest to reconsider your architecture, as it might be case that there are some flaws in it.
If this models is not linked, you should not return them from single controller method. If it should be showed on one page, you can load this partial views with ajax actions
one of examples how to do this click
Ok, I'm still getting the hang of asp.net and the MVC framework and converting my knowledge over from classic ASP and VB - so please be gentle.
I've got my first view (/home/details/X) functioning well thanks to previous help pointing me in the right direction, now I need to add data from multiple tables and queries/views to the MVC view (I hate that SQL and MVC both use the word view for different meanings).
I'm not looking for someone to write the answer for me (unless they're feeling really energetic), more so for someone to point me in the right direction of what I should be looking at and reading up on to understand it and do this myself.
My problem
There are multiple datasets which I need to display in this view, and each different data set has a proper PK/FK 1-M relationship established, and the resultant records would need to be looped through.
How I would have done this previously
In my classic ASP days, I would have just defined the SQL query at the head of the page where the data was to be used, with a select statement along the lines of:
SELECT * FROM query_name
WHERE query_uniquecolumnname = Request.QueryString("value")
Once that was done, you'd set the do while query_name NOT BOF/EOF up, then drop in the field names you wanted from that query and it was all done.
How do I acheive this now?
So, fast forwarding from my classic ASP knowledge, how do I acheive the same outcome with MVC?
The tables/views I wish to use are already defined within my data model (and the relationships are showing up in there which I would assume is a plus), I just need to work out how I could call these within the page and use the ID of the record being displayed in the Details view to ensure only related data is displayed.
Thanks in advance
The concept you are looking for is called a ViewModel. Essentially this is a custom class that you write that contains all the data that would be used in your view. So it is responsible for amalgamating all the data from the different tables and exposing it as properties. If you're using a data access layer, this is often as simple as bringing a few entities together. If you're using raw SQL to do it, then you would execute your queries when the properties were accessed.
Then you would make your View inherit from the ViewModel, like so:
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MvcApplication1.Models.MyViewModel>" %>
Now in your View, you can access all the different properties of your object simply by writing statements like:
<%= Html.TextBox("MyProperty", Model.MyProperty) %>
To construct your view from your controller, create a new instance of your class (MyViewModel), pass it the ID of the details record that you need, and the logic in your class will take care of getting the right data. Then return your view from your controller like normal.
var myDetailsModel = new MyViewModel(detailsID);
return View(myDetailsModel);
I would recommend reading this primer on ASP.NET MVC
http://weblogs.asp.net/scottgu/archive/2009/04/28/free-asp-net-mvc-nerddinner-tutorial-now-in-html.aspx
It covers most basic scenarios you'll need to get up and running.
If however you want to combine multiple resultsets into one, and then return it as a view, you should create a custom object, and map the resultset to it, then you can bind against your custom object in the view.
When I need to display multiple things like this on a web page, I use typically use RenderAction to do it.
RenderAction allows you to use a controller method dedicated to that particular part of the view (a subview, in effect), so you can pass a single data set of strongly-typed data to that "subview".
RenderAction is in the Microsoft.Web.Mvc ("futures") assembly.
If you are new at all of this, I apologize; this is a bit bleeding edge, but you're going to need to know it anyway. Be sure to check out the NerdDinner tutorial first.
http://www.andreas-schlapsi.com/2008/11/01/renderaction-and-subcontrollers-in-aspnet-mvc/
http://davidhayden.com/blog/dave/archive/2009/04/04/...