230 likes | 383 Views
Taking Control of WCF. Jay Hill Patrick Roeper. Presentation Goals. Take the most common WCF experience and make it better Leverage OO design principles; improve extensibility, maintainability , testability Reduce repetition Demonstrate techniques when playing role of: Publisher
E N D
Taking Control of WCF Jay Hill Patrick Roeper
Presentation Goals • Take the most common WCF experience and make it better • Leverage OO design principles; improve extensibility, maintainability, testability • Reduce repetition • Demonstrate techniques when playing role of: • Publisher • Consumer • Publisher and Consumer
Demo • Jay is recovering from star-trek-hand syndrome • Occasional accidental-reboot while typing
MethodA(ReqA req) { Logger.Log(“Handling ReqA”); try { var result = new ResultA(); result.Name = GetName(req.Id); result.Email = GetEmail(req.Id); return result; } catch (Exception ex) { Logger.LogError(ex); throw; } } Horizontal API var result = new ResultA(); result.Name = GetName(req.Id); result.Email = GetEmail(req.Id); return result; return req.Role == GetRole(req.Id) ? new ResponseB(true) : new ResponseB(false); using(var db = new Ctx()) { return db.Contacts; } MethodB(ReqB req) { Logger.Log(“Handling ReqB”); try { return req.Role == GetRole(req.Id) ? new ResponseB(true) : new ResponseB(false); } catch (Exception ex) { Logger.LogError(ex); throw; } } MethodC(ReqC req) { Logger.Log(“Handling ReqC”); try { using(var db = new Ctx()) { return db.Contacts; } } catch (Exception ex) { Logger.LogError(ex); throw; } }
Horizontal API var result = new ResultA(); result.Name = GetName(req.Id); result.Email = GetEmail(req.Id); return result; return req.Role == GetRole(req.Id) ? new ResponseB(true) : new ResponseB(false); using(var db = new Ctx()) { return db.Contacts; } Logging Caching Exception Handling
What we don’t like • WCF services have many responsibilities; .svc file makes it hard to modularize operation handling • Generated client code is clunky and is a duplication of server-side contracts; easy to get out of sync • Client endpoints scale in parallel to server endpoints
Step 1 – Modularizing Operations • Move to request/response • Re-imagine each operation’s code as a separate class – MessageHandler<> • One-to-One with request • Provide a hook into WCF internals that will instantiate and invoke a MessageHandler<> instead of a service instance (.svc) • Identify and isolate infrastructural concerns from MessageHandler<> implementations
Recap • Each operation is handled in its own class • Extensible • Maintainable • Testable .svc File Invoker Invoker Message Handler
What we don’t like • WCF services have many responsibilities; .svc file makes it hard to modularize operation handling • Generated client code is clunky and is a duplication of server-side contracts; easy to get out of sync • Client endpoints scale in parallel to server endpoints
Step 2 – Deploy an API • Goodbye “Add Service Reference” • Move service definition and data contract components to a separate assembly • Package a client wrapper for invoking a service with the contract assembly • Open doors to build integration between products
Recap • Contracts moved to separate assembly and shared with consumers (possibly through build integration) • Client API packaged with contracts • DRY – Single LOC invocation • KISS – Hide IDisposable from consumer
Shared Contracts Server.sln Client.sln Contracts (Build) Contracts Server Logic Client Logic Web Host Client App
What we don’t like • WCF services have many responsibilities; .svc file makes it hard to modularize operation handling • Generated client code is clunky and is a duplication of server-side contracts; easy to get out of sync • Client endpoints scale in parallel to server endpoints
Authentication Client Authentication Service Financial Service Financial Client Search Service Search Client Administration Service Administration Client
Step 3 – Create a single gateway • Create another service (“Portal”) with a single operation that will process any request • Uses the same invoker as all other services to call a MessageHandler for the request • Include a client API that will accept any request • Add “facilities” under the covers • Compression
Recap DB Authentication MH1 MH2 Customer MH3 MH4 … SOA Byte[] Portal …Request Byte[] N-Tier
Nitpicker Corner • Async • Reuse requests for > 1 operations • Auditing vs. Tracing • Decorator vs. IErrorHandler • .Svc exception smell • Portal in distributed environment • Horizontal APIs enable discoverability