foreach GetEnumerator error when converting to Razor syntax - asp.net-mvc

I'm currently in the process of converting the MVC 2 portion of a hybrid Web Forms/MVC 2 application to MVC 3 (I'm not familiar with Web Forms or MVC 2) and have been encountering some problems with some of the foreach statements (which work fine in the original hybrid application).
When converting to Razor, some (not all) of my foreach statements will say something along the lines of:
foreach statement cannot operate on variables of type
'System.Data.Objects.DataClasses.EntityCollection<Project.Activity.PortalMember>'
because
'System.Data.Objects.DataClasses.EntityCollection<Project.Activity.PortalMember>'
does not contain a public definition for 'GetEnumerator'
This is an example .ascx from the Web Forms/MVC 2 application where the foreach works fine:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Project.Activity.PortalGroup>" %>
<% if (Model.PortalMembers.Count() > 0) { %>
<div>
<% foreach (var item in Model.PortalMembers) { %>
<div>
<%: item.SubAccount.FirstName %> <%: item.SubAccount.LastName %>
</div>
<%} %>
</div>
<%} %>
This is my attempt for the .cshtml conversion that is giving me the error:
#model Project.Activity.PortalGroup
#if (Model.PortalMembers.Count() > 0)
{
<div>
#foreach (var item in Model.PortalMembers)
{
<div>
#item.SubAccount.FirstName #item.SubAccount.LastName
</div>
}
</div>
}

Try add reference to System.Data.Linq.dll in your project

Try to add reference to System.Data.Entity.

Related

Postback problem with partial view

I have the following view
<form action="/Questionnaire/Submit" method="post">
<%:"UserName : "%>
<%=ViewData["UserName"]%>
<%=Html.TextBox("test",ViewData["tt"])%>
<p />
<%:"Phone Number :"%>
<%=ViewData["PhoneNumber"]%>
<p />
<%
foreach (var q in Model)
{
Html.RenderPartial("Question", q);
}
%>
<input type="submit" name="submit" value="submit" />
</form>
That render the following partial view
<% using (Html.BeginForm("Submit", "Questionnaire", FormMethod.Post))
{%>
<%:"Question Number "%>
<%=Model.QuestionNumber%>
<%:" "%>
<%=Model.Body%>
<%:" "%>
<%
foreach (var option in Model.Options)
{%>
<p/>
<%=Html.RadioButton(option.QuestionId.ToString(), (option.IsSelected) )%> <%= option.OptionBody%>
<%
}
}
%>
The problem is , The form dosn't submit , and when I remove the "foreach" statment from the master view, It works
My Objective, is to have the updated model ( from the master view and partial view ) to save it later on in DB
Your master view contains a form and then your partial view also creates a form each time it renders, so you will be left with a page containing multiple forms but only one 'Submit' button.
I'm not 100% certain what you need to do, but I'd try and remove the 'BeginForm' call from the partial and see if that fixes the problem.

Cannot get Editor Templates working in MVC3

I am converting a MVC2 app to MVC3.
I cannot seem to join up a View with an Editor Template.
So in my View the code is;
#model IEnumerable<ITOF.Models.LatestContractNumber>
#{
ViewBag.Title = "EditContractNumbers";
Layout = "~/Views/Shared/_Layout.cshtml";
}
using (Html.BeginForm())
{
<fieldset>
<legend>Edit Latest Contract Numbers</legend>
<div style="width:90%">
<div style="width:45%; float:left; vertical-align:top;">
<p>A contract number is in a format: AA/B999</p>
<p>Where AA is a 2 character code for the division, for example CD.</p>
<p>Where B is a letter for the contract, usually the first letter of the contract title.</p>
<p>999 is a 3 digit number.</p>
<p>The 999 number depends on the B letter. </p>
<p>Initially all the numbers start as 1 and are incremented each time the B letter is used.</p>
<p>This pages sets the initial 999 number for each B letter.</p>
<p>Once the application is up and running, this page should be used initially and then no more.</p>
#if (TempData["Message"] != null && TempData["Message"].ToString().Trim().Length > 0)
{
<p class="success">#TempData["Message"].ToString()</p>
}
</div>
<div style="width:45%; float:right; vertical-align:top;">
<div>
<table>
<tr>
<td>Letter</td>
<td>Number</td>
</tr>
#Html.EditorForModel(Model)
</table>
</div>
<div style="padding-top:20px">
<input type="submit" value="Submit Changes" />
</div>
</div>
</div>
</fieldset>
}
And my Editor Template is in the correct folder and now looks like;
#model ITOF.Models.LatestContractNumber
<tr>
<td>
#Html.HiddenFor(model => model.LatestContractNumberId)
#Html.DisplayFor(model => model.Letter)
</td>
<td>
#Html.TextBoxFor(model => model.Number, new { style = "width:30px" })
</td>
</tr>
The Model in #Html.EditorForModel(Model) relates to #model IEnumerable at the top of the page.
In the Editor Template, this should translate to a loop of ITOF.Models.LatestContractNumber, hence at the top of the template I have put #model ITOF.Models.LatestContractNumber
First, you are calling EditorForModel with a model of type IEnumerable<ITOF.Models.LatestContractNumber> (which is the Model for your View) but you should be calling it with ITOF.Models.LatestContractNumber (which is the Model your template expects to see/get). You need a foreach somewhere in there
foreach(ITOF.Models.LatestContractNumber number in Model) {
#Html.EditorForModel(number)
}
Second, not 100% sure, but EditorTemplates should be in Shared folder under the Views folder. So ~/Views/Shared/EditorTemplates/ and should be named after the class name so LatestContractNumber.cshtml.
HTH
The question turned out to be a red herring. The real problem was that having migrated to MVC and started prefixing partial views with _, the name of the Editor Template was invalid.
Thanks to Russ Cam for asking the right questions that got me the answer.

