I have seen some people write #model IEnumerable<WebApplication1.Models.Weight> at the top of their view and some write #model WebApplication1.Models.Weight
I wanted to know the difference between both.Like when to use what?
A razor view which takes an IEnumerable<Entity> as a Model means that a collection of objects (e.g. view models, or entities) is passed as the Model to the page by the controller. e.g.
#model IEnumerable<MyNamespace.Entity>
would match a Controller action such as
[HttpGet]
public ActionResult SearchByName(string startsWith)
{
var entities = Db.Entities
.Where(e => e.StartsWith(startsWith))
.ToList();
return View(entities);
}
So that the view will have access to multiple Entity objects (e.g. the page in question might be an Index or Search result page, where the entries could be listed in tabular fashion with a foreach)
In contrast, a razor view which takes a single object as a Model is just showing the one object, e.g.
#model MyNamespace.Entity
Would be used from a controller action such as
[HttpGet]
public ActionResult Details(int id)
{
var entity = Db.Entities.Find(id);
if (entity == null)
return HttpNotFound();
return View(entity);
}
Means that the view has a single Entity model subject, e.g. the page might be showing the details of one Entity object, or allowing update, or insertion of just one Entity.
The corresponding Model instance object available to the page will be the according type of the #model.
One other point to note is that IEnumerable also expresses immutability, i.e. the View should read the collection, but may not e.g. Add or Delete entities from it (i.e. it is good practice to leave the scaffolded IEnumerable and not change this to e.g. IList or ICollection).
Related
Form 1 is a set of filters, and the "submit" button applies those filters to a GET method. Form 2 is a set of data, and the "submit" button saves that data and also continues the filters via a POST method. The filter options are passed back and forth - the user GETs the initial page, possibly sets up some filters which GETs the same page again in terms of controller method, then the user can modify some data and save via a POST, which then returns back with a GET for the same filtered page.
Simplified (lots more that is likely to be irrelevant):
#model PagedList.IPagedList<xxx.Models.WttPlatformGridRow>
#using (Html.BeginForm("PlatformGridEdit", "Wtt", FormMethod.Get))
{
#Html.CheckBox("ExcludeThrough", (bool)ViewBag.ExcludeThrough)
<input type="submit" value="Filter" />
}
#using (Html.BeginForm("PlatformGridEdit", "Wtt", FormMethod.Post))
{
#Html.Hidden("ExcludeThrough", (bool)ViewBag.ExcludeThrough)
<input type="submit" value="Save" />
}
Simplified controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult PlatformGridEdit(List<WttPlatformGridRow> rows, bool? excludeThrough)
{ etc }
public ActionResult PlatformGridEdit(bool? excludeThrough)
{ etc }
Obviously naming two elements the same is illegal in HTML, and it doesn't work anyway (parameter is null in the C# method).
The answers I've seen so far suggest a single BeginForm with all the data. Fine. Except one is a GET (no data changes) and one is a POST (data changes). User need to be able to bookmark the filter so I can't handle it all as a POST anyway, otherwise the browser will ask the user if resubmitting form data is okay.
I'm also using an IPagedList which (as far as I know) precludes the use of a single model with a list field instead of using ViewBag.
Another option seems to be using client side scripting to copy the value from one field to another. But I don't see how to do this when the parameter name in the controller method is the same for both client side fields.
What is the best way of handling this please?
I have a solution but I can't help thinking there must be a better way.
FWIW, this is what I've done. The two fields have non-identical names (but similar). The "master" version (visible checkbox) has script that copies the value to the "slave" version (hidden field) on submit. The controller method takes both names and decides which is relevant - one or both should be null, but both shouldn't have a value, but we handle that just in case.
Finally, the controller returns the view with the combined value (using the "master" identity).
View - form 1:
bool excludeThrough = ViewBag.ExcludeThrough != null ? ViewBag.ExcludeThrough : false;
#Html.CheckBox("ExcludeThrough", excludeThrough, new
{
#class = "form-control",
onchange = "document.getElementById('ExcludeThroughFilter').value = document.getElementById('ExcludeThrough').value;"
})
View - form 2:
#Html.Hidden("ExcludeThroughFilter", excludeThrough)
Controller:
public ActionResult PlatformGridEdit(..., bool? excludeThrough, bool? excludeThroughFilter)
{
bool excThru = false;
if (excludeThrough.HasValue) excThru = excludeThrough.Value;
if (excludeThroughFilter.HasValue && excludeThroughFilter.Value) excThru = true;
...etc...
}
I'm trying to have two Web API methods in my controller. One for when GET is called with a MyViewModel object in the header, and one without.
MyController.cs:
[Produces("application/json")]
[Route("api/[controller]")]
public class MyController : Controller
{
[HttpGet]
public IEnumerable<UserModel> Get()
{
// ...
}
[HttpGet]
public IEnumerable<UserModel> Get(MyViewModel viewModel)
{
// ...
}
}
But browsing to the route address in Chrome without passing any MyViewModel gives me this error:
AmbiguousActionException: Multiple actions matched. The following
actions matched route data and had all constraints satisfied:
MyController.Get (MyProject)
MyController.Get (MyProject)
If I comment out the parameterless method and put a break point in the parameterized function and browse to the api URL, it looks like rather than the viewModel being null like I expected, it appears to be a new MyViewModel object made with a parameterless constructor. Seems like it may be relevant to my problem.
I'm running on Microsoft.AspNetCore v1.1.2 and Microsoft.AspNetCore.Mvc v1.1.3.
Add attribute routing to one of them.
For example:
[HttpGet("/myaction")]
public IEnumerable<UserModel> Get(MyViewModel viewModel)
{
// ...
}
Or add it to all of them. MVC can't distinguish two methods because viewModel can be null, and doesn't know if it should match first get action or another.
One for when GET is called with a MyViewModel object in the header, and one without.
Model Binding in ASP.NET Core by default uses query parameters as the source for model population, not headers. If you need to fill MyViewModel from the header, use [FromHeader] attribute:
public IEnumerable<UserModel> Get([FromHeader] MyViewModel viewModel)
ASP.NET Core routing implementation is not using headers for routing resolving. As you are using attribute routing, as #Vlado said, you need to use different Route Name for disambiguating actions.
I have a main view using several partial Views.
Each of these partials use a different model and have post action.
My problem is I need one property from my main view's model to be used in one of my partials.
The partial view which I need to pass this property view is the last stage in the process.
The application reaches a partial view that contains a switch statement , based on the status on the item being queried, decides which partial will be rendered.
I have the property passing that far and even have it included in the Renderaction for the partial but I don't know how to retrieve it in the controller, PartialViewResult.
In the main view:
#{Html.RenderPartial("StatusForm", Model.HeadingDataModel.Status, new ViewDataDictionary { { "PurchaseOrderNumber", Model.AccordionModel.LtsSpecific.PurchaseOrderNumber } });}
PurchaseOrderNumber is what I'm after. The value gets passed to the next stage:
#{
var obj = ViewData["PurchaseOrderNumber"];
}
And within the same view:
Html.RenderAction("FinishedCalibrationForm", obj);
How can I retreive this in my controller ?? The following is not correct I know, but you get the idea.
public PartialViewResult FinishedCalibrationForm( string obj)
All help is appreciated.
Calling Html.RenderAction or Html.Action is largely the same as Url.Action. There's many different overloads, but essentially, the first parameter is the action name, the second parameter is going to be either the controller name or an anonymous object of route values, and the third parameter will be an anonymous object of route values if the second parameter was used for the controller name.
Anyways, whatever you pass in the route values will be used to find and call the associated action, which includes parameters for the action. So, for your example:
Html.RenderAction("FinishedCalibrationForm", new { obj = obj })
Would properly pass obj into your action method. As you have it now, it's going to interpret the value of obj as the controller name the action is within, which is obviously not correct.
Maybe it´s a strange question, but imagine this:
//We all know that View is a method...
public ActionResult Something()
{
return View("index");
}
But what if I step before this method to perform some stats
public ActionResult Something()
{
return PerformStats(View("index"));
}
I will have a private method like this:
private ActionResult PerformStats(ViewResult viewResult)
{
//THIS IS WHAT I WANT TO ACCHIEVE:
//*********************************
var contentSent = viewResult.InnerHtml.Lengh; <<-- I wish!
return viewResult;
}
And latter, what i want to do, is to save that ammount of content sent to the client.
It doesn´t matter if it is the exactly quantity of html, even if I get the .count() of a json it will do the trick.
Is any way to know the rendered content on the controller?
Thanks!
OnActionExecuting: Called before action method executes. You can put stats related logic in there.
http://msdn.microsoft.com/en-us/library/system.web.mvc.iactionfilter.onactionexecuting(v=vs.98).aspx
OnActionExecuted: Called after action method executed.
http://msdn.microsoft.com/en-us/library/system.web.mvc.iactionfilter.onactionexecuted(v=vs.98).aspx
Within these methods you can access ActionExecuting and ActionExecutedContext
If you want to get a size of rendered HTML (partial or complete view), then you probably need to:
Find the view that you want to render
Store it in the string builder
Get its length
There is a question that explains how to render view as a string within the action method: In MVC3 Razor, how do I get the html of a rendered view inside an action?
I understand how to return a single collection (List<>) from a controller by returning View({mylist}); then referencing that with razor syntax #Model etc. inside the view page. In my case, I have several different collections I want to use separately on the page. I understand that I can make "the mother of all collections collection" and simply include the collections inside another collection (and return that one), but I'm wondering if there is some way in MVC4 that allows me to handle this situation more gracefully.
Thanks and Happy New Year!
You should create a view model. That is a regular class that will hold all the collection or properties you need in your view.
Check this post: http://msdn.microsoft.com/en-us/vs2010trainingcourse_aspnetmvc3fundamentals_topic7.aspx
You can make use of ViewBag for every collection in controller and use those ViewBag variables View
In controller
public ActionResult HotelDetails(List<HotelDetailsModel> model)
{
ViewBag.HotelDetails = model;
return View();
}
and in View
#{
List<HotelDetailsModel> hotels = (List<HotelDetailsModel>)ViewBag.SearchResultsModel;
if (hotels.Count > 0)
{
foreach (HotelDetailsModel item in hotels)
{
}
}
}