WCF - Generic Dictionary Name Problems - wcf

So, I'm consuming a WCF service where a colleague has created functions like this:
<OperationContract()>
Function GetRelationshipsGroupedByClass(ByVal objId As Integer, ByVal showDeleted As Boolean) As Dictionary(Of String, List(Of Relationship))
When I create the service reference in my asp.net application the return type is no longer a dictionary but
ArrayOfKeyValueOfstringArrayOfRelationshipQknDUPatKeyValueOfstringArrayOfRelationshipQknDUPat
Is there any way of giving WCF a custom name to call this instead of this crazy name? Or am I going to have to rewrite all the functions that use generic dictionaries to output custom data contracts instead?

Because Dictionaries are not inherently serializable into XML , WCF converts it into an array - the array you see in your service reference. You may choose to create your own serializable dictionary - here's one, or use custom data contracts as you suggested.

Related

WCF Serialised List object giving strange names for objects

Here is the Method signature in the WCF service:
APIMessageList<APISimpleContact> GetMembers(string apiKey, APIContactSearchFilter filter);
APIMessageList inherits from IList. Once I have built a proxy against this WCF service the class name is APIMessageListOfAPISimpleContactjHldnYZV.
Why do I not get: APIMessageListOfAPISimpleContact?
It adds random text to the end of every APIMessageList object in the interface (there are several) They all end with the same few chars - jHldnYZV. I have looked online for possible causes, but I can't find any posts of people having this problem.
This is a purely cosmetic issue but this interface is exposed to our external customers so its appearance is important.
Anybody know why I am getting this problem?
Many thanks
Joe
Your solution will be at http://msdn.microsoft.com/en-us/library/ms731045.aspx. Basically, since you could have multiple "SimpleContract" classes (in different namespaces), WCF will add a disambiguation hash to the end of the contract name, which is what you have in the 8 chars at the end of the contract name. But you can control that, by using the CollectionDataContract and its Name property:
[CollectionDataContract(Name = "APIMessageListOfSimpleContract")]
public class APIMessageList : IList<SimpleContract> { ... }
We had a similar problem while using Generic types for return values. If we are not specifying a concrete type, the default data contract serializer or the WCF serializer is unable to infer the exact type of the returned entity. Hence it generates a random class name for the returned type.
In our project we overcame this problem by building a data contract which was of specific type and returned the same as a result of a WCF operation call.
My guess is that you are using a generic type and the serializer is unable to infer the type of the returned object.
I suggest you create a Data Transfer Object (DTO) and return the same from the WCF service. That should solve your problem.

WCF Service Contract

I have a problem using an custom data type in a WCF service method, below is my sample code
[ServiceContract()]
public class SampleServise : ISampleServise
{
void object GetSomething(ICustomData objectData)
{
// Do Something
}
}
What shall I do with ICustomData class interface?
Thanks
Afshin
WCF is based on message passing, and that message passing is modelled using XML schema (XSD). As such, whatever can be expressed in XML schema can be used in WCF.
This also means: interfaces are not supported. You need to use actual, concrete types for the parameters in your WCF service methods.
In your case, create a concrete class that implements ICustomData and then use that class as the parameter type.
For a good reference, read MSDN Designing Service Contracts which states for parameters:
Parameters and Return Values
Each operation has a return value and a parameter, even if these are
void. However, unlike a local method, in which you can pass references
to objects from one object to another, service operations do not pass
references to objects. Instead, they pass copies of the objects.
This is significant because each type used in a parameter or return
value must be serializable; that is, it must be possible to convert an
object of that type into a stream of bytes and from a stream of bytes
into an object.

Passing Objects Between WCFs

