views:

129

answers:

3

Very strange issue... I have something like this in my Controller:

public ActionResult Initialize(IEnumerable<MyModel> Requests)
{
...

}

I generate form elements in my submitting View that look like this:

Requests[90ed54f6-4650-44c7-8cc2-c4d225a9a334].Name
Requests[90ed54f6-4650-44c7-8cc2-c4d225a9a334].Address
Requests[db67e8e5-94f8-4b35-b69c-65184980f2a1].Name
Requests[db67e8e5-94f8-4b35-b69c-65184980f2a1].Address

On Firefox, when I submit this with multiple elements, the binder works and I get a collection of objects. On Safari, the exact same data always generates only 1 object in the collection.

Weirdly, in the debugger if I look at Requests.Params.AllKeys[] I see the values -- they're being submitted, just somehow not binding. I use Firebug on Firefox but don't have an equivalent tool for Safari. Since I see the values in the Request.Params, I assume that it's not an issue with the form values being passed in -- just something about they way they're being bound to the ViewModel...

The binder is kind of black magic to me -- I'm not sure where this lives and if I can step through this to see what it's doing.

Any ideas what this might be or how I might chase this down?

Edit: This works correctly in IE as well -- just Safari is acting weird.

Edit 2: I lied... Safari does not post the index values as I would expect:

Requests.index = {GUID}
Requests[90ed54f6-4650-44c7-8cc2-c4d225a9a334].Name
Requests[90ed54f6-4650-44c7-8cc2-c4d225a9a334].Address
Requests.index = {GUID}
Requests[db67e8e5-94f8-4b35-b69c-65184980f2a1].Name
Requests[db67e8e5-94f8-4b35-b69c-65184980f2a1].Address

Both Firefox and Internet Explorer post both Requests.index values as comma separated values, but Safari only posts the first. I'm not sure what "correct" is for this case, but this is something I can sink my teeth into.

+1  A: 

I assume that the "index" is a GUID that functions as the request's id. I would assume that you would actually generate something like:

 <input type="hidden" name="Requests[0].ID" value="90ed54f6-4650-44c7-8cc2-c4d225a9a334" />
 <input type="text" name="Requests[0].Name" />
 <input type="text" name="Requests[0].Address" />

Of course, your MyModel class will need to have the ID property to hold the Guid.

My suspicion is that it has something to do with how the query parameters are encoded, but honestly I have never set up collections the way you are and it's not clear to me how the model binder should interpret the parameter index -- perhaps it's mapping them all onto 0 -- if it's not numeric.

tvanfosson
They're guid based indexes on the form objects ... the values are literally (Requests[90ed54f6-4650-44c7-8cc2-c4d225a9a334].Name). Encoding sounds like it might be right -- could explain why Safari behaves differently. Thanks
Andrew Flanagan
@Andrew - Try setting up your indexes like: Request[ *GUID* ].index = *GUID*. I still think it would be better to use numeric indices absent any other compelling reason not to. After all, you're simply getting back an enumerated list. Unless you store the GUID as part of the object (as I've shown), it doesn't make the results any more unique than simply using an monotonically increasing integer value.
tvanfosson
On the input side, I'm allowing arbitrary adding/removing of rows of data which makes it difficult to do with concurrent indexes. So for example, a user can input 0,1,2,3 and then delete row 2 before submitting the form. The GUIDs help with that. I'll try what you suggest though.
Andrew Flanagan
@Andrew - it should still be ok. You might, however, get gaps that correspond to the missing indices. Doing something like: `var actualRequests = requests.Where( r => r != null )` would solve that.
tvanfosson
A: 

Compare actual values POST'd by each browser:

public ActionResult Initialize(FormCollection collection)
{
  //... dump the collection's NameValueCollection ...
}

And compare actual HTML rendering of the form between browsers, just to be sure.

Tyler Jensen
A: 

So the final solution to this had to do with improperly placed <input> tags. Specifically, I was placing a hidden <input> after a <tr> and before a <td>. On Firefox and IE it's very forgiving and this was working. On Safari for some reason, it would not consider the 2nd-Nth elements to be valid form inputs. Putting the <input> elements inside of the <td> worked for all browsers.

Thanks for your help guys.

Andrew Flanagan