Reputation: 8319
I am writing a client/server application, where the client is a Windows Forms app, and the server is a WCF service hosted in a Windows Service. Note that I control both sides of the application.
I am trying to implement the practice of coding against an interface: i.e. I have a Shared assembly which is referenced by the client application. This project contains my WCF ServiceContracts and interfaces which will be exposed to clients. I am trying to only expose interfaces to the clients, so that they are only dependant on a contract, not any specific implementation. One of the reasons for doing this is so that I can have my service implementation, and domain change at any time without having to recompile and redeploy the clients. The interfaces/contracts will in this case not change. I only need to recompile and redeploy my WCF service.
The design issue I am facing now, is: on the client, how do I create new instances of objects, e.g. ICustomer
, if the client doesn't know about the Customer
concrete implementation? I need to create a new customer to be saved to the DB.
Do I use dependency injection, or a Factory class to instantiate new objects, or should I just allow the client to create new instances of concrete implementations?
I am not doing TDD, and I will typically only have one implementation of ICustomer
or any other exposed interface.
Upvotes: 1
Views: 943
Reputation: 2634
You've probably got your answer by now but I'm trying to do something similar at the moment - inject my Repositories into my WCF services, so those services don't have any dependencies on code that accesses the db. I've found the following articles which I think may help answer your question:
Link http://www.silverlightshow.net/items/Deep-dive-into-WCF-part-1-TDD.aspx
HTH
Ciaran
Upvotes: 0
Reputation: 2013
I've come across the same question in my WCF development. The fact is there must be a concrete implementation of your data contracts on both sides of the communication. So where do those implementations come from? On the server side, the implementations are typically your business objects, with all of their business logic and so on. And you don't want to use those implementations on the client--that would mean putting them in the shared assembly, and you don't want that for several reasons. So the client needs its own, separate set of concrete classes. Either you're going to write them yourself, or you're going to have them generated automatically.
Writing the implementations yourself is tedious. Because the client objects are typically simple--all they really do is store data--code generation is probably the way to go. At that point you have a few choices: You could generate code based on the WSDL via Add Service Reference, or you could generate classes at runtime based on the interfaces using a framework of some sort.
Both approaches give you the benefits of coding against an interface: As long as the interface doesn't change, the server and client can be modified and rebuilt independently. In one case the interface is the WSDL and in the other it's a CLR interface, but since WCF generates the WSDL based on the CLR interface, they're really one and the same. Personally I like Add Service Reference because it's already there and doesn't add any dependencies to my project, but pick whichever you like better.
Upvotes: 1
Reputation: 6827
We've discussed doing this internally for enterprise apps where we control both sides of application, as a productivity gain, for .NET clients. Jury is still out on this one.
However, when discussing having contracts in a shared library (between client and service) typically this would include both service contracts ([ServiceContract]), as well as the entities ([DataContract]) for any parameters to service operations. These types are traditionally the concrete types your expecting for those service operations.
In your case, your DTO implements an interface, such as ICustomer, implementing properties that represent Customer, and is a [DataContract]. Assuming that the type will serialize correctly going to the service (using NetDataContractSerializer), then I imagine the client can pretty much shove whatever concrete implementation they want - the service is only interested in what conforms to ICustomer.
A client can create any concrete instance of ICustomer that they want: OrderingCustomer, FinanceCustomer, etc. As long as the type implements the service ICustomer interface it could conceivably be passed as the value to a service operation if it serializes correctly. e.g.
public class OrderingCustomer : ICustomer
{
}
I am not sure that you will achieve zero client impact your aiming for. If you change an interface type (add property to ICustomer) your clients will need to recompile. If you add a parameter, even one of core .NET type (e.g. int), your clients will need to recompile. This is effectively the same impact as the client updating their service reference and recompiling.
However, if your not changing your service implementation or behavior (e.g. bug fix), then in both cases (shared types or service reference) the clients will need not do anything as long as that contract between you and your client doesn't change. Of course, I'd also like to hear any experiences you've had with this that prove this wrong!
This practice would also completely kill your interoperable story with non-.NET systems. As sure as I sweep this one under the rug, some department somewhere will hear about your super spiffy service and want to use it....and they will be running some Java stack,or COBOL, or FORTRAN..etc. :)
Upvotes: 1
Reputation: 755227
Well, I think you're confusing (or mixing up) two things:
your Service contract will describe only the functions your service exposes, things like FindCustomer
or AddCustomer
- for those operations, your client only needs to know the interface, and when you add a client proxy (by using "Add Service Reference"), you'll also get a YourServiceClient
concrete class in your client proxy which implements those calls
the Data contract describes the data going back and forth, and those are always concrete classes - Customer
, Invoice
etc. - since those are based on a XML schema. Those are defined at the server, and the client, when adding a Service Reference, will infer those types from the WSDL/XSD published by the service, and will create concrete classes on the client side for this data. Those are NOT the exact same classes as the server uses - they look the same, and their main requirement is that they serialize into and deserialize from XML the same - but they're different classes really (different .NET namespace, most likely).
So for your functionality, you have the service contract which you really only need to share as an interface - that's sufficient, and the client will create a "proxy class" (the YourServiceClient
class) from that interface. The client does not depend on the server implementation or its concrete class there.
On the other hand, the data being exchanged - being serialized into XML format by default - will always be concrete classes (no interfaces) which are infered from the WSDL/XSD - again, the client does not depend on the server's classes - only on their "XML serialization fingerprint", so to speak.
Now I'm not sure this helps you a lot :-) but at least it hopefully makes things as they are a bit clearer - or not?
Marc
Upvotes: 0