ASP.net mvc EntityCollection is null when saving

I've been trying to figure this out for over a day now but I just can't get this to work.
I have an asp.net MVC website which uses the entityframework for its datamodel.
I need to be able to edit a complex Release entity which contains a List<ReleaseDescription>
I have the following model (Apparantly I cannot upload pictures so I'll just type it out):
public class Release
{
public string Version
..some other primitive properties
public EntityCollection<ReleaseDescription>
}
public class ReleaseDescription
{
public string Description
public Language Language
}
public class Language
{
public string ISOCode
public string Description
}
When looking for a solution for this problem on the web. I found out that using an EntityCollection (see list Release.ReleaseDescription) is not a good idea so in the partial class Release I made an extra property ReleaseDescriptionList which transforms this entityCollection into a List<ReleaseDescription> through the getter, it has no setter.
The problem is that, when saving, my release.ReleaseDescription or even the release.ReleaseDescriptionList is always empty when items should be in it.
Here follows the rest of my code:
My Edit.aspx code looks like this
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<Server.DM.Release>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit</h2>
<% using (Html.BeginForm()) {%>
<%: Html.ValidationSummary(true) %>
... (Code for the primitive properties (works all fine)
<fieldset>
<legend>Descriptions</legend>
<% for(var i =0; i<Model.ListReleaseDescriptions.Count; i++)
{%>
<%: Html.EditorFor(x => Model.ListReleaseDescriptions[i], "ReleaseDescriptionRow")%>
<%} %>
<%= Html.ActionLink("Add another...", "AddDescription", Model) %>
</fieldset>
<p>
<input type="submit" value="Save" />
</p>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
</asp:Content>
The asp code in the DescriptionRelease looks like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Server.DM.ReleaseDescription>" %>Language: <%= Html.TextBoxFor(x => x.Language.ISOCode) %>Qty: <%=Html.TextBoxFor(x => x.Description)%>
(I couldn't get above codeblock on multiple lines sorry)
When I click the save button in the edit screen and I get to my ActionController
[HttpPost]
public ActionResult Edit(Release release)
release.DescriptionRelease does not contain any data when 3 items should be in it.
Any help is appreciated in resolving this issue!
(ps: yes I know there are similar threads on this forum and others but none of it seems to work for me.)
OK, After a lot of searching I finally found an answer for my problem.
I already made an extra property to make up for the EntityCollection but it looked like this:
public IList<ReleaseDescription> ListReleaseDescription
{
get
{
return ReleaseDescription.ToList();
}
}
That didn't work so I made a simple property out of it like so:
public IList<ReleaseDescription> ListReleaseDescription{get; set;}
and I populated this property in my controller. This finally fixed my problem and I got all the data back when saving! I can't believe I wasted 1,5 days on this when the solution was this simple.

How to make update panel in ASP.NET MVC

How do I make an update panel in the ASP.NET Model-View-Contoller (MVC) framework?
You could use a partial view in ASP.NET MVC to get similar behavior. The partial view can still build the HTML on the server, and you just need to plug the HTML into the proper location (in fact, the MVC Ajax helpers can set this up for you if you are willing to include the MSFT Ajax libraries).
In the main view you could use the Ajax.Begin form to setup the asynch request.
<% using (Ajax.BeginForm("Index", "Movie",
new AjaxOptions {
OnFailure="searchFailed",
HttpMethod="GET",
UpdateTargetId="movieTable",
}))
{ %>
<input id="searchBox" type="text" name="query" />
<input type="submit" value="Search" />
<% } %>
<div id="movieTable">
<% Html.RenderPartial("_MovieTable", Model); %>
</div>
A partial view encapsulates the section of the page you want to update.
<%# Control Language="C#" Inherits="ViewUserControl<IEnumerable<Movie>>" %>
<table>
<tr>
<th>
Title
</th>
<th>
ReleaseDate
</th>
</tr>
<% foreach (var item in Model)
{ %>
<tr>
<td>
<%= Html.Encode(item.Title) %>
</td>
<td>
<%= Html.Encode(item.ReleaseDate.Year) %>
</td>
</tr>
<% } %>
</table>
Then setup your controller action to handle both cases. A partial view result works well with the asych request.
public ActionResult Index(string query)
{
var movies = ...
if (Request.IsAjaxRequest())
{
return PartialView("_MovieTable", movies);
}
return View("Index", movies);
}
Basically the 'traditional' server-controls (including the ASP.NET AJAX ones) won't work out-of-the-box with MVC... the page lifecycle is pretty different. With MVC you are rendering your Html stream much more directly than the abstracted/pseudo-stateful box that WebForms wraps you up in.
To 'simulate' an UpdatePanel in MVC, you might consider populating a <DIV> using jQuery to achieve a similar result. A really simple, read-only example is on this 'search' page
The HTML is simple:
<input name="query" id="query" value="dollar" />
<input type="button" onclick="search();" value="search" />
The data for the 'panel' is in JSON format - MVC can do this automagically see NerdDinner SearchController.cs
public ActionResult SearchByLocation(float latitude, float longitude) {
// code removed for clarity ...
return Json(jsonDinners.ToList());
}
and the jQuery/javascript is too
<script type="text/javascript" src="javascript/jquery-1.3.2.min.js"></script>
<script type="text/javascript">
// bit of jquery help
// http://shashankshetty.wordpress.com/2009/03/04/using-jsonresult-with-jquery-in-aspnet-mvc/
function search()
{
var q = $('#query').attr("value")
$('#results').html(""); // clear previous
var u = "http://"+location.host+"/SearchJson.aspx?searchfor=" + q;
$("#contentLoading").css('visibility',''); // from tinisles.blogspot.com
$.getJSON(u,
function(data){
$.each(data, function(i,result){
$("<div/>").html(''+result.name +''
+'<br />'+ result.description
+'<br /><span class="little">'+ result.url +' - '
+ result.size +' bytes - '
+ result.date +'</span>').appendTo("#results");
});
$("#contentLoading").css('visibility','hidden');
});
}
</script>
Of course UpdatePanel can be used in much more complex scenarios than this (it can contain INPUTS, supports ViewState and triggers across different panels and other controls). If you need that sort of complexity in your MVC app, I'm afraid you might be up for some custom development...
If you are new to asp.mvc I recommend you to download the NerdDinner (source) sample application. You will find in there enough information to start working effectively with mvc. They also have ajax examples. You will find out you don't need and update panel.

Creating your own table with CommandArgument buttons in ASP.NET MVC

I'm trying to implement something like this:
<div>
<table>
<thead>
<tr>
<td>Port name</td>
<td>Current port version</td>
<td>New port version</td>
<td>Update</td>
</tr>
</thead>
<% foreach (var ip in Ports) { %>
<tr>
<td>
<%= ip.PortName %>
</td>
<td>
<%= ip.CurrentVersion %>
</td>
<td>
<%= ip.NewVersion %>
</td>
<td>
<asp:Button ID="btnUpdate" runat="server" Text="Update" CommandArgument="<% ip.PortName %>" />
</td>
</tr>
<% } %>
</table>
</div>
The button's CommandArgument property is where my code complains about not being able to resolve symbol ip. Is there any way to do what I'm trying to do?
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
You don't want to use a Webforms button in ASP.NET MVC. MVC is a completely different way of working, and you no longer have the WebForms abstraction.
You have 2 different options you can either replace your asp:Button with an input tag or use a standard hyperlink instead. If you use the input option then you will need to wrap in a form element. The form action should point to a Controller action.
You can't use webform controls in ASP.NET MVC in a trivial manner because they rely on things that are stripped out in MVC. Instead you add a button in two ways, both using the HtmlHelper on the ViewPage:
You can add a button in a form, which is easily handeled in a controller if you have a form for each single button:
<% using(Html.BeginForm("Update", "Ip", new {portName = ip.PortName} )) { %>
....
<input name="action" type="submit" value="Update">
<% } %>
BeginForm() will default to the same controller and action as the view was created from. The other way is to add a link instead, which is more fitting to your example of iterating through a list. For example lets say you have IpController
<%= Html.ActionLink("Update IP", "Update", "Ip",
new {
portName = ip.PortName
})
%>
The link will go to the Update action in IpController with the given portName as parameter. In both cases you'll need this action in IpController:
public ActionResult Update(string portName) {
// ...
}
Hope this helps.
I think you have to enclose your block in Form tags ans runat=server.
FWIW,
I think this text is missing an equals sign:
CommandArgument="<% ip.PortName %>"
Should be
CommandArgument="<%= ip.PortName %>"

Resources