views:

420

answers:

4

I have a WPF application which so far has been client only, but now I'm working on splitting it into a client and server side. In this work I'm introducing WCF for the client-server communication. My application has several projects, and service references are needed from more than one of these.

Initial effort in doing the separation is to do everything "straight forward". All projects needing to communicate with a service gets a service reference, and so do the main WPF application project - to get the app.config there. I find this to turn into a mess rather quickly, and I can't imagine this being the typical architecture people use? I've also seen problems with the fact that each of the service references generates a new implementation of the DataContract classes - hence there is no common understanding of the DataContract classes on cross of projects. I have some ViewModel classes in one project, and another project instanciating some ViewModel. I'd like to pass the object received from service, but I can't as the generated client-side representation of the object received differs in each project.

So - is there a recommended way of structuring such client/server separations using WCF? Or principles to follow? I'm thinking one common Proxy project used on the client side that does the communication with the services, wraps the received data, and returns data on a form well known to the client libraries. Should give only one service reference, and I guess I only need the App.config in the wpfApp-project? Does this make sense?

+1  A: 

It depends. WCF is a big framework and it's meant to span a lot of different scenarios.

But for a straightforward application like yours, when you don't care about stuff like Java interop or generic web services interop, this is what I do:

All DataContract classes and ServiceContract interfaces go into a library (or libraries) which is shared between the client and the server. Note that you probably shouldn't decorate your service Implementation with ServiceContract, you'd create a separate interface with the ServiceContract attributes which you could put in a shared assembly.

So you seem to be doing just about everthing right. What you probably DON'T need is to auto-generate the proxies at all in this case. That's just causing you pain. So don't use the Add Service Reference dialog for what you're doing. Just include your shared DataContract assemblies and use ChannelFactory to get a proxy to your service interface defined in the shared library. This also keeps you from having to keep re-generating the proxy in Visual Studio, which, for any decent sized project, gets old VERY FAST.

If you're going this route, you can also get rid of the MetaDataExchange endpoint, since that's only needed to describe the service to the client. Since you do everything in a shared assembly, you don't need the service description, since you already have the service description in code form.

Dave Markle
Thanks! This sounds very appealing. The auto-generated proxies have indeed caused pain already... I'm actually trying a similar implementation to the one you describe already, but it stopped when I wanted async services. Can I easily use the ChannelFactory to generate async services too?
stiank81
Oh, and JavaInterop etc is not relevant at all. This will be all .net to .net! Having the DataContracts in a shared library I can actually return e.g. a MyClass object from a service, and it will be the exact same type received?
stiank81
Yes: http://msdn.microsoft.com/en-us/library/bb885132.aspx
Dave Markle
+1  A: 

The usual structure I use is:

Common - contains interfaces, data-contracts, service contracts, abstract classes etc; Client - references Common, contains server proxy class; Server - references Common, contains actual implementation classes;

Goran
Agreed. Though I would often make the common library include DTO's that can be used on both sides of the service and then don't use the generated proxy classes.
asgerhallas
Sounds like I need to have a common project for the shared stuff..! Are you using autogenerated proxies, or omitting those - like @asgerhallas? Sure think I'd like to omit using them if I can. They have caused too much pain already..
stiank81
I derive the proxy class from ClientBase<T> and implement interface to forward calls to Channel.
Goran
Sounds good. Can you implement async services too deriving from ClientBase, or must I use ClientFactory instead? If I've understood correctly the service should be made async on the server side - in which case I guess this won't make a difference?..
stiank81
You can implement async services. Just create beginX and endX methods (in interface, implementation and proxy).
Goran
@Goran: On the server side then? Looking into it, but not too much time this weekend.. I have a question on this if you feel like putting up a quick sample :-) http://stackoverflow.com/questions/1890679/implementing-an-async-wcf-service
stiank81
A: 

On good read on a way to structure such an application is Davy Brions series of post found here: http://davybrion.com/blog/2009/11/requestresponse-service-layer-series/

asgerhallas
Thanks! Will have a look.
stiank81
+4  A: 

I like to structure my WCF solutions like this:

Contracts (class library)
Contains all the service, operations, fault, and data contracts. Can be shared between server and client in a pure .NET-to-.NET scenario

Service implementation (class library)
Contains the code to implement the services, and any support/helper methods needed to achieve this. Nothing else.

Service host(s) (optional - can be Winforms, Console App, NT Service)
Contains service host(s) for debugging/testing, or possibly also for production.

This basically gives me the server-side of things.

On the client side:

Client proxies (class library)
I like to package my client proxies into a separate class library, so that they can be reused by multiple actual client apps. This can be done using svcutil or "Add Service Reference" and manually tweaking the resulting horrible app.config's, or by doing manual implementation of client proxies (when sharing the contracts assembly) using ClientBase<T> or ChannelFactory<T> constructs.

1-n actual clients (any type of app)
Will typically only reference the client proxies assembly, or maybe the contracts assembly, too, if it's being shared. This can be ASP.NET, WPF, Winforms, console app, other services - you name it.

That way; I have a nice and clean layout, I use it consistently over and over again, and I really think this has made my code cleaner and easier to maintain.

This was inspired by Miguel Castro's Extreme WCF screen cast on DotNet Rocks TV with Carl Franklin - highly recommended screen cast !

marc_s
Thanks for a very nice answer! A few questions back: Having a service host you need to start both the host and the client when starting your app? Or is there some way to get around this? Regarding Client Proxies - which would you prefer? Manual impl sounds more consistent as you don't have to deal with service references going out of date..
stiank81
@bambuska: sure, you have to launch both the service host and the client to test; pick "launch multiple projects" in Visual Studio to achieve this - you can launch both the service host and the client when pressing F5.
marc_s
Client proxies: I like the total control I have when I do manual implementation of the client proxies - this **requires** though that I can share the contract between server and client (since the manual impl. of client proxies must have access to the actual contracts)
marc_s
The answer I was hoping for :-) Just struggling with implementing async service functions...
stiank81
Regarding testing - you can add reference to Service implementation and use implementation class instead of proxies. Once everything works remove reference to Service implementation and go back to using proxies.
Goran