I have an ASP application, which calls an HTTP WCF service, which calls a TCP WCF service (all on different servers). I'm ultimately trying to pass one class object between the three.
I've discovered that I can't do this directly in the HTTP WCF, even though my class object is defined identically in BOTH WCFs. Like this:
Public Function CallOtherFunction(ByVal ThisClass as MyClass)
Dim RetVal as Boolean
RetVal = CallMyOtherWCFFunction(ThisClass)
End Function
Instead I have to:
Public Function CallOtherFunction(ByVal ThisClass as MyClass)
Dim RetVal as Boolean
Dim MyOutgoingClass as MyOtherWCF.MyClass
MyOutgoingClass.MyString = ThisClass.MyString
RetVal = CallMyOtherWCFFunction(MyOutgoingClass)
End Function
My objects are rather large, to say they have a lot of properties. Any way to not have to declare a new variable in my calling function, so my code can be a little easier (like the first example)?
Thanks,
Jason
You can't pass it directly because those are two diffrent types. You can, however, declare your data contracts in a shared assembly (used by the three projects, or at least by the HTTP and the TCP services), an when adding the service reference to create the proxy in the HTTP service, you specify that you want to "reuse types in referenced assemblies". This way it should use the same type in all projects.

type conversion from webservice object to class object

i've created bunch of classes. i have webservices which reference these classes and contains the classes as parameters and return objects.
when i call the weservice, i have to convert the class to the webservice object else i can type conversion error.
is there a generic way to convert between these types without having to assign the values by hand?
for example
public class person
fname as string
lname as string
end class
web service method
public getperson() as person
return new person()
end sub
in the client
dim ws as new webservice
dim person = ws.getperson
i would liek ot be able to call the web service and return the data type back and have a generic coversion instead of as above in stead of:
dim wsPerson as wsReference.Person = ws.getperson()
thanks
Since the generated proxy class for a web reference is a copy of the interface of the exposed class, you should be able to use reflection to do such conversions.
However, if your classes are not very large or many, I would suggest to manually create a converter that will handle conversion from web service class types to "internal" class types, and the other way around. If the number of classes is large, and if there will be new classes added regularly, or their design change, I would look into making some sort of code generator that will create the converter functionality for you.
Some of the advanced features are hard to use from vb.net, but AutoMapper will do the basic translation of Person to Person classes nicely for you.

Type casting in VB .NET

I am adding a feature to an existing VB .Net application that involves retrieving data from a .Net web service. The web service returns an array of Locations. A Location is pretty simple, it has 3 properties – an integer and two strings.
So that the rest of my application does not have to be dependent on this web service, I would like to create my own Location type within my application. My thought is I could call a method that returns a generic list of my Location type which internally calls the web service and populates the list I return. That way, if the data source for Locations changes in the future to something other than the web service, I only have to fix the method instead of fixing all the callers.
So I created my own Location that has identical properties as the service Location. But I don’t seem to be able to cast the array of service locations into a generic list of my locations. I also tried casting a single service Location into one of my Locations and that didn’t work either.
So is casting an option or do I have to loop through each service Location and assign each property to a new one of my Locations? Or is there a completely different way to go about this?
By default you will not be able to cast one Location to another. They are completely unrelated types and thus cannot be the subject of casting. You can make it possible to cast though by defining a custom operator for the application version of CType.
' Location for application
Public Class Location
...
Public Shared Operator Widening CType(p1 as Namespace.Of.WebService.Location) As Location
Dim loc = ConvertWebServiceLocationToApplicationLocation
return loc
End Operator
End Class
This allows you to now do a CType operation between a WebService Location the Application Location.
Casting the array though, simply won't be possible. There is no way to define a conversion operator for arrays so they can't use the above trick. But you can write a quick and dirty function for this purpose
Public Shared Function ConvertArray(ByVal arr As Namespace.Of.WebServiec.Location()) As Location()
Dim newArray(arr.Length) As Location
For i as Integer = 0 To arr.Length - 1
newArray(i) = CType(arr(i), Location)
Next
return newArray
End Function
Casting will not work because these are not the same type. Even if two types look exactly the same, you cannot cast from one to the other, unless you define a CType operator which describes how to transform an object from one type into an object from another type.
Even then, you cannot cast a List(of Type1) into a List(Of Type2) directly.
You will have to loop through and create a new object of your class.