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?
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 !
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.
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;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With