httppost returns nothing with complex objects in mvc3 razor vb.net
I'm having issues with my MVC3 vb.net application. When I try to post the changes I've made to the controller, the model is not send to the controller.
At the end I only want that the model returns one value for each batch that is the value that I will save to the database.
When I post the model and try to send to the controller the page sends the following by post:
But I don't know how to convert this querystring to a BatchesForAssignation object, assign it to the model and send to the controller.
NOTE: The values for Client and Datacenters shown in the querystring are not used in the controller. I need the BatchesForAssignation[n].CenterID part.
Can you please point me to found a solution on this?
This are the objects that I'm using in my MVC application (code compacted):
Public class Batch public property ID as integer public property CenterID as integer public property name as string end class
Centers (This object just store all the list of centers that will be assigned to the Batch. The name is just to show the name in the drop down list):
Public class Center public property ID as integer public property name as string end class
(There's also a Batchlist and a Centerlist objects that acts as collections inherited from CollectionBase that stores all the Batch and Center objects. If you need the class definition please let me know but is pretty strightforward).
The model is as follows
Public class ProcessingModel public property BatchesForAssignation as BatchList public property Datacenters as CenterList End class
The Controller is as follows:
<HttpGet()> <Authorize()> _ Public Function AssignToDataCenters() As ActionResult Dim model As New ProcessingModel Dim BatchHandler As New BatchControl 'This line will get the list of batches without datacenter model.BatchesForAssignation = BatchHandler.GetBatchesAvailable(ConnectionString) 'This method will get the list of Datacenters available model.Datacenters=BatchHandler.GetDatacenters(ConnectionString) return View(model) End Function
HttpPost (This is actually not working because the model returns an empty model):
<HttpPost()> <Authorize()> _ Public Function AssignToDataCenters(ByVal Model as ProcessingModel) As ActionResult Dim BatchHandler As New BatchControl Dim SaveResult as Boolean=false 'This line will get the list of batches without datacenter model.BatchesForAssignation = BatchHandler.GetBatchesAvailable(ConnectionString) 'This method save the information returned by the model SaveResult=BatchHandler.UpdateBatches(model) ViewBag("Result")=SaveResult Return View(model) End Function
The View is as follows (is a Strongly-typed view):
@ModelType MVCAdmin.ProcessingModel @Code ViewData("Title") = "Assign Batches To centers" End Code @Using Html.BeginForm() @<table id="tblAvailableBatches"> <thead> <tr> <th>Assign batch to:</th> <th>Name</th> </tr> </thead> <tbody> @code For i As Integer = 0 To Model.BatchesForAssignation.Count - 1 Dim a As Integer = i @<tr> <td>@Html.DropDownListFor(Function(m) m.BatchesForAssignation(a).CenterID, New SelectList(Model.Datacenters, "ID", "name", model.BatchesForAssignation(i).CenterID), " ")</td> <td>@Model.BatchesForAssignation(i).name</td> </tr> Next End Code </tbody> </table> <input type="button" value="Apply changes" id="btnApply" /> End Using
Thanks in advance
After making some researh I found that I can parse the querystring in the controller using request.Form I can parse the results sent by the view. But the querystring keys are in the form BatchesForAssignation.CenterID,BatchesForAssignation.CenterID,BatchesForAssignation.CenterID and so on...
Is there's a better way to do this "automagically" so that the model parses the querystring and sends the parsed object to the controller?
Again...Thanks in advance
After reviewing this question I've found that the best way to create the model and send it to the controller is creating a CustomModelBinder (from the IModelBinder Interface) and parsing the form's querystring on the BindModel method using the controllerContext.HttpContext.Request.Form property. Something like this:
Public Class ProcessingModelBinder implements IModelBinder public Function BindModel(controllerContext As System.Web.Mvc.ControllerContext, bindingContext As System.Web.Mvc.ModelBindingContext) As Object dim model as ProcessingModel = if(nothing.equals(bindingContext.Model),directcast(bindingContext.Model,directcast(DependencyResolver.Current.GetService(typeof(ProcessingModel)) dim Keys as string()=controllerContext.HttpContext.Request.Form.AllKeys for each key in Keys 'Fill the model required parameters Next return model End Function
And finally register the new Model Builder in the global.asax file
Sub Application_Start() AreaRegistration.RegisterAllAreas() ModelBinders.Binders.Add(typeof(ProcessingModel),New ProcessingModelBinder()) RegisterGlobalFilters(GlobalFilters.Filters) RegisterRoutes(RouteTable.Routes) End Sub
I hope that this helps someone