My question is about binding in MVC. Could you please help me with it?
My controller:
public class TestController : Controller
{
//
// GET: /Test/
[HttpGet]
public ActionResult Index()
{
return View(new TestModel());
}
public ActionResult Index(TestModel test)
{
return View(test);
}
}
My View:
#model MvcApplication1.Models.TestModel
#using (Html.BeginForm())
{
#Html.TextBoxFor(x => x.test) // or x.Test
<input type="submit" value="Set"/>
}
My model:
public class TestModel
{
public string test { get; set; } // or Test{get;set;}
}
The problem is connected with the name of parameter "test" in controller as I understand. I have just changed it to "model" and the binding is working. But it is not working in original state (the name of parameter is 'test'), 'test' parameter is null.
Please give me understand why the binding is not working in current example. Thank you a lot!
You need an [HttpPost] attribute on your second method. You also cannot use test as your variable name, as it is the same name as the property of the class you're attempting to bind to; the ModelBinder fails to determine which to use. Your code would look as follows:
public class TestController : Controller
{
//
// GET: /Test/
[HttpGet]
public ActionResult Index()
{
return View(new TestModel());
}
//
// POST: /Test/
[HttpPost]
public ActionResult Index(TestModel testModel)
{
return View(testModel);
}
}
Related
I created an Umbraco DocumentType with the alias Personal and created a controller that inherits
Umbraco.Web.Mvc.RenderMvcController
I added two Actions, one is the default action and the other is called Test.
How can I fire the Test Action from the Personal controller?
public class PersonalController : Umbraco.Web.Mvc.RenderMvcController
{
// GET: Personal
public override ActionResult Index(RenderModel model)
{
return base.Index(model);
}
public String Test(RenderModel model)
{
return "fff";
}
}
When I put the url like this: localHost/personal/test it shows:
No umbraco document matches the url '/test'.
Which is right, so how can I call it?
I would do it like this
[HttpPost]
public ActionResult SubmitSearchForm(SearchViewModel model)
{
if (ModelState.IsValid)
{
if (!string.IsNullOrEmpty(model.SearchTerm))
{
model.SearchTerm = model.SearchTerm;
model.SearchGroups = GetSearchGroups(model);
model.SearchResults = _searchHelper.GetSearchResults(model, Request.Form.AllKeys);
}
return RenderSearchResults(model.SearchResults);
}
return null;
}
public ActionResult RenderSearchResults(SearchResultsModel model)
{
return PartialView(PartialViewPath("_SearchResults"), model);
}
See this blog post for the full context behind where this code snippet came from.
http://www.codeshare.co.uk/blog/how-to-search-by-document-type-and-property-in-umbraco/
This is my model
public class MessageSetTypeCollection<T> : CollectionBase where T : MessageSetType, new()
{
public string Name { get; set; }
public string[] Tags { get; set; }
public MessageSetType this[int index]
{
get
{
return (MessageSetType)List[index];
}
}
public void Add(MessageSetType value)
{
List.Add(value);
}
}
This is my controller actions
public ActionResult TestAction()
{
MessageSetTypeCollection<MessageSetType> Model = new MessageSetTypeCollection<MessageSetType>();
Model.Add(new MessageSetType()
{
Alert = "test" // Alert is a public property of the MessageSetType class
});
Model.Add(new MessageSetType()
{
Alert = "test2"
});
return View(Model);
}
[HttpPost]
public void TestAction(MessageSetTypeCollection<MessageSetType> Model)
{
return;
}
In the view I've this code
#using (Html.BeginForm())
{
#Html.EditorFor(a => a[0].Alert)
#Html.EditorFor(a => a[1].Alert)
<input type="submit" value="OK" />
}
When I submit this form to the TestAction action, the inner list into the Model parameter has a Count of 0 elements. Why?
I've also tested this code with List<MessageSetType> model type instead of MessageSetTypeCollection<MessageSetType> and all works correctly. Where is the error?
Please see here source code for List:
http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs
The implementation is pretty different. You don't have a collection of type MessageSetType on which your indexer should work.
I think you can use source code of to adjust your model: MessageSetTypeCollection.
I've resolved inheriting the MessageSetTypeCollection<T> from List<T> instead of CollectionBase
public class MessageSetTypeCollection<T> : List<T> where T : MessageSetType, new()
{
//Omissis
}
In ASP.NET MVC, I have recently found out that:
This doesn't work and results in an HTTP 404.
public class TestController : Controller
{
[HttpGet]
[HttpPost]
public ActionResult Index(TestModel model)
{
return View(model);
}
}
This works fine.
public class TestController : Controller
{
public ActionResult Index(TestModel model)
{
return View(model);
}
}
This also works fine:
public class TestController : Controller
{
[HttpGet]
[ActionName("Index")]
public ActionResult GetIndex(TestModel model)
{
return View("Index", model);
}
[HttpPost]
[ActionName("Index")]
public ActionResult PostIndex(TestModel model)
{
return View("Index", model);
}
}
I would like an explanation of why the first version doesn't work, but the other two do work. I would also appreciate if someone could tell me how I can modify the first version to make it work. I like the first version because it is more concise (1 method rather than 2) and also filters out unnecessary HTTP methods.
HTTP verb attributes are mutually exclusive, a request cannot be both GET and POST at the same time. Instead, you have to do this:
[AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
public ActionResult Index(TestModel model) { ... }
i ve got a weird problem. My view :
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using(Html.BeginForm())
{
<input type="submit" value="asds"/>
}
#Html.Action("Index2")
My Controller:
public class DefaultController : Controller
{
//
// GET: /Default1/
[HttpPost]
public ActionResult Index(string t)
{
return View();
}
public ActionResult Index()
{
return View();
}
//
// GET: /Default1/
[HttpPost]
public ActionResult Index2(string t)
{
return PartialView("Index");
}
[ChildActionOnly()]
public ActionResult Index2()
{
return PartialView();
}
}
When i click on a button [HttpPost]Index(string t) is executed, wich is fine. But after that [HttpPost]Index2(string t) is excuted and thats really weird to me because i ve posted data for Index action not for Index2. My logic tells me that [ChildActionOnly()]ActionResult Index2() instead of HttpPost one.
Why is this happening? How can override this behaviour without renaming [HttpPost]Index2 action?
That's the default behavior. It is by design. If you cannot change the POST Index2 action name you could write a custom action name selector that will force the usage of the GET Index2 action even if the current request is a POST request:
public class PreferGetChildActionForPostAttribute : ActionNameSelectorAttribute
{
public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo)
{
if (string.Equals("post", controllerContext.HttpContext.Request.RequestType, StringComparison.OrdinalIgnoreCase))
{
if (methodInfo.CustomAttributes.Where(x => x.AttributeType == typeof(HttpPostAttribute)).Any())
{
return false;
}
}
return controllerContext.IsChildAction;
}
}
and then decorate your two actions with it:
[HttpPost]
[PreferGetChildActionForPost]
public ActionResult Index2(string t)
{
return PartialView("Index");
}
[ChildActionOnly]
[PreferGetChildActionForPost]
public ActionResult Index2()
{
return PartialView();
}
If you have 5 list views in a controller and in each list you can go to edit, details or delete.
On the edit, details and delete page youo have a link 'return to list'.
What's the best method to 'remember' to which list action you must return?
As a solution I've put some info like CurrentAction in the ViewModel and used that in the View. But if you want to use this with different controllers instead of one...
(You can use a Currentcontroller, CurrentArea, but that's not a 'beautifull' solution)
public class MyController : Controller
{
public ActionResult Index()
{
...
}
public ActionResult List2()
{
...
}
public ActionResult List3()
{
...
}
public ActionResult List4()
{
...
}
public ActionResult Create(...)
{
...
}
[HttpPost]
public ActionResult Create(...)
{
...
}
public ActionResult Edit(...)
{
...
}
[HttpPost]
public ActionResult Edit(...)
{
...
}
public ActionResult Delete(...)
{
...
}
[HttpPost]
public ActionResult Delete(...)
{
...
}
}
thanks
Filip
You can use Request.UrlReferrer Property to examine from where did user come to delete ot edit screens.Then bind url to return to list command.
You can set TempData["ReturnUrl"] in your caller action and then use it to set the url of return to list hyperlink.