I have a WCF service where I am trying to return a List (where IWatchable is a custom interface I have built) in one of my operation contracts. When I test the service on the client the method returns an object[] instead of List<IWatchable>. Is it possible to return a List of IWatchable, since IWatchable is an interface with WCF?
Method:
public List<IWatchable> GetWorkload( Guid nodeId, int maximum )
IWatchable:
public interface IWatchable
{
string ActionName { get; set; }
Guid ActionReference { get; set; }
}
Hopefully a bit more info will be helpful...
I have a derived interface:
public interface IAMRAWatchable: IWatchable
And three concrete implementations from IAMRAWatchable:
public class InstrumentationWatch: IAMRAWatchable
public class OutputWatch: IAMRAWatchable
etc...
In my WCF method that returns List<IWatchable> I want to send an InstrumentationWatch and an OutputWatch to the client... Is this possible or am I going about this the wrong way?
Resolved
Thanks to John I found my solution. KnownType wasn't working since I was using List<IWatchable> - So I wrapped my list into a new class and added the attributes to it. I'll need to re-factor my code but for others who are interested here is the class:
[DataContract]
[KnownType( typeof( InstrumentationWatch ) )]
[KnownType( typeof( OutputWatch ) )]
public class WorkInfo
{
[DataMember]
public List<IWatchable> WorkQueue { get; set; }
}
and my WCF method:
public WorkInfo GetWorkload( Guid nodeId, int maximum )
An interface can never be serialized. It is only a description of behavior.
You can serialize objects which implement the interface, but you must tell WCF what their types are. See Data Contract Known Types.
Related
The common way in WCF is to have a service with several operation contracts. Once an operation contract is defined you better not change it anymore because there are a lot of cases in which an operation change will break an existing client. But how about having just one general or universal operation contract (One single instead of many operation contracts. In fact I know you won’t be able to combine all in one but most of them).
Here one example. That’s not the way I would finally realize it … just a simple illustration.
public enum Operation
{
Add,
Sub,
Mul,
Div
}
[DataContract]
public class Info
{
[DataMember]
public Operation Operation { get; set; }
[DataMember]
public object Data { get; set; }
}
[ServiceContract]
public interface IService
{
[OperationContract]
Info Do(Info info);
}
public class Service : IService
{
public Info Do(Info info)
{
var result = -1;
switch (info.Operation)
{
case Operation.Add:
// cast info.Data and calculate result
break;
case Operation.Sub:
// cast info.Data and calculate result
break;
}
return new Info { Operation = info.Operation, Data = result };
}
}
The main disadvantage on a universal contract is that you have to know how to pass data to the service and how to interpret the result. But this can be solved by documentation.
Currently I’m working on a project with a big client-server-application combined in one solution. It’s a big hassle to add one operation, update service references…
What speaks against to combine operation contracts? Do I have something more to consider?
Once an operation contract is defined you better not change it anymore
But how about having just one general or universal operation contract
[ServiceContract]
public interface IService
{
[OperationContract]
Info Do(Info info);
}
Though you have made an attempt to make it "universal" or generic you really haven't. That's because your service interface only accepts Info as an argument with no room for expansion.
Info has members of type Operation - an enumeration which you cannot change as you rightly stated. What happens if I want to do a square root operation down the track? Or maybe a factorial?
One approach for single method service contracts that allow for future request types is the request/response pattern. Essentially you define the WCF service contract once and it never changes even when you add new operations. There's actually no need to. The object that is passed in the Request parameter is essentially an a standard envelope in which the actual specific operation is serialised.
e.g. here I have renamed your Request to RequestEnvelope
[ServiceContract]
public interface IService
{
[OperationContract]
ResponseEnvelope Do(RequestEnvelope request);
}
[DataContract]
public class RequestEnvelope
{
[DataMember]
public IRequest Request { get; set; }
}
[DataContract]
public class ResponseEnvelope
{
[DataMember]
public IResponse Response { get; set; }
}
For example, I might want to calculate prime numbers so I would serialise an instance of CalculatePrimes into the Request member of RequestEnvelope.
public interface IRequest { }
public interface IResponse { }
[Serializable]
public class CalculatePrimes : IRequest
{
public int StartAt { get; set; }
public int CountToCalculate { get; set; }
public TimeSpan Timeout { get; set; }
}
[Serializable]
public class CalculatePrimesResponse : IResponse
{
public List<int> Primes { get; set; }
}
This approach works very well when refactoring large monolithic services with many many operations on a single WCF interface into something more manageable and significantly less long-term maintenance. Note how the actual requests and responses don't have to be actual WCF types but POCOs.
We have trouble with the protobuf-net type inheritance.
We have a base class like this:
[DataContract, ProtoContract]
public abstract class BaseClass : IBase
{
protected IBase()
{
RequestUID = Guid.NewGuid();
}
[DataMember(Order = 8000), ProtoMember(8000)]
public Guid ID { get; set; }
[DataMember(Order = 8001), ProtoMember(8001)]
public string User { get; set; }
}
And classes which inherits from BaseClass.
[DataContract, ProtoContract]
public class ConcreteClass : BaseClass
{
[DataMember(Order = 4), ProtoMember(4)]
public int? WorkItemId { get; set; }
}
(In future we are going to use only ProtoMember and ProtoContract.)
When the client and server starts we do following in both environments:
RuntimeTypeModel.Default[typeof(BaseClass)].AddSubType(50, typeof(ConcreteClass));
Now when we pass an instance of ConcreteClass to a WCF service operation we get exceptions:
BaseClass does not provide a public constructor. (Wrong type chosen for deserialization)
Or if we provide a public constructor for BaseClass it tries to cast the BaseClass object to ConcreteClass on the server. (Again wrong type)
And under some special circumstances (we don't know exactly when this happens) Protobuf tries to deserialize from OtherConcreteClass to ConcreteClass.
What are we doing wrong? The WCF behavior is register correctly. We had no problems with simple classes (no inheritance).
Is there and documentation how two configure the inheritance properly for WCF scenarios?
Thanks
I have a WCF Client, and the Endpoint has just been upgraded with a new method (OperationContract). I want to write a common method to handle the response from this new method as well as from the existing method at the endpoint.
I am trying to create a "Base" response class and adding common properties to it provided by the WCF endpoint, but I notice in my handler method, the properties are not being retained.
The code for the class I want all responses to inherit from looks like this :
public class ResponseBase
{
public string[] ItemsReturned;
public bool ItemsWereAvailable;
}
So I add partial declarations to get this onto the objects in the endpoint.
public partial class RetrieveResponse :ResponseBase
{
}
public partial class RetrieveResponse2 :ResponseBase
{
}
This way I have a handler method that just accepts "ResponseBase" as its input.
Am I doing this all wrong?
Any class whose instances will be return values and/or parameters of an operation contract should be decorated with the DataContract attribute, and the properties, as DataMembers:
[DataContract]
public class ResponseBase
{
[DataMember]
public string[] ItemsReturned { get; set; }
[DataMember]
public bool ItemsWereAvailable { get; set; }
}
http://msdn.microsoft.com/en-us/library/ms733127.aspx
If they are not, the DataContractSerializer doesn't serialize them.
I originally have defined a data contract for testing purpose as
[DataContract]
public class CreditCard: ISensitive
{
[DataMember]
public string CardNumber { get; set; }
}
The Wcf client reads this contract properly and I can use client reference classes for manipulating CardNumber field. However, when I use .NET Entity framework to generate the data contract's actual implementation I do not see the changes reflected completely in the client reference classes.
[DataContract]
public partial class CreditCard: EntityObject
{
// all Properties coming from database table
[DataMember]
public string CardNumber { get; set; }
[DataMember]
public string CardHolderName { get; set; }
[DataMember]
public DateTime ExpiryDate { get; set; }
}
public partial class CreditCard: ISensitive
{
// interface implementation and other methods
}
I am only able to manipulate CardNumber property, while other properties are not generated in the client code. I also do not see other entity types being generated on client code. Is there some versioning problem I am neglecting? Am I updating the service reference incorrectly? Why does the client code does not show DataContract classes generated by Entity Framework?
If you need to update your service definition on Client side, go to Solution Explorer. Under your client project, open 'Connected Services' and right-click on your Service Reference that connects to your buggy service. Select 'Update Service'.
That should renew the service definition on your client side to match the host.
The book Domain Driven Design by Eric Evans describes pattern called value object. One of the important characteristics of a value object is that it is immutable.
As an example I have a value object "Clinic" which must have a name and an id. To make it a value object I do not provide setters on name and id. Also to make sure that there is not invalid instance I take name and id in a constructor and do not provide at parameter less constructor.
public class Clinic
{
public Clinic(string name, string id)
{
Name = name;
Id = id;
}
public string Name{get; private set;}
public string Id{get; private set;}
}
The problem is that when I try to return this object from a WCF Service I get an exception that the object does not have parameter less constructor and the properties do not have public setters. I want to avoid adding parameter less constructor and public setters because then my domain model pattern goes for a toss. How can I get around this problem?
Regards,
Unmesh
I had a similar problem with serializing immutable types before, in the end I decided to implement the ISerializable interface and use the SerializationInfo to store & retrieve the private variables at both ends of the serialization/deserialization process:
http://theburningmonk.com/2010/04/net-tips-making-a-serializable-immutable-struct/
I just built and run a test app using the same technique and it seems to work for me. So in terms of changes to your Clinic class you could change it to:
[Serializable]
public class Clinic : ISerializable
{
public Clinic(string name, string id)
{
Name = name;
Id = id;
}
public Clinic(SerializationInfo info, StreamingContext context)
{
Name= info.GetString("Name");
Id= info.GetString("Id");
}
public string Name{get; private set;}
public string Id{get; private set;}
[SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Name", Name);
info.AddValue("Id", Id);
}
}
This will solve the problem you're having passing the data back from WCF. But from a design point of view, I agree with what Ladislav is saying and typically you will want to separate your domain objects with objects purely intended for message passing (DataTransferObjects), and in that case here's an example of how you MIGHT approach it:
// the domain object (NOT EXPOSED through the WCF service)
public class Clinic
{
public Clinic(string name, string id)
{
Name = name;
Id = id;
}
public string Name{ get; private set;}
public string Id{ get; private set;}
// other methods encapsulating some business logic, etc.
...
}
// the corresponding DTO object for the domain object Clinic
// this is the type exposed through the WCF layer, that the client knows about
[DataContract]
public class ClinicDTO
{
[DataMember]
public string Name { get; set; }
[DataMember]
public string Id { get; set; }
}
// WCF service contract, NOTE it returns ClinicDTO instead of Clinic
[ServiceContract]
public interface IClinicService
{
[OperationContract]
ClinicDTO GetClinicById(string id);
}
To ease the pain of converting from Clinic to ClinicDTO, you could either add a method on Clinic to do this or implement an implicit/explicit converter. I've got an example on how to do this here:
http://theburningmonk.com/2010/02/controlling-type-conversion-in-c/
Hope this helps!
The problem is that your value object is not serializable. How do you plan to use the service? Do you plan to share domain objects / value objects with your clients? If yes than it IMO violates your domain driven desing - only business layer should be able to work with domain objects and call their methods. If you don't want to share objects you will probably create proxy by add service reference which will generate data contrats for the client. These contrats will have public parameterless constructor and all properties settable (and no domain methods).
If you want to have real Domain driven design you should not expose your domain objects in WCF. Instead you should create set of DTO and expose those DTOs. Service layer will be responsible of converting those DTOs to Domain objects / value objects and vice-versa.