httppost returns nothing with complex objects in m

2019-08-10 03:40发布

问题:

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.

I've tried to follow many posts like this one and this one, but I'm not sure of how to implement them in my application since my model did not send IEnumerable types.

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:

Client=2&Datacenters=20&BatchesForAssignation[0].CenterID=4&BatchesForAssignation[1].CenterID=20&BatchesForAssignation[1].DatacenterID=14...

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):

Batch:

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

UPDATE 2012-06-14:

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[0].CenterID,BatchesForAssignation[1].CenterID,BatchesForAssignation[2].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

回答1:

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

Regards