2

I have this strange problem. I wrote a wcf service and added a service reference to other project so that I can use it. Usage in a project with a reference to this service looks like this:

private DataAccessServiceReference.DataAccessServiceClient Client = new DataAccessServiceReference.DataAccessServiceClient();

Client.UserGetByIdAsync(id);

Everthing worked fine until I added this method to the service:

IDataAccessService.cs:

[ServiceContract]
public interface IDataAccessService
{
     ...

    [OperationContract]
    void UserGetContactsAsync(long userId, Action<ContactDTO[]> onSuccess, Action<Exception> onFailure);

     ...
}

After rebuilding my service project and updating service reference, type "DataAccessServiceClient" disappeared from my DataAccessServiceReference namespace. Instead of it visual studio generated this strange looking type: DataAccessServiceReference.ActionOfArrayOfContactDTOx0gUquOn

I played around with code a little bit and it seems that problem is with type Action< UserDTO[]>. Now when I created another method in my service:

IDataAccessService.cs:

[ServiceContract]
public interface IDataAccessService
{
     ...

    [OperationContract]
    void method(Action<int[]> action);

     ...
}

problem was similar -> again type DataAccessServiceClient was not available, instead I had another strange looking type, but this time it was: DataAccessServiceReference.ActionOfArrayOfintuHEDJ7Dj.

When I use Action< int > or Action< UserDTO > everything works fine.

I am stuck. Thank you for your help.

EDIT.

If instead of Action< UserDTO[] > I use my own delegate:

public delegate void ActionArrayOfUserDTO(UserDTO[] users);

proxy is still not generated.

Is it even possible to use delegates in wcf contracts?

Bartosz Ciechanowski
  • 10,293
  • 5
  • 45
  • 60
Jarek Mazur
  • 2,052
  • 1
  • 25
  • 41

1 Answers1

0

Unfortunately, you're stuck with the names generated through the WCF serializer (the infamous "this behavior is by design"). This blog post has a good explanation of why WCF generated the client class names that way.

After some clarification, Action in the question represents a .NET delegate and it cannot be serialized by WCF since it represents executable code. Method parameters and return values must be serializeable classes or value types.

Update from the comments:

[DataContract]
public class ActionArrayOfUserDto
{
    public string ActionProperty1 { get; set; }
    public string ActionProperty2 { get; set; }
    // ... the rest of the Action generic class properties

    public UserDto[] UserDtos { get; set; }
}

[DataContract]
public class UserDto
{
    //UserDto properties...
}

You'd write code in your service to populate ActionArrayOfUserDto appropriately and not expose the Action generic class.

Sixto Saez
  • 12,610
  • 5
  • 43
  • 51
  • So there is no way for me to use Action< array of items > and make this work? – Jarek Mazur Nov 15 '12 at 15:35
  • I'm pretty sure WCF will correctly pass data through those classes otherwise it wouldn't create serializations for them. Service-side generics get translated to client-side simple classes with very strange names by WCF. XML Schema and soap have no concept of a "generic class". That's why WCF creates standard (non-generic) client-side classes that way it does. If you want more control over the client-side class **names**, create a standard class with properties and collections you want to pass to the client and map/initialize an instance of this class from your generic class instance. – Sixto Saez Nov 15 '12 at 15:55
  • It's not that I want to have control over client-side class names, but the problem is that proxy class is not generated. – Jarek Mazur Nov 15 '12 at 16:27
  • I'm sorry for stupid question by I don't quite get what class should I write. My UserDTO class is marked with DataContract attribute, when I use Action< UserDTO > in my server side method evertything is ok. So now how do I write separate class marked as DataContract which will allow me to use Action< UserDTO[] >? That is what I'm not getting. – Jarek Mazur Nov 15 '12 at 16:33
  • I see, I didn't understand that the proxy class fails to generate. I've updated the answer with an example class. – Sixto Saez Nov 15 '12 at 16:43
  • Thank you for your help Sixto but again there seems to be a little misunderstanding :) Action is not a generic class but a generic delegate: public delegate void Action(T obj) (it is defined int .net framework) – Jarek Mazur Nov 15 '12 at 16:51
  • So is there a way to write serializable delegate that takes as a parameter array of UserDTOs (because I assume that is would I should do right)? – Jarek Mazur Nov 15 '12 at 16:54
  • for example if I use: public delegate void ActionArrayOfUserDTO(UserDTO[] users), instead of Action< UserDTO[] > proxy is still not generated. – Jarek Mazur Nov 15 '12 at 17:05
  • Sorry, I was confused because I assume you were just showing sample code and that `Action` was a placeholder name for your actual class name. WCF *cannot* serialize a delegate of any kind. Remember, WCF is just an abstraction for message passing between a client and a service. The message can **only** ever contain data and **never** executable code. – Sixto Saez Nov 15 '12 at 17:19
  • Ok I understand. Thank you for your help :). You can edit your answer so that I can mark it as a solution. – Jarek Mazur Nov 15 '12 at 17:42
  • Thanks! I updated the answer. Sorry for taking a while to figure out what you were actually asking. – Sixto Saez Nov 15 '12 at 17:52