WCF Polymorphism in service contract - wcf

I am trying to create a service that with an operation that accepts, as a parameter, an any object that implements a specific interface. I would have thought this would be easy to accomplish, but I am running into problems (what I am guessing to be serialization problems but I am not certain). I have the following contract:
//Unsustainable because I would need a method for each of the (currently)
//3 student types, plus I have 2 more root categories that have multiple subtypes
public interface IEmailTemplateAccess
{
[FaultContract(typeof(ValidationFault))]
[FaultContract(typeof(ErrorResponse))]
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
TemplateResponse GetStudentTemplate(ITemplateRequest request);
}
And this is what I would like it to look like:
public interface IEmailTemplateAccess
{
[FaultContract(typeof(ValidationFault))]
[FaultContract(typeof(ErrorResponse))]
[OperationContract]
[TransactionFlow(TransactionFlowOption.Allowed)]
TemplateResponse GetTemplate(ITemplateRequest request);
}
In my service I use an abstract factory to return the correct template based on the type of request that comes in. In addition, I have created concrete ITemplateRequests for the different kinds of templates that could be returned. For example, I have Template Request types A and B. Template Request Type A can have one of 3 sub types, SubType1, SubType2 and SubType3. I then created a SubType3 request that implemented the ITemplateRequest interface (SubType3Request).
I would hate to have to create a method for each request type I have (i.e. GetSubType1Template, GetSubType2Template, GetSubType3Template, GetTypeBTemplate, etc) as this would quickly become unwieldy as the types of templates I can get will be changing occasionally.
Is there a way to have a contract method accept anything that implements ITemplateRequest as a parameter and let my factory do the work of figuring out what type of template to get?
So far, I have the following methods in my service:
//Not a part of the contract right now although I would like it to be
public IEmailTemplate GetTemplate(ITemplateRequest request)
{
TemplateFactoryBuilder builder = new TemplateFactoryBuilder();
ITemplateFactory factory = builder.GetTemplateFactory(request.Type);
var template = factory.GetTemplate(request);
return template;
}
//contract method --This would be my Parent Request Type (RequestTypeA) from above.
//There are 3 subtypes of the Student type
public TemplateResponse GetStudentTemplate(StudentEmailTemplateRequest request)
{
var response = new TemplateResponse
{
RequiresProcessing = true
};
response.Template = (EmailMergeTemplate) GetTemplate(request);
return response;
}

Sorry for the link-ish answer, but it's pretty long.. What you're after (I think) is here: http://blogs.msdn.com/b/morgan/archive/2009/08/05/polymorphism-in-wcf.aspx
It boils down to using known types. Something like this;
[ServiceContract]
[ServiceKnownType("GetKnownTypes", typeof(CommandServiceHelper))]
public interface ICommandService

Related

SerializationException when returning custom classes from a WCF service

