Search code examples
c#.netwcfdatacontractoperationcontract

Strange issue with wcf service


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?


Solution

  • 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.