So I have worked out how to pass my custom objects into ASP.Net json webservices. Works a charm.
Problem I am having is passing in straight arrays of my custom objects or alternatively passing in arrays that are parameters of my custom objects.
So for example...
Public Class WebService1
Inherits System.Web.Services.WebService
<WebMethod()> _
<ScriptMethod(ResponseFormat:=ResponseFormat.Json)> _
Public Function AddPersonList(ByVal PersonList As PersonList) As String
Debug.Assert(False)
End Function
Public Class Person
Public Sub New()
End Sub
Public Property FirstName As String
Public Property LastName As String
End Class
Public Class PersonList
Inherits List(Of Person)
End Class
End Class
<script>
$(function () {
$.ajax({
type: "POST",
url: "WebService1.asmx/AddPersonList",
data: " { PersonList: [ { FirstName: 'Max', LastName: 'Gershkovich' }, { FirstName: 'Test1', LastName: 'Test2' } ] }",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (e) { debugger; },
error: function (e) { debugger; }
});
});
</script>
Fails with error: The value \"System.Collections.Generic.Dictionary`2[System.String,System.Object]\" is not of type \"WebApplication1.WebService1+Person\" and cannot be used in this generic collection.\r\nParameter name: value
So how do I explain to ASP.net that it is infact an array of Person?
Please note: That changing the function to as List(of Person) or ArrayList does work but given that I implement my own custom collections this is not optimal for me.
UPDATE: Ok so what I have worked out so far is that this problem is definitely associated with how the JavascriptSerializer uses the SimpleTypeResolver to resolve types. Basically if I do something like this
Public Function AddPersonList(ByVal PersonList As String) As PersonList
I can recreate the error using the following code.
Dim PersonList As PersonList = jsonSerializer.Deserialize(Of PersonList)(PList)
However when I provide my own custom type resolver along the lines of
Dim jsonSerializer As New JavaScriptSerializer(New MyCustomTypeResolver)
I can successfully create an instance of my custom list.
Now I have worked out how to provide my own custom convertor in the web.config file. Along the lines of this….
<system.web.extensions>
<scripting>
<webServices>
<jsonSerialization>
<converters>
<add name="MyCustomConverter" type="WebApplication1.MyCustomConverter" />
</converters>
</jsonSerialization>
</webServices>
</scripting>
</system.web.extensions>
But the problem is that I can’t find a way to specify a CustomTypeResolver. My assumption is that this is the only piece of the puzzle I am missing.
PSS: I have tried to use the assembly fully qualified name as specified in the docs for the SimpleTypeResolver (SimpleTypeResolver MSDN) but this throws a "Operation is not valid due to the current state of the object." exception - which is an error caused when the TypeResolver cannot resolve the name (I know this by testing with my CustomTypeResolver)
UPDATE @ Oleg and Sean:
I sincerely appreciate your input and have infact changed my application to reflect your suggestions; having said that the problem with this change is that it requires reworking of my class implementation and its associated behaviour in ways that I would have preferred to avoid.
My problem was never passing in a List(of Object) into my webservice (I simply posed the question as such to simplify it for stackoverflow). In such a case I would be willing to completely accept using a Generic List(of) but my problem was actually that one of my custom objects implemented a property with a strong typed List(of) so for example:
Customer {CustomerID AS Guid, FirstName AS String, LastName AS String, EmailAddresses AS EmailAddressList}
which now needs to be changed to
Customer {CustomerID AS Guid, FirstName AS String, LastName AS String, EmailAddresses AS List(Of EmailAddress)}
This is admittedly not the end of the world and is probably better in the webservice context (as you have suggested) but definitely a detriment when it comes to internal application usage of my Collection properties. What this means is that once I have this property I either need to cast it to my CustomCollectionList every time I want to use some advanced feature or I need to implement another property which exposes the CustomCollectionList. Either solution leaves a nasty taste in my mouth.