I have two an action method
- > RoleURLManagement
which differs with its input parameter in the get compared to the post so we have
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult RoleURLManagement(string id)
{
}
and
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult RoleURLManagement(aspnet_Roles rt)
{
}
The get is bringing back a page based on the id in the URL.
The Post should be updating that record.
Now,
this works perfect locally on my machine,
But I have deployed it, It does not recognise the Post at all.
Not sure why this is happening, on the view I have a BeginForm posting to this method.
Wow
HTML
<% using (Html.BeginForm("RoleURLManagement", "Role", FormMethod.Post))
{%>
<fieldset>
<%-- <legend>Fields</legend>--%>
<div class="display-label">ApplicationId</div>
<div class="display-field"><%: Model.ApplicationId%></div>
<%: Html.TextBoxFor(model => model.ApplicationId, new {#class = "RemoveAttribute" })%>
<div class="display-label">RoleId</div>
<div class="display-field"><%: Model.RoleId%></div>
<%: Html.TextBoxFor(model => model.RoleId, new {#class = "RemoveAttribute" })%>
<div class="display-label">RoleName</div>
<h1><div class="display-field"><%: Model.RoleName%></div></h1>
<%: Html.TextBoxFor(model => model.RoleName, new {#class = "RemoveAttribute" })%>
<%: Html.TextBox("RoleName") %>
<div class="display-label">LoweredRoleName</div>
<div class="display-field"><%: Model.LoweredRoleName%></div>
<%: Html.TextBoxFor(model => model.LoweredRoleName, new {#class = "RemoveAttribute" })%>
<div class="display-label">Description</div>
<div class="display-field"><%: Model.Description%></div>
<%: Html.TextBoxFor(model => model.Description, new {#class = "RemoveAttribute" })%>
</fieldset>
<div class="siteCheck">
<%=Html.SiteMapCheckBoxManagement("checkManagememt", Model)%>
<%=Html.TextArea("t")%>
</div>
<input type="submit" value="Map Sites to Role" />
<% } %>
Hmm... not sure why that isn't work... here are a few stabs at ideas:
1) You aren't passing the id into the post method?
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult RoleURLManagement(string id)
{
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult RoleURLManagement(string id, aspnet_Roles rt)
{
}
2) See if it works when accepting a FormCollection instead of aspnet_Roles: (then get the role based on ID, and do an UpdateModel(role) to apply the changes)
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult RoleURLManagement(string id)
{
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult RoleURLManagement(string id, FormCollection form)
{
}
Of course neither of those explain why it works different on your machine than the server. Do you have different versions of IIS? RC of MVC 2?
Good Luck...
Related
The title just about says it all. I have a complex EF4 entity object that has a list of smaller objects I'd like to bind to checkboxes within my view. I just can't figure out how to satisfy the first argument of Html.CheckboxFor(). Intellisense keeps giving me an error.
Here's my view models:
public class PlatformListing
{
public Platform Platform { get; set; }
public bool IsSelected { get; set; }
}
public class AdminGameReviewViewModel
{
public Game GameData { get; set; }
public List<Genre> AllGenres { get; set; }
public List<PlatformListing> AllPlatforms { get; set; }
}
And my (most likely horrible) controller code which populates the AdminGameReviewViewModel and sends it to the view:
public ActionResult EditReview(int id)
{
var game = _siteDB.Games.Include("Genre").Include("Platforms").Include("Content").Single(g => g.GameID == id);
var genres = _siteDB.Genres.OrderBy(g => g.Name).ToList();
var platforms = _siteDB.Platforms.OrderBy(p => p.Name).ToList();
List<PlatformListing> platformListings = new List<PlatformListing>();
foreach (Platform platform in platforms)
{
platformListings.Add(new PlatformListing { Platform = platform, IsSelected = game.Platforms.Any(p => p.PlatformID == platform.PlatformID) ? true : false });
}
var model = new AdminGameReviewViewModel { GameData = game, AllGenres = genres, AllPlatforms = platforms };
return View(model);
}
I'm just not sure what I'm missing, and it's driving me nuts. The documentation I've found hasn't really shed any light on it, either.
EDIT: relevant view code (partial view to be used for both Create and Edit) -
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<HandiGamer.ViewModels.AdminGameReviewViewModel>" %>
<p>
<%: Html.Label("Game Title") %>
<%: Html.TextBoxFor(model => model.GameData.GameTitle) %>
<%: Html.ValidationMessageFor(model => model.GameData.GameTitle) %>
</p>
<p>
<%: Html.LabelFor(model => model.GameData.Genre) %>
<%: Html.DropDownList("Genre", new SelectList(Model.AllGenres, "GenreID", "Name", Model.GameData.GenreID)) %>
</p>
<p>
<%: Html.Label("Platforms") %><br />
<% foreach(var item in Model.AllPlatforms) { %>
<%: item.Platform.Name %> <%: Html.CheckBox("Platforms[]", item.IsSelected, new { id = item.Platform.PlatformID }) %><br />
<% } %>
</p>
<p>
<%: Html.Label("Review Title") %>
<%: Html.TextBoxFor(model => model.GameData.Content.Title) %>
</p>
<p>
<%: Html.Label("Review") %>
<%: Html.TextAreaFor(model => model.GameData.Content.Text) %>
</p>
<p>
<%: Html.Label("Review Score") %>
<%: Html.DropDownList("Score", new SelectList(new int[] {1, 2, 3, 4, 5}, "ReviewScore")) %>
</p>
<p>
<%: Html.LabelFor(model => model.GameData.Pros) %><br />
<%: Html.TextBox("Pros[]") %><br />
<%: Html.TextBox("Pros[]") %><br />
<%: Html.TextBox("Pros[]") %><br />
<%: Html.TextBox("Pros[]") %><br />
<%: Html.TextBox("Pros[]") %>
</p>
I believe you want something like:
Html.CheckBoxFor(model => model.AdminGameReviewViewModel[i].IsSelected)
within some loop that's defined i in your View. Posting your View might help make this clearer.
I am trying out ASP.Net MVC2 by building a small sample website which, amongst other features provides the user with a 'Contact Us' page. The idea is to allow a user to enter their name, email address, message subject and message. To send the message the user clicks on an ActionLink. This is the view:
<% Html.BeginForm(); %>
<div>
<%: Html.Label("Name")%>
<br />
<%: Html.TextBox("txtName", "",new { style = "width:100%" })%>
<br />
<%: Html.Label("Email address")%>
<br />
<%: Html.TextBox("txtEmail", "", new { style = "width:100%" })%>
<br />
<%: Html.Label("Subject")%>
<br />
<%: Html.TextBox("txtSubject", "", new { style = "width:100%" })%>
<br />
<%: Html.Label("Message")%>
<br />
<%: Html.TextBox("txtMessage", "", new { style = "width:100%" })%>
</div>
<div style='text-align: right;'>
<%:
Html.ActionLink("Send", "SentEmail", new { name = Html.g, sender = "txtEmail", subject = "txtSubject", message="txtMessage" })
%>
</div>
<% Html.EndForm(); %>
The idea is once the ActionLink has been clicked a method in the controller is called into which the username, email address, subject and message will be passed. This is the method in the controller:
public ActionResult SentEmail(string name, string sender, string subject, string message)
{
//Send email here and then display message contents to user.
ViewData["Name"] = name;
ViewData["Message"] = message;
ViewData["ThankyouMessage"] = "Thank you for contacting us. We will be in touch as soon as possible.";
return View();
}
However... when I click the link the values which are passed into the method are null. I have tried creating a route to do this but it doesn't work either. Should I be using another method?
Thank you,
Morris
Actually to achieve what you want to is easier than in your sample. Never heard about Model classes, Model Binder and strong typed views? Here thery are
Model class
public class ContactUsModel
{
public string Name { get; set; }
public string Email { get; set; }
public string Subject { get; set; }
public string Message { get; set; }
}
Then in your controller you should have two action: the first that show the form with default values and the second that receive the form with the data placed by the user. These two actions maps exactly to the HttpGet and HttPost verbs.
[HttpGet]
public virtual ActionResult ContactUs() {
ContactUsModel model = new ContactUsModel();
return View(model);
}
[HttpPost]
public virtual ActionResult ContactUs( ContactUsModel model ) {
//e.g. Save the contact request to database
}
To use this your view shal be strong typed to the ContactUsModel class
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ContactUsModel>" %>
<% using (Html.BeginForm()) { %>
<div>
<%: Html.LabelFor(model => model.Name) %><br />
<%: Html.TextBoxFor(model => model.Name, new { style = "width:100%" })%>
</div>
<div>
<%: Html.LabelFor(model => model.Email) %><br />
<%: Html.TextBoxFor(model => model.EMail, new { style = "width:100%" })%>
</div>
<div>
<%: Html.LabelFor(model => model.Subject) %><br />
<%: Html.TextBoxFor(model => model.Subject, new { style = "width:100%" })%>
</div>
<div>
<%: Html.LabelFor(model => model.Message) %><br />
<%: Html.TextAreaFor(model => model.Message, new { style = "width:100%" })%>
</div>
<div>
<input type="submit" value="Save" />
</div>
<% } %>
the magic of everything this is called ModelBinder. Please read more and more about MVC here.
The action link isn't going to trigger a http post nor will it pass in the values of your form fields, just a http get and not passing through any form data - ideally you'd use an input submit button to post the data. What is certain is that it is good practise that any request that causes creating/updating of data should be done via a http post.
Submit button would just be like.
<input type="submit" value="Send" />
You then have several ways of accessing the form data firstly you could use a FormCollection to access the data
[HttpPost]
public ActionResult SendEmail(FormCollection collection)
{
string email = collection["txtEmail"];
...
}
Secondly you could use the method parameters and rely on model binding, but you must make sure field names match the parameter name so
<%: Html.TextBox("txtEmail", "", new { style = "width:100%" })%>
...would require...
[HttpPost]
public ActionResult SendEmail(string txtEmail)
{
...
}
If this form isn't being posted to the same action thats return the view then you'd also need to change your begin form tag, ideal you should use 'using' with it as well. So you'd get:
<% using (Html.BeginForm("SendEmail", "<controller-name>"))
{ %>
.... form fields in here ...
<input type="submit" value="Send" />
<% } %>
If the button isn't suitable for your design you could use something like:
<input type="image" src="<%: Url.Content("~/Content/images/myimage.gif") %>" value="Send" />
This would have the same effect. To trigger a post from an a tag though you'd need to look at using javascript, I can't remember the exact syntax but off hand I think if you used jquery you'd be looking at something like: (form a single form page only)
Send
But then you create a dependency on javascript where as really you should try have your site degrade gracefully so it can be used by visitors with javascript disabled. There are perhaps more advanced way of achieving this whilst meeting design requirements but that can get heavily into client side code which is probably outside of what you want for your sample.
I gotta the following code in controller and view. The problem is that the model(Photo is an Entity Framework entity) is empty(all fields are nulled). Why?
// GET: /Admin/Photo/Create
public ActionResult Create()
{
return View();
}
//
// POST: /Admin/Photo/Create
[HttpPost]
public ActionResult Create(int id, FormCollection collection)
{
try
{
var file = (HttpPostedFileBase) Request.Files[0];
if (file != null && file.FileName != null)
{
var filename = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Photos/Product/", Path.GetFileName(file.FileName));
file.SaveAs(filename);
var photo = new Photo();
photo.Description = collection["Description"];
photo.Main = collection["Main"].Contains("true");
photo.Filename = Path.GetFileName(file.FileName);
photo.Product_Id = id;
Entities.AddToPhotos(photo);
Entities.SaveChanges();
}
else
{
ModelState.AddModelError("", "Plik musi zostać załadowany.");
return View();
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
<h2>Create</h2>
<% using (Html.BeginForm(null, null, null, FormMethod.Post, new {enctype = "multipart/form-data" })) {%>
<%: Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%: Html.LabelFor(model => model.Description) %>
</div>
<div class="editor-field">
<%: Html.TextBoxFor(model => model.Description) %>
<%: Html.ValidationMessageFor(model => model.Description) %>
</div>
<div class="editor-label">
<label for="MainContent_file">Plik: </label>
</div>
<div class="editor-field">
<asp:FileUpload ID="file" runat="server" />
</div>
<div class="editor-label">
<%: Html.LabelFor(model => model.Main) %>
</div>
<div class="editor-field">
<%: Html.CheckBoxFor(model => model.Main) %>
<%: Html.ValidationMessageFor(model => model.Main) %>
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
<% } %>
<div>
<%: Html.ActionLink("Back to List", "Index") %>
</div>
Update: I checked and the collection is populated with proper fields, but they are all nulled.
Check to make sure that the name attributes in the resulting html match your collection name. You could also change your public ActionResult Create(int id, FormCollection collection) to public ActionResult Create(int id, YourViewModel model) to automagically map the post values to the model.
Check the html source in the browser.
It might be sending them as: "Photo.Description"
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"
I am looking for best practices conforming to the MVC design pattern.
My Entities have the following relationship.
tblPortal PortalId PrortalName
tblPortalAlias AliasId PortalId HttpAlias
Each Portal can have many PortalAlias.
I want to Add a New Portal and then Add the associated PortalAlias.
I am confused on how I should structure the Views and how I should present the Views to the user. I am looking for some sample code on how to accomplish this.
My thoughts are first present the Portal View, let the user add the Portal. Then click the Edit link on the Portal List View and on the Portal Edit View let them Add the PortalAlias.
If so, what should the Edit View look like?
So far I have:
Edit View
<%# Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<MyProject.Mvc.Models.PortalFormViewModel>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" runat="server">
Edit
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Edit</h2>
<% Html.RenderPartial("PortalForm", Model); %>
<div>
<%= Html.ActionLink("Back to List", "Index") %>
</div>
</asp:Content>
PortalForm
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<MyProject.Mvc.Models.PortalFormViewModel>" %>
<%= Html.ValidationSummary("Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<%= Html.ValidationSummary(true) %>
<fieldset>
<legend>Fields</legend>
<div class="editor-label">
<%= Html.LabelFor(model => model.Portal.PortalId) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Portal.PortalId) %>
<%= Html.ValidationMessageFor(model => model.Portal.PortalId) %>
</div>
<div class="editor-label">
<%= Html.LabelFor(model => model.Portal.PortalName) %>
</div>
<div class="editor-field">
<%= Html.TextBoxFor(model => model.Portal.PortalName) %>
<%= Html.ValidationMessageFor(model => model.Portal.PortalName) %>
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
<% } %>
Alias<br /><%-- This display is for debug --%>
<% foreach (var item in Model.PortalAlias) { %>
<%= item.HTTPAlias %><br />
<% } %>
PortalFormViewModel
public class PortalFormViewModel
{
public Portal Portal { get; private set; }
public IEnumerable<PortalAlias> PortalAlias { get; private set; }
public PortalFormViewModel()
{
Portal = new Portal();
}
public PortalFormViewModel(Portal portal)
{
Portal = portal;
PortalAlias = portal.PortalAlias;
}
}
Hopefully you've found an answer to this elsewhere, although based on how difficult it is to find information about this online, it's probably unlikely ...
An MSDN blog linked over to ASP.NET MVC, Entity Framework, Modifying One-to-Many and Many-to-Many Relationships (there's a link to the previous in the series in the first paragraph).
But Editing a variable length list, ASP.NET MVC 2-style seems a little better (and includes sample code).