ASP.net MVC 2 EditorFor Dictionary Bind - asp.net-mvc-2

I try this, but don't work.
bemutatkozas#Modify = null all the time.
public class Iroda
{
public Dictionary<int,string> bemutatkozas { get; set; }
}
public ActionResult Index()
{
var dct = new Dictionary<int, string>();
dct.Add(1, "magyar");
dct.Add(2, "angol");
dct.Add(3, "olasz");
return View(new Iroda { bemutatkozas = dct });
}
[HttpPost]
public ActionResult Modify(Dictionary<int,string> bemutatkozas)
{
return View();
}
<% using (Html.BeginForm("Modify","Iroda"))
{%>
<%= Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<%= Html.EditorFor(o=>o.bemutatkozas,"MultiLanguageEditor") %>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Dictionary<int, string>>" %>
<% int i = 0; %>
<% foreach (var s in Model)
{ %>
<%= Html.Hidden(Html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix+"["+i+"].key", s.Key) %>
<%= Html.TextBox(Html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix+"["+i+"].value",s.Value) %>
<% i++; %>
<% }%>
Whats the solution?
Thx!

Related

asp:CheckBoxList in a form

I am trying to put a checkboxlist onto a simple form in asp.NET MVC 2. This is the code for it:
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm("HandSurvey", "Resources", FormMethod.Post, new { runat="server" }))
{ %>
<asp:CheckBoxList id="chkListChemical" runat="server">
<asp:ListItem>Fiberglass & resins</asp:ListItem>
<asp:ListItem>Heavy duty oil paints & stains</asp:ListItem>
<asp:ListItem>Mechanics - tools, grease/oil</asp:ListItem>
<asp:ListItem>Metalworking fluids</asp:ListItem>
<asp:ListItem>Paint & Stains in use</asp:ListItem>
<asp:ListItem>Exposure to solvents</asp:ListItem>
<asp:ListItem>Difficult soils</asp:ListItem>
<asp:ListItem>Hydrocarbons</asp:ListItem>
</asp:CheckBoxList>
<% }
%>
</asp:Content>
When I hit this page it gives this error:
Control 'ctl00_MainContent_chkListChemical_0' of type 'CheckBox' must be placed inside a form tag with runat=server.
I thought I was specifying the runat attribute correctly. Or is there something else that I am missing here? If I don't use the helper class and just use a regular form tag, it works.
In ASP.NET MVC you should avoid using server controls. Basically everything that has the runat="server" should not be used (except the content placeholder in WebForms view engine). In ASP.NET MVC you design view models:
public class MyViewModel
{
[DisplayName("Fiberglass & resins")]
public bool Item1 { get; set; }
[DisplayName("Heavy duty oil paints & stains")]
public bool Item2 { get; set; }
...
}
then you have controller actions that manipulate the view model:
// Action that renders the view
public ActionResult Index()
{
var model = new MyViewModel();
return View(model);
}
// Handles the form submission
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// TODO: Process the results
return View(model);
}
and finally you have a strongly typed view:
<% using (Html.BeginForm("HandSurvey", "Resources")) { %>
<div>
<%= Html.CheckBoxFor(x => x.Item1) %>
<%= Html.LabelFor(x => x.Item1) %>
</div>
<div>
<%= Html.CheckBoxFor(x => x.Item2) %>
<%= Html.LabelFor(x => x.Item2) %>
</div>
...
<p><input type="submit" value="OK" /></p>
<% } %>
UPDATE:
As requested in the comments section in order to have those checkboxes dynamically generated from a database it is a simple matter of adapting our view model:
public class ItemViewModel
{
public int Id { get; set; }
public string Text { get; set; }
public bool IsChecked { get; set; }
}
and now we will have our controller action to return a list of this view model:
public ActionResult Index()
{
// TODO: obviously those will come from a database
var model = new[]
{
new ItemViewModel { Id = 1, Text = "Fiberglass & resins" },
new ItemViewModel { Id = 2, Text = "Heavy duty oil paints & stains" },
};
return View(model);
}
and the view will now simply become:
<% using (Html.BeginForm("HandSurvey", "Resources")) { %>
<%= Html.EditorForModel() %>
<p><input type="submit" value="OK" /></p>
<% } %>
and the last part would be to define an editor template for our view model (~/Views/Shared/EditorTemplates/ItemViewModel.ascx):
<%# Control
Language="C#"
Inherits="System.Web.Mvc.ViewUserControl<AppName.Models.ItemViewModel>"
%>
<div>
<%= Html.HiddenFor(x => x.Id) %>
<%= Html.CheckBoxFor(x => x.IsChecked) %>
<%= Html.DisplayFor(x => x.Text) %>
</div>

ASP.NET MVC2 - How to create a form?

How can I create a form in ASP.NET MVC2, send the data to a controller that adds something to the database and then redirects to the home page? Can you give me an example/snippet of how it's done in the View?
For some reason, I have a bug in my form. Here's the code:
AddEvent.aspx
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Add Event</h2>
<% using (Html.BeginForm()) { %>
<div>
<%= Html.LabelFor(x => x.EventName) %>:
<%= Html.TextBoxFor(x => x.EventName) %>
</div>
<div>
<%= Html.LabelFor(x => x.EventDate) %>:
<%= Html.TextBoxFor(x => x.EventDate) %>
</div>
<div>
<%= Html.LabelFor(x => x.EventLocation) %>:
<%= Html.TextBoxFor(x => x.EventLocation) %>
</div>
<div>
<%= Html.LabelFor(x => x.EventDescription) %>: </br>
<%= Html.TextAreaFor(x => x.EventDescription) %>
</div>
<input type="submit" value="Submit" />
<% } %>
HomeController.cs
public ActionResult AddEvent()
{
return View();
}
[HttpPost]
public ActionResult AddEvent(Event e)
{
e.EventCreatorName = Session["UserName"].ToString();
DatabaseModels db = new DatabaseModels();
db.AddEvent(e);
return RedirectToAction("Index", "Home");
}
DatabaseModels.cs
public bool AddEvent(Event e)
{
anEvent eventToAdd = new anEvent();
eventToAdd.creator_nickname = e.EventCreatorName;
eventToAdd.event_category = 1; // TODO
if (e.EventDate == null)
{
eventToAdd.event_date = new DateTime();
}
else
{
eventToAdd.event_date = DateTime.Parse(e.EventDate);
}
eventToAdd.event_location = e.EventLocation;
eventToAdd.event_name = e.EventName;
m_db.AddToevents(eventToAdd);
m_db.SaveChanges();
return true;
}
I type in details in the form and I get the following Exception:
This property cannot be set to a null value.
on event_location. Can anyone help solve this?
The asp.net/mvc site contains numerous examples, videos and tutorials about MVC that are worth reading. Here's an example of how the scenario you are asking about could be implemented:
Model:
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Controller:
public class PersonsController: Controller
{
public ActionResult Index()
{
return View(new Person());
}
[HttpPost]
public ActionResult Index(Person person)
{
// The person object here will have it's FirstName
// and LastName properties bound to whatever values
// the user entered in the corresponding textboxes in the form
// TODO: save person to database
// redirect to /home/index
return RedirectToAction("index", "home");
}
}
View:
<%# Page
Language="C#"
MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<AppName.Models.Person>" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<% using (Html.BeginForm()) { %>
<div>
<%= Html.LabelFor(x => x.FirstName) %>:
<%= Html.TextBoxFor(x => x.FirstName) %>
</div>
<div>
<%= Html.LabelFor(x => x.LastName) %>:
<%= Html.TextBoxFor(x => x.LastName) %>
</div>
<input type="submit" value="Save" />
<% } %>
</asp:Content>
Now you might be wondering about the TODO part. Usually I create a repository to decouple my data access logic from my controller:
public interface IPersonsRepository
{
void Save(Person person);
}
and then use constructor injection of this repository into my controller:
public class PersonsController: Controller
{
private readonly IPersonsRepository _repository;
public PersonsController(IPersonsRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
return View(new Person());
}
[HttpPost]
public ActionResult Index(Person person)
{
// The person object here will have it's FirstName
// and LastName properties bound to whatever values
// the user entered in the corresponding textboxes in the form
// save person to database
_repository.Save(person);
// redirect to /home/index
return RedirectToAction("index", "home");
}
}
Obviously now the last part that's left is the implementation of this repository. This will depend on how/where your data is stored and the particular data access technology you would be using. So are you using a relational database, flat text file, XML file, object database, some database stored on the cloud, ... how are you going to access it: EF, NHibernate, Linq-to-XML, some REST API, ...
Once you make your choice you simply implement the interface and instruct your DI framework to pass the proper implementation to the controller constructor.

Having difficulty with ModelBinding and Dictionary, ASP.NET MVC 2.0

Using the following model, I expect that when the Submit button is hit, the Edit Method to Fire, and the model parameter to have the adjusted values. But it keeps returning an instance of the class with all null values. It is as if no model binding ever happens.
class Trait
{
string Name { get; set; }
// other properties
}
class DesignViewModel
{
Dictionary<Trait, int> Allocation { get; set; }
}
Controller
public ActionResult Create()
{
var model = new DesignViewModel();
// retrieve traits from database
foreach(var trait in Repository.Traits)
model.Allocation.Add(trait, 0);
return View(model);
}
[HttpPost]
public ActionResult Edit(DesignViewModel model)
{
// nothing works yet, so I don't have a lot of code here...
}
HTML
Top Level Page
<%# Page Title="" Language="C#" MasterPageFile="~/Areas/Setup/Views/Shared/Setup.master"
Inherits="System.Web.Mvc.ViewPage<OtherModel>" %>
<% Html.RenderAction("Design", "Test"); %>
Partial View
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<DesignViewModel>" %>
<% using (Html.BeginForm("Edit", "Test", FormMethod.Post ) ) {%>
<div id="eq">
<% foreach (var trait in Model.Allocations) { %>
<div style="margin: 15px;">
<%: trait.Key.Name %>
<br />
<span class="slider"></span>
<%: Html.TextBox(trait.Key.Name, trait.Value, new { #class = "spent" , #readonly = "readonly" })%>
</div>
<% } %>
</div>
<p>
<input type="submit" value="Submit" />
</p>
<% } %>
You need to add [HttpPost] to your Edit method for it to be fired during POST requests.

How to show errors on in the view from a fluentvalidation result in a asp.net mvc 2 app?

I am learning asp.net mvc 2 and fluent validation. My setup is shown after the text here. My problem is that I do not know how to set the errors contained in the res object on the view page in a nice way. How should this be done? As it is now no errors are displayed on the view, but the validation is working quite well. I suspect I have to insert some code where I have written "// Set errors on view" in the code. But what code do I need to put? I was not really able to find any clear answers to this - maybe I am just blind. I am looking forward to your help. Thank you.
My controller:
public class AccountController
{
public ActionResult LogOn()
{
return View();
}
[HttpPost]
public ActionResult LogOn(LogOnModel1 model, string returnUrl)
{
public class LogOnModel1
{
public string UserName { get; set; }
public string Password { get; set; }
public bool RememberMe { get; set; }
}
public class AccountValidator : AbstractValidator<LogOnModel1>
{
public AccountValidator()
{
RuleFor(x => x.UserName).NotNull().WithMessage("Brugernavn skal udfyldes").NotEmpty().WithMessage("Brugernavn skal udfyldes");
RuleFor(x => x.Password).NotNull().WithMessage("Kodeord skal udfyldes").NotEmpty().WithMessage("Kodeord skal udfyldes");
Custom(x => { return Membership.Provider.ValidateUser(x.UserName,x.Password) ? new ValidationFailure(null, "wrong password") : null; });
}
}
FluentValidation.Results.ValidationResult res = new Models.AccountValidator().Validate(model);
if (res.IsValid)
{
FormsService.SignIn(model.UserName, model.RememberMe);
if (!String.IsNullOrEmpty(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
}
else
{
// Set errors on view
}
return View(model);
}
}
My model and validation class:
public class LogOnModel1
{
public string UserName { get; set; }
public string Password { get; set; }
public bool RememberMe { get; set; }
}
public class AccountValidator : AbstractValidator<LogOnModel1>
{
public AccountValidator()
{
RuleFor(x => x.UserName).NotNull().WithMessage("Brugernavn skal udfyldes").NotEmpty().WithMessage("Brugernavn skal udfyldes");
RuleFor(x => x.Password).NotNull().WithMessage("Kodeord skal udfyldes").NotEmpty().WithMessage("Kodeord skal udfyldes");
Custom(x => { return Membership.Provider.ValidateUser(x.UserName,x.Password) ? new ValidationFailure(null, "wrong password") : null; });
}
}
and finally my view:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<TelCountMVC.Models.LogOnModel1>" %>
<asp:Content ID="loginTitle" ContentPlaceHolderID="TitleContent" runat="server">
Log On
</asp:Content>
<asp:Content ID="loginContent" ContentPlaceHolderID="MainContent" runat="server">
<h2>Log On</h2>
<p>
Please enter your username and password. <%: Html.ActionLink("Register", "Register") %> if you don't have an account.
</p>
<% using (Html.BeginForm()) { %>
<%: Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.") %>
<div>
<fieldset>
<legend>Account Information</legend>
<div class="editor-label">
<%: Html.LabelFor(m => m.UserName) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(m => m.UserName) %>
<%: Html.ValidationMessageFor(m => m.UserName) %>
</div>
<div class="editor-label">
<%: Html.LabelFor(m => m.Password) %>
</div>
<div class="editor-field">
<%: Html.PasswordFor(m => m.Password) %>
<%: Html.ValidationMessageFor(m => m.Password) %>
</div>
<div class="editor-label">
<%: Html.CheckBoxFor(m => m.RememberMe) %>
<%: Html.LabelFor(m => m.RememberMe) %>
</div>
<p>
<input type="submit" value="Log On" />
</p>
</fieldset>
</div>
<% } %>
</asp:Content>
I suspect that you have figured this out ages ago.
You lose model state if you call RedirectToAction. You have to return a view and pass the LogOnModel1 model into it.
Connect the view to your model instead of System.Web.Mvc.ViewPage and then in your controller do something like this:
if(! ModelState.IsValid) {
return View("Index", logOnModel1);
}
And here is a link to Jeremy Skinner's (the creator of Fluent Validation) description of how to set it up with MVC 2.

Modelbinding Failing VS2010 asp.net mvc2

The contactAddModel.Search always comes through as null - any ideas?
View declaration
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<rs30UserWeb.Models.StatusIndexModel>" %>
ViewModels
public class StatusIndexModel
{
public ContactAddModel contactAddModel;
public StatusMessageModel statusMessageModel;
}
public class ContactAddModel
{
[Required(ErrorMessage="Contact search string")]
[DisplayName("Contact Search")]
public string Search { get; set; }
}
View content
<% using (Html.BeginForm("AddContact", "Status")) { %>
<div>
<fieldset>
<legend>Add a new Contact</legend>
<div class="editor-label">
<%= Html.LabelFor(m => m.contactAddModel.Search) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(m => m.contactAddModel.Search)%>
<%= Html.ValidationMessageFor(m => m.contactAddModel.Search)%>
</div>
<p>
<input type="submit" value="Add Contact" />
</p>
</fieldset>
</div>
<% } %>
Controller
[HttpPost]
public ActionResult AddContact(Models.ContactAddModel model)
{
if (u != null)
{
}
else
{
ModelState.AddModelError("contactAddModel.Search", "User not found");
}
return View("Index");
}
You should modify the action AddContact like this
AddContact(Models.ContactAddModel contactAddModel)
just replace "model" with "contactAddModel"