I have the following classes...
public abstract class Fallible<T> {
}
public class Success<T> : Fallible<T> {
public Success(T value) {
Value = value;
}
public T Value { get; private set; }
}
The background to this can be found in a previous question of mine, but you don't need to read that post as the classes above are all that's needed to see the problem.
If I have a simplified WCF service call like this...
[OperationContract]
public Fallible<Patient> GetPatient(int id) {
return new Success<Patient>(new Patient {ID = 1,FirstName = "Jim",Surname = "Spriggs"});
}
...then when I try to call the service from the WPF app that consumes it (or the WCF test client), I get a CommunicationException exception...
There was an error while trying to serialize parameter :GetPatientResult. The
InnerException message was 'Type 'PhysioDiary.Entities.FallibleClasses.Success`1[[PhysioDiary.Entities.Patient,
PhysioDiary.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
with data contract name > 'SuccessOfPatient0yGilFAm:http://schemas.datacontract.org/2004/07/PhysioDiary.Entities.FallibleClasses'
is not expected. Consider using a DataContractResolver if you are using
DataContractSerializer or add any types not known statically to the list of
known types - for example, by using the KnownTypeAttribute attribute or by
adding them to the list of known types passed to the serializer.'. Please
see InnerException for more details.
...with an inner SerializationException exception of...
Type 'PhysioDiary.Entities.FallibleClasses.Success`1[[PhysioDiary.Entities.Patient,
PhysioDiary.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
with data contract name > 'SuccessOfPatient0yGilFAm:http://schemas.datacontract.org/2004/07/PhysioDiary.Entities.FallibleClasses'
is not expected. Consider using a DataContractResolver if you are using
DataContractSerializer or add any types not known statically to the list
of known types - for example, by using the KnownTypeAttribute attribute
or by adding them to the list of known types passed to the serializer.
I've tried adding [DataContract] to the class and [DataMember] to each property, as well as adding a [KnownType] attribute for all four classes involved, and adding a [ServiceKnownType] for each of them on the service contract, but nothing helps.
I've read countless answers to the same question, but have not found anything that works. My services return other custom classes, and they all get serialised without a problem.
Anyone able to explain what the problem is here? Please let me know if I've not supplied enough information.
Turns out all I needed to do was decorate the service method with [ServiceKnownType] attributes for the base type, and each derived type...
[OperationContract]
[ServiceKnownType(typeof(Fallible<Patient>)]
[ServiceKnownType(typeof(Success<Patient>)]
[ServiceKnownType(typeof(BadIdea<Patient>)]
[ServiceKnownType(typeof(Failure<Patient>)]
public Fallible<Patient> GetPatient(int id) {
return new Success<Patient>(new Patient {ID = 1,FirstName = "Jim",Surname = "Spriggs"});
}
Although it's a pain to have to add four attributes to every call, it works. I'd like to know if there is a way to combine them into one attribute, but at least I have a working service now.
Hope this helps someone.

AutoFac WCF proxy with changing ClientCredentials

I'm writing a WCF service and am using the AutoFac WCF integration for DI. I have a slightly weird situation where I have a proxy to another service that requires credentials. The credentials will change based on some parameters coming in so I can't just set the values when I'm setting up the container and be done with it.
public class MyService : IMyService
{
private ISomeOtherService _client;
public MyService(ISomeOtherService client)
{
_client = client;
}
public Response SomeCall(SomeData data)
{
// how do I set ClientCredentials here, without necessarily casting to concrete implementation
_client.MakeACall();
}
}
What's the best way to set the credentials on proxy without having to cast to a known type or ChannelBase. I'm trying to avoid this because in my unit tests I'm mocking out that proxy interface so casting it back to one of those types would fail.
Any thoughts?
You can do it, but it's not straightforward, and you have to slightly change the design so the logic of "decide and set the credentials" is pulled out of the MyService class.
First, let's define the rest of the classes in the scenario so you can see it all come together.
We have the ISomeOtherService interface, which I've modified slightly just so you can actually see what credentials are getting set at the end. I have it return a string instead of being a void. I've also got an implementation of SomeOtherService that has a credential get/set (which is your ClientCredentials in WCF). That all looks like this:
public interface ISomeOtherService
{
string MakeACall();
}
public class SomeOtherService : ISomeOtherService
{
// The "Credentials" here is a stand-in for WCF "ClientCredentials."
public string Credentials { get; set; }
// This just returns the credentials used so we can validate things
// are wired up. You don't actually have to do that in "real life."
public string MakeACall()
{
return this.Credentials;
}
}
Notice the Credentials property is not exposed by the interface so you can see how this will work without casting the interface to the concrete type.
Next we have the IMyService interface and associated request/response objects for the SomeCall operation you show in your question. (In the question you have SomeData but it's the same idea, I just went with a slightly different naming convention to help me keep straight what was input vs. what was output.)
public class SomeCallRequest
{
// The Number value is what we'll use to determine
// the set of client credentials.
public int Number { get; set; }
}
public class SomeCallResponse
{
// The response will include the credentials used, passed up
// from the call to ISomeOtherService.
public string CredentialsUsed { get; set; }
}
public interface IMyService
{
SomeCallResponse SomeCall(SomeCallRequest request);
}
The interesting part there is that the data we're using to choose the set of credentials is the Number in the request. It could be whatever you want it to be, but using a number here makes the code a little simpler.
Here's where it starts getting more complex. First you really need to be familiar with two Autofac things:
Implicit relationships - we can take a reference on a Func<T> instead of a T to get a "factory that creates T instances."
Using parameters from registration delegates - we can take some inputs and use that to inform the outputs of the resolve operation.
We'll make use of both of those concepts here.
The implementation of MyService gets switched to take a factory that will take in an int and return an instance of ISomeOtherService. When you want to get a reference to the other service, you execute the function and pass in the number that will determine the client credentials.
public class MyService : IMyService
{
private Func<int, ISomeOtherService> _clientFactory;
public MyService(Func<int, ISomeOtherService> clientFactory)
{
this._clientFactory = clientFactory;
}
public SomeCallResponse SomeCall(SomeCallRequest request)
{
var client = this._clientFactory(request.Number);
var response = client.MakeACall();
return new SomeCallResponse { CredentialsUsed = response };
}
}
The real key there is that Func<int, ISomeOtherService> dependency. We'll register ISomeOtherService and Autofac will automatically create a factory that takes in an int and returns an ISomeOtherService for us. No real special work required... though the registration is a little complex.
The last piece is to register a lambda for your ISomeOtherService instead of a simpler type/interface mapping. The lambda will look for a typed int parameter and we'll use that to determine/set the client credentials.
var builder = new ContainerBuilder();
builder.Register((c, p) =>
{
// In WCF, this is more likely going to be a call
// to ChannelFactory<T>.CreateChannel(), but for ease
// here we'll just new this up:
var service = new SomeOtherService();
// The magic: Get the incoming int parameter - this
// is what the Func<int, ISomeOtherService> will pass
// in when called.
var data = p.TypedAs<int>();
// Our simple "credentials" will just tell us whether
// we passed in an even or odd number. Yours could be
// way more complex, looking something up from config,
// resolving some sort of "credential factory" from the
// current context (the "c" parameter in this lambda),
// or anything else you want.
if(data % 2 == 0)
{
service.Credentials = "Even";
}
else
{
service.Credentials = "Odd";
}
return service;
})
.As<ISomeOtherService>();
// And the registration of the consuming service here.
builder.RegisterType<MyService>().As<IMyService>();
var container = builder.Build();
OK, now that you have the registration taking in an integer and returning the service instance, you can just use it:
using(var scope = container.BeginLifetimeScope())
{
var myService = scope.Resolve<IMyService>();
var request = new SomeCallRequest { Number = 2 };
var response = myService.SomeCall(request);
// This will write "Credentials = Even" at the console
// because we passed in an even number and the registration
// lambda executed to properly set the credentials.
Console.WriteLine("Credentials = {0}", response.CredentialsUsed);
}
Boom! The credentials got set without having to cast to the base class.
Design changes:
The credential "set" operation got moved out of the consuming code. If you don't want to cast to the base class in your consuming code, you won't have a choice but to also pull the credential "set" operation out. That logic could be right in the lambda; or you could put it in a separate class that gets used inside that lambda; or you could handle the OnActivated event and do a little magic there (I didn't show that - exercise left to the reader). But the "tie it all together" bit has to be somewhere in the component registration (the lambda, the event handler, etc.) because that's the only point at which you still have the concrete type.
The credentials are set for the lifetime of the proxy. It's probably not good if you have a single proxy in your consuming code where you set different credentials just before you execute each operation. I can't tell from your question if that's how you have it, but... if that's the case, you will need a different proxy for each call. That may mean you actually want to dispose of the proxy after you're done with it, so you'll need to look at using Owned<T> (which will make the factory Func<int, Owned<T>>) or you could run into a memory leak if services are long-lived like singletons.
There are probably other ways to do this, too. You could create your own custom factory; you could handle the OnActivated event that I mentioned; you could use the Autofac.Extras.DynamicProxy2 library to create a dynamic proxy that intercepts calls to your WCF service and sets the credentials before allowing the call to proceed... I could probably brainstorm other ways, but you get the idea. What I posted here is how I'd do it, and hopefully it will at least point you in a direction to help you get where you need to go.
The approach we ended up taking is to cast ISomeOtherService to ClientBase,
This avoids referencing the proxy type. Then in our unit tests we can set up the mock like so
var client = new Mock<ClientBase<ISomeOtherService>>().As<ISomeOtherService>();
So it can be casted to ClientBase, but still setup as ISomeOtherService

generic requests on agatha

does anyone know why I can't do this ?
public class CreateScenarioHandler :
GL.RRSL.RequestHandler<CommandRequest<ScenarioProfileData>,
CommandResponse<ScenarioProfileData>>
why is it imposible for Agatha to figure out the type of the generic Request. It is defined there. ?
Type 'GL.RequestResponse.CommandRequest`1[T]' cannot be exported as a schema type because it is an open generic type. You can only export a generic type if all its generic parameter types are actual types.
any ideas of how to do this. It feels so restrictive to have to create a request object for each type of operation.
I'm actually using generic requests/responses successfully.
The trick was to register closed generic requests/responses as known-types.
In order to achieve this, I'm using the following conventions:
generic requests/responses can have only one generic parameter
that generic parameter should has a generic constraint that specifies that it should implement a given interface
I'm using this convention to construct every possible closed generic type
that I'm going to be using as request or response.
For example, I can have something like this:
interface IDtoWithId
{
int Id { get; }
}
public class GetEntityRequest<TDto> : Request where TDto : IDtoWithId
{
....
}
public class UserDto : IDtoWithId
{
public int Id { get; set; }
public string Name { get; set; }
}
Then, when configuring Agatha, I'm using something like
this https://gist.github.com/916352 and doing:
....
configuration.Initialize();
KnownTypeProvider.ClearAllKnownTypes();
KnownTypeHelper.RegisterRequestsAndResponses(typeof(UserDto).Assembly);
The KnownTypeHelper registers the GetEntityRequest type as a
known-type and that allow me to handle that request using a handler
hierarchy like this:
public abstract class GetEntityHandler<TEntity, TDto> :
RequestHandler<GetEntityRequest<TDto>, GetEntityResponse<TDto>>
{
...
}
public class GetUserHandler : GetEntityHandler<User, UserDto>
{
}
I'm using this approach for the CRUD part of an application and it is
working very well.
The problem here has to do with how CommandRequest and CommandResponse are defined.
Agatha looks at the classes which extends Request and Response and add's them to the known types in the WCF.
When the server starts the service, WCF complains that the type CommandRequest is generic and can't be used. WCF if saying that it can't claim to know about a generic type.
When I define CommandRequest and CommandResponse as abstract, and then create classes like ScenarioIORequest/Response which extend CommandRequest and CommandResponse respectively with the apropiate type to be wrapped, WCF does not complain.
It feels like a waste that I have to define specific types when I would like to have generic requests and responses for different DTO. Maybe this will change at some point, but it seams to be WCF issue rather then the Agatha project issue.

WCF DataContract Upcasting

I'm trying to take a datacontract object that I received on the server, do some manipulation on it and then return an upcasted version of it however it doesn't seem to be working. I can get it to work by using the KnownType or ServiceKnownType attributes, but I don't want to roundtrip all of the data. Below is an example:
[DataContract]
public class MyBaseObject
{
[DataMember]
public int Id { get; set; }
}
[DataContract]
public class MyDerivedObject : MyBaseObject
{
[DataMember]
public string Name { get; set; }
}
[ServiceContract(Namespace = "http://My.Web.Service")]
public interface IServiceProvider
{
[OperationContract]
List<MyBaseObject> SaveMyObjects(List<MyDerivedObject> myDerivedObjects);
}
public class ServiceProvider : IServiceProvider
{
public List<MyBaseObject> SaveMyObjects(List<MyDerivedObject> myDerivedObjects)
{
... do some work ...
myDerivedObjects[0].Id = 123;
myDerivedObjects[1].Id = 456;
myDerivedObjects[2].Id = 789;
... do some work ...
return myDerivedObjects.Cast<MyBaseObject>().ToList();
}
}
Anybody have any ideas how to get this to work without having to recreate new objects or using the KnownType attributes?
I think that your problem is that you are trying to send over a generic list.
It will work if you encapsulate the list in an object. That is create an object with a single public property which is the generic list.
You also need to make sure that all classes that are not used directly in the contract are marked as serializable.
If you want to return the derived objects then there will always be a round trip because the client and the service are separate. In order for the client to update its own list of MyBaseObjects it has to deserialize the list of MyDerivedObjects that came from the server.
The use of KnownType and/or ServiceKnownType is needed because this leads to the addition of that type information into WSDL, which is in turn used by the client to deserialize the messages to the correct type.
For starters, a useful tool for testing the scenario you've described: http://www.wcfstorm.com
You might try creating a DataContractSurrogate (IDataContractSurrogate) and returning your base type for the call to GetDataContractType. I'm not really sure that's how it was intended to be used so you still may be better of with "the extra work", but maybe I don't understand the scope of that extra work.
One of the problems with WCF (and .net remoting) is that it they tries to make “message passing” look like method calls.
This fall down when you try to use too many “oop” type designs.
The fact that the messages are
represented by .net classes, does not
make all of their behaviour like .net
class.
See this, and this, for more on the problem of Leaking Abstraction.
So you need to start thinking about message passing not object when designing your WCF interfaces, or you will hit lots of problems like this.

Is it possible to serialize objects without a parameterless constructor in WCF?

I know that a private parameterless constructor works but what about an object with no parameterless constructors?
I would like to expose types from a third party library so I have no control over the type definitions.
If there is a way what is the easiest? E.g. I don't what to have to create a sub type.
Edit:
What I'm looking for is something like the level of customization shown here: http://msdn.microsoft.com/en-us/magazine/cc163902.aspx
although I don't want to have to resort to streams to serialize/deserialize.
You can't really make arbitrary types serializable; in some cases (XmlSerializer, for example) the runtime exposes options to spoof the attributes. But DataContractSerializer doesn't allow this. Feasible options:
hide the classes behind your own types that are serializable (lots of work)
provide binary formatter surrogates (yeuch)
write your own serialization core (a lot of work to get right)
Essentially, if something isn't designed for serialization, very little of the framework will let you serialize it.
I just ran a little test, using a WCF Service that returns an basic object that does not have a default constructor.
//[DataContract]
//[Serializable]
public class MyObject
{
public MyObject(string _name)
{
Name = _name;
}
//[DataMember]
public string Name { get; set; }
//[DataMember]
public string Address { get; set; }
}
Here is what the service looks like:
public class MyService : IMyService
{
#region IMyService Members
public MyObject GetByName(string _name)
{
return new MyObject(_name) { Address = "Test Address" };
}
#endregion
}
This actually works, as long as MyObject is either a [DataContract] or [Serializable]. Interestingly, it doesn't seem to need the default constructor on the client side. There is a related post here:
How does WCF deserialization instantiate objects without calling a constructor?
I am not a WCF expert but it is unlikely that they support serialization on a constructor with arbitrary types. Namely because what would they pass in for values? You could pass null for reference types and empty values for structs. But what good would a type be that could be constructed with completely empty data?
I think you are stuck with 1 of 2 options
Sub class the type in question and pass appropriate default values to the non-parameterless constructor
Create a type that exists soley for serialization. Once completed it can create an instance of the original type that you are interested in. It is a bridge of sorts.
Personally I would go for #2. Make the class a data only structure and optimize it for serialization and factory purposes.