Any way of passing generic type definition to asmx

2019-08-12 16:43发布

问题:

I use jQuery ajax calls to ASP.Net web services (ASMX files) to update the web page data.

I have the database storing code seperate from the domain object class code (in the example code below, there is an Animal class and an AnimalRepository class). I'm implememting a convention that all similar domain object repository classes will have a Store method .

I would like to create a web service that can cater for calling the Store method for any one of these repository classes. To get this to work, in the below code sample, the List(Of Animal) parameter would need to be a generic type.

I tried a List(Of Object), but the Store command errors on not able to convert types. I don't think I can cast the List(Of Object) to the right type, as it's not known until runtime.

    <WebMethod(True)> _
Public Sub StoreAnimals(ByVal _animals As List(Of Animal), ByVal _type As String)
    Dim classType As Type = Type.GetType(_type & "Repository, MyCompany.Assembly")
    Dim instanceOfClass = Activator.CreateInstance(classType)
    Dim method As MethodInfo = classType.GetMethod("Store")
    method.Invoke(instanceOfClass, New Object() {_animals})
End Sub

Ideally, I would like:

    <WebMethod(True)> _
Public Sub StoreData(Of T)(ByVal _data As List(Of T), ByVal _type As String)
    Dim classType As Type = Type.GetType(_type & "Repository, MyCompany.Assembly")
    Dim instanceOfClass = Activator.CreateInstance(classType)
    Dim method As MethodInfo = classType.GetMethod("Store")
    method.Invoke(instanceOfClass, New Object() {_data})
End Sub

There's no room for generics in the webservice method definition, but is there a trick to achieve the same end result. Otherwise, I'm going to be creating lots of these Store* webservices that only differ on the first parameter.

回答1:

Generics have no meaning in the web services world.

You can't come anywhere close to this with ASMX. With WCF, you might be able to do something, but you can't use an open generic type in an operation contract.



回答2:

If you know what type of object you expect you could serialize the List(of Animal) to byte array and the deserialize the object from the byte array instead.

I made a small sample, in VB.NET though but I think you can translate it. I created a class which both the web service and the client shares.

Client code

Imports System.Xml.Serialization
Imports SharedLibrary

Public Class Form1

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Dim client As New ServiceReference1.WebServiceSoapClient

    Dim a As New Animal
    a.Name = "Pooh"
    MessageBox.Show(client.SendObject(XmlSerialize(a), ServiceReference1.ObjectT.Animal))

    Dim v As New Vehicle
    v.Name = "Volvo"
    MessageBox.Show(client.SendObject(XmlSerialize(v), ServiceReference1.ObjectT.Vehicle))
End Sub

Public Shared Function XmlSerialize(ByVal serializableObject As Object) As Byte()
    Dim serializer As XmlSerializer = New XmlSerializer(serializableObject.GetType())
    Dim aMemStr As New System.IO.MemoryStream

    Dim writer As System.Xml.XmlWriter = System.Xml.XmlWriter.Create(aMemStr)

    serializer.Serialize(writer, serializableObject)
    writer.Close()
    aMemStr.Close()
    Return aMemStr.ToArray()
End Function

Shared library

 Public Class ObjectTypes
  Public Enum ObjectT
    Animal
    Vehicle
   End Enum
  End Class

  Public Class Animal
Private strName As String

Public Property Name As String
    Get
        Return strName
    End Get
    Set(value As String)
        strName = value
    End Set
End Property
End Class

Public Class Vehicle

Private strName As String

Public Property Name As String
    Get
        Return strName
    End Get
    Set(value As String)
        strName = value
    End Set
End Property
End Class

Web service

<WebMethod()> _
Public Function SendObject(bytObject As Byte(), objType As SharedLibrary.ObjectTypes.ObjectT) As String
    Try
        Select Case objType
            Case ObjectTypes.ObjectT.Animal
                Dim myAnimal As Animal = XmlDeSerialize(bytObject, GetType(Animal))
                Return "I received an animal with name: " & myAnimal.Name
            Case ObjectTypes.ObjectT.Vehicle
                Dim myVehicle As Vehicle = XmlDeSerialize(bytObject, GetType(Vehicle))
                Return "I received a vehicle with name: " & myVehicle.Name
        End Select
    Catch ex As Exception
        Return "Something went wrong: " & ex.Message
    End Try

    Return "I did not receive anything :("

End Function

Public Shared Function XmlDeSerialize(ByVal xmlbytearr As Byte(), ByVal objectType As Type) As Object
    Dim serializer As XmlSerializer = New XmlSerializer(objectType)
    Dim aStream As System.IO.MemoryStream = New System.IO.MemoryStream(xmlbytearr)

    Return serializer.Deserialize(aStream)
End Function