pass a controller parameter to a view - asp.net-mvc

What is the best way to passing a controller parameter to a view? The parameter is not related to any model, so cant do strongly typed view.
Controller:
public ActionResult DisplayParam(string id, string name)
{
return View();
}
View:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<%# Import NameSpace="System.IO" %>
<%# Import NameSpace="System" %>
<%# Import NameSpace="System.Data" %>
<%# Import NameSpace="System.Web" %>
<%# Import NameSpace="System.Text" %>
<%# Import Namespace="MY.Controllers" %>
Controller Parameter
<div>
Controller Parameter id: #id
Controller Parameter name: #name
</div>

The best way is to use a view model:
public class MyViewModel
{
public string Id { get; set; }
public string Name { get; set; }
}
and then have your controller action populate this view model and pass it to the view, just like this:
public ActionResult DisplayParam(string id, string name)
{
var model = new MyViewModel
{
Id = id,
Name = name
};
return View(name);
}
and finally you would have your view strongly typed to this view model and use the information to display it:
<%# Page
Language="C#"
Inherits="System.Web.Mvc.ViewPage<AppName.Models.MyViewModel>"
%>
<div>
Controller Parameter id: <%= Html.DisplayFor(x => x.Id) %>
Controller Parameter name: <%= Html.DisplayFor(x => x.Name) %>
</div>
or if you were using the Razor view engine:
#model AppName.Models.MyViewModel
<div>
Controller Parameter id: #Html.DisplayFor(x => x.Id)
Controller Parameter name: #Html.DisplayFor(x => x.Name)
</div>

Related

Passing Data from Controller to Webform Page

I have a asp.net mvc application. One of it's controller calls an aspx page instead of normal razor view page. I followed this https://www.hanselman.com/blog/MixingRazorViewsAndWebFormsMasterPagesWithASPNETMVC3.aspx
Now the problem is I need to send some data from my controller to that aspx page which I can't do using Viewbag.
Any idea how can I send data from my regular controller to my aspx page?
Passing data using model to view(aspx engine) from controller:
Model:
public class Product
{
public string ProductID { get; set; }
public string ProductName { get; set; }
public int Quantity { get; set; }
public int Price {get; set;}
}
Controller:
public ActionResult Index()
{
List<Product> productLst = new List<Product>{
new Product{ProductID="P01",ProductName="Pen",Quantity=10,Price=12},
new Product{ProductID="P02",ProductName="Copy",Quantity=12,Price=20},
new Product{ProductID="P03",ProductName="Pencil",Quantity=15,Price=22},
new Product{ProductID="P04",ProductName="Eraser",Quantity=20,Price=27}
ViewData["Message"] = "Your message comes here";
return View();
}
ASPX View:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<Product>" %>
<!DOCTYPE html>
<html>
<head runat="server">
<title>Index</title>
</head>
<body>
<div>
<h3>Passing Data From Controller To View using ViewData</h3>
<h3><%= Html.Encode(ViewData["Message"]) %></h3>
<%foreach (var item in Model)
{ %>
<p><%=item.ProductID %></p>
<p><%=item.ProductName %></p>
<p><%=item.Quantity %></p>
<p><%=item.Price %></p>
<%} %>
</div>
</body>
</html>
References for model binding in aspx engine,
https://www.codeproject.com/Articles/391289/Implementing-ASP-NET-MVC-Views-in-three-different
https://weblogs.asp.net/gunnarpeipman/asp-net-mvc-3-using-multiple-view-engines-in-same-project
Assign dynamic HTML attribute for any HTML tags:
<input checked="#isRazor" type="checkbox"><!-- Razor engine -->
<input checked="<%:isASPX%>" type="checkbox"><!-- ASPX engine -->
You can do more mixing of HTML tags with Razor and ASPX View Engine, Following code block shows how you can do that.
Your Sample Html Code or Text #RazorCode (#AnotherRazorCode)
Your Sample Html Code or Text <%: ASPXCode %> (<%:AnotherASPXCode %>)
Instead of that, You can go with creating your own Custom Model to passing the data from Controller to View.
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<YourModel>" %>
<% foreach(var item in Model) { %>
<tr>
<td><%: item.Name %></td>
</tr>
Have you tried passing it through ViewData, like so?
in the action: ViewData["myvar"] = "realvalue";
in the view: string parl = ViewData["myvar"];
NOTE: Alternatively you can use Session like this example:
in MVC action:
Session["UserName"] = "Test";
in WebForms:
string UserName = (string)Session["UserName"];
That is all!

Create UserControl in ASP.NET MVC4

I develop a web application using ASP.NET MVC4 in VS2012, in that a HomeController as Views/Home/Index.aspx.
I created a user control as UC/UC_Menu.ascx in Views Folder.
In Index.aspx page, I coded in below and run ok.
<% Html.RenderPartial("~/Views/UC/UC_Menu.ascx"); %>
Now, I want to UC/UC_Menu.ascx load data in database. How could I do?
In ASP.NET MVC, views and partials are not supposed to be retrieving any data. They are designed for displaying data that has been retrieved by the corresponding controller under the form of a view model.
So basically you should create a view model that will be a projection of your data. For example:
public class MyViewModel
{
public string Foo { get; set; }
public string Bar { get; set; }
}
and then have your controller action fetch the data from the database and project it to the view model:
public class HomeController: Controller
{
public ActionResult Index()
{
MyViewModel model = ... go fetch from db
return View(model);
}
}
and now your Index.aspx view will be strongly typed to this view model and pass the model to your partial view:
<%# Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage<MyNs.MyViewModel>" %>
and then pass the model to the partial for displaying:
<% Html.RenderPartial("~/Views/UC/UC_Menu.ascx", Model); %>
and your partial can now display the data:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyNs.MyViewModel>" %>
<%= Html.DisplayFor(x => x.Foo) %>
<%= Html.DisplayFor(x => x.Bar) %>
Invoking "Child Actions" gives you encapsulation similar to "UserControls".
Note: "UserControls" is a term used in ASP.NET Web Forms. In MVC, you would call it a "PartialView".
You could create a child action on your controller, for example:
public class HomeController : Controller
{
[ChildActionOnly]
public ActionResult Menu()
{
var model = BuildModelFromDB();
return PartialView(model);
}
}
Then invoke it in your view, passing in the ActionName and ControllerName:
<%= Html.Action("Menu", "Home") %>

Return a generic list to the MVC Controller

I have a class that looks like this;
public class item
{
public string Tradingname { get; set; }
}
I have a Partial View that inherits from the "item" class;
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<item>" %>
<%= Html.TextBoxFor(x => x.Tradingname) %>
In my view I create a number of them. Let's Say 2;
<% using (Html.BeginForm())
{ %>
<% Html.RenderPartial("TradingName", new Binding.Models.item()); %><br />
<% Html.RenderPartial("TradingName", new Binding.Models.item()); %><br />
<input type="submit" />
<%} %>
Then in my controller I was hoping to be able to write this;
[HttpPost]
public ActionResult Index(List<item> items)
or
[HttpPost]
public ActionResult Index([Bind(Prefix = "Tradingname")]List<item> items)
But I can't seem to get any data back from my partial views into my List. Anyone know how I can get a variable list of data back from a variable set of partialViews?
I would recommend you using editor templates:
Controller:
public class HomeController: Controller
{
public ActionResult Index()
{
List<item> model = ...
return View(model);
}
[HttpPost]
public ActionResult Index(List<item> items)
{
...
}
}
and in the view:
<% using (Html.BeginForm()) { %>
<%= Html.EditorForModel();
<input type="submit" />
<% } %>
and finally simply move the partial in ~/Views/Home/EditorTemplates/item.ascx (name and location are important):
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<item>" %>
<%= Html.TextBoxFor(x => x.Tradingname) %><br/>

Does ReadOnly(true) work with Html.EditorForModel?

Consider the following setup:
Model:
public class Product
{
[ReadOnly(true)]
public int ProductID
{
get;
set;
}
public string Name
{
get;
set;
}
}
View:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MvcApplication4.Models.Product>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Home Page
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<%= Html.EditorForModel() %>
</asp:Content>
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new Product
{
ProductID = 1,
Name = "Banana"
});
}
}
There result is this:
I was expecting that the ProductID property was not going to be editable via the ReadOnly(true) attribute. Is this supported? If not is there any way to hint ASP.NET MVC that some properties of my model are read-only? I would not like to just hide ProductID via [ScaffoldColumn(false)].
I solved this problem by adding a UIHintAttribute to the property on my class of "ReadOnly".
[UIHint("ReadOnly")]
public int ClassID { get; set; }
Then I simply added a ~\Views\Shared\EditorTemplates\ReadOnly.ascx file to my project with this in it:
<%= Model %>
A really simple way to add custom templates, you could include formatting or whatever.
The ReadOnly and Required attributes will be consumed by the metadata provider but won't be used. If you want to get rid of the input with EditorForModel you'll need a custom template, or [ScaffoldColumn(false)].
For custom template ~/Views/Home/EditorTemplates/Product.ascx:
<%# Control Language="C#" Inherits="ViewUserControl<Product>" %>
<%: Html.LabelFor(x => x.ProductID) %>
<%: Html.TextBoxFor(x => x.ProductID, new { #readonly = "readonly" }) %>
<%: Html.LabelFor(x => x.Name) %>
<%: Html.TextBoxFor(x => x.Name) %>
Also note that the default model binder won't copy a value into a property with [ReadOnly(false)]. This attribute won't influence the UI rendered by the default templates.
<%# Control Language="C#" Inherits="ViewUserControl<Product>" %>
<%: Html.LabelFor(x => x.ProductID) %>
<%: Html.TextBoxFor(x => x.ProductID, new { #readonly = true }) %>
<%: Html.LabelFor(x => x.Name) %>
<%: Html.TextBoxFor(x => x.Name) %>

Pass SelectList "SelectedValue" to Controller Action Method

I have a registration form which displays a users Name (textbox), Email (textbox) and Division (SelectList). The Name and Email are pre-populated (I'm using Windows Authentication, Intranet app), and I want to send the SelectedValue from the DropDown to my controller as an Int32, I don't want to send the entire SelectList back. This list is small now, but will grow to considerable size.
I a class called RegistrationViewModel, it contains public properties for these fields. However, when I use SelectList for the DivisionList, I receive this error: No parameterless constructor defined for this object..
If i change the Type, it works no problem, but Division is null or 0. Is there a way to pass the SelectedValue from a DropDown to a Controller Action method as a Int32?
Edit 1:
I'm not really sure what I'm doing, I've been using MVC for about 48 hours, watched the PDF, TechEd, and TechDays videos.
My apologies, here is my controller code:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Register(RegistrationViewModel rvm)
{
IApplicationContext context = ContextRegistry.GetContext();
IValidationErrors errors = new ValidationErrors();
IValidator validator = (IValidator)context.GetObject("RegistrationValidator");
bool valid = validator.Validate(rvm, errors);
if (valid)
repo.SaveRegistration();
else
ViewData["DivisionList"] = repo.GetDivisions();
return View(rvm);
}
RegistrationViewModel Class
public class RegistrationViewModel
{
public string Name { get; set; }
public string Email { get; set; }
//public SelectList DivisionList { get; private set; }
public int Division { get; set; }
}
Here's the view
<%# Page Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<RegistrationViewModel>" %>
<%# Import Namespace="Project1.Entities"%>
<%# Import Namespace="Project1.Models"%>
<asp:Content ID="registerTitle" ContentPlaceHolderID="TitleContent" runat="server">
Register
</asp:Content>
<asp:Content ID="registerContent" ContentPlaceHolderID="MainContent" runat="server">
...
<% using (Html.BeginForm())
{ %>
<div>
<fieldset>
<legend>Account Information</legend>
<p>
<label for="name">Name:</label>
<%= Html.TextBox("Name", User.Identity.Name.GetDisplayName()) %>
<%= Html.ValidationMessage("username") %>
</p>
<p>
<label for="email">Email:</label>
<%= Html.TextBox("email", User.Identity.Name.GetEmailFromLogin()) %>
<%= Html.ValidationMessage("email") %>
</p>
<p>
<label for="division">Division:</label>
<%= Html.DropDownList("DivisionList", ViewData["DivisionList"] as SelectList)%>
<%= Html.ValidationMessage("confirmPassword") %>
</p>
<p>
<input type="submit" value="Register" />
</p>
</fieldset>
</div>
<% } %>
</asp:Content>
Edit 2:
Eilon: Here is what I changed it too:
Controller:
public ActionResult Register()
{
ViewData["DivisionList"] = repo.GetDivisions();
return View();
}
View:
<%= Html.DropDownList("DivisionValue", ViewData["DivisionList"] as SelectList)%>
I recieve this exception:
There is no ViewData item with the key 'DivisionValue' of type 'IEnumerable'.
When I updated the View to this:
<%= Html.DropDownList("DivisionList", ViewData["DivisionList"] as SelectList)%>
It works just great! It only seems to work if all the "Division" items named identically. If I change the name the View crashes or the ViewModel "Division" property is sent as 0.
Why is that?
The RegistrationViewModel type should contain a simple-typed property such as:
public string DivisionValue { get; set; }
Or change the type to int, DateTime, or whatever the appropriate type is.
In HTML and HTTP the only thing that gets posted back for a drop down list is the name of the field and the selected value.
To get everything to match up you also need to change the view to render a different input name for the drop down list:
<%= Html.DropDownList("DivisionValue", ViewData["DivisionList"] as SelectList)%>
Notice that I'm using "DivisionValue" is the value of the list, and DivisionList as the list of all available items.
I'd just be more explicit with the SelectList type. I'd suggest creating the SelectList in the controller action and forget about casting it in the view. My code works like this (CRUD Edit page):
..in the Action:
ViewData["WorkType.ID"] = new SelectList(this._vacancySvc.GetVacancyWorkTypes(),
"ID", "Name", ViewData["WorkType.ID"] ?? vacancy.WorkType.ID);
..and in the view:
<p><% =Html.Encode("Work Type:") %><br />
<% =Html.DropDownList("Worktype.ID")%><span class="smallgrey">(required)</span><br />
.. you can see that either the initial selection (from DB) is persisted or the ViewData from post backs (like if the form fails validation) thru the use of the [null coalescing operator][1] (??).
Moreover, if i refactored this code, i'd prob like to use a ViewModel object like you are.
The only thing is: (1) you'd never need to reference the ViewModel SelectList property in the view coz MVC auto binds this for us by the Html.DropDownList() overload.. and (2) i'd still need to ref the ViewData in the action anyway to get the selected value from a failed validation post back so what's the point really??

Resources