290 likes | 487 Views
WCF Extensibility. Scott Reed Owner - Brain Hz Software scott@brainhzsoftware.com Instructor – DevelopMentor scottr@develop.com. WCF Design Goal. To be the single best way of getting any two pieces of software to communicate under any circumstances (assuming at least one is .NET).
E N D
WCF Extensibility Scott Reed Owner - Brain Hz Software scott@brainhzsoftware.com Instructor – DevelopMentor scottr@develop.com
WCF Design Goal • To be the single best way of getting any two pieces of software to communicate under any circumstances (assuming at least one is .NET)
Extensibility in a nutshell • WCF doesn’t support everything out of the box • When a limitation is reached WCF can still be used by adding or replacing a specific piece of the framework • (Almost) everything can be extended • Infinitely flexible = more difficult than it needs to be
Client Service C C C C C B B B B B A A A A A Service
Client Code parameters Service Type parameters Service Model Layer Client Runtime Dispatcher Runtime Channel Channel Channel Channel Transport Channel byte[] Channel Layer Transport Channel byte[] Encoder Encoder
ServiceHost ChannelDispatcher EndpointDispatcher DispatchRuntime DispatchOperation ChannelStack IChannel(Protocol) IChannel (Protocol) IChannel (Transport)
Behavior extensibility steps 1) Implement the functionality • MessageInspector, ErrorHandler, InstanceProvider, etc. 2) Hook up the functionality through behavior • ServiceBehavior, EndpointBehavior, OperationBehavior 3) Let WCF know about the behavior from #2 • Programmatically, configuratively, declaratively
[MyBehavior] <myBehavior /> .Description.Behaviors.Add(new MyBehavior()); Behaviors When Behaviors Run 1. Reflect Over T ServiceHost() or ChannelFactory() 2. Load Config .Description 3. Build Runtime .Open(); 4. Open Resources
Three Behaviors • All three behavior types have the same methods: public void AddBindingParameters(<description>, BindingParameterCollection); public void ApplyClientBehavior(<description>, <client plumbing>);* public void ApplyDispatchBehavior(<description>, <service plumbing>); public void Validate(<description>); *ApplyClientBehavior isn’t present in IServiceBahvior
Parameter Inspectors Parameter Inspection Useful for consistent client and service side validation Client Runtime Client Operation Channel public interface IParameterInspector { object BeforeCall(string operationName, object[] inputs); void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState); }
Formatter Message Formatting Actually creates the message from parameters, and breaks apart the message into parameters and return value. Client Runtime Client Operation Channel public interface IClientMessageFormatter { Message SerializeRequest(MessageVersion messageVersion, object[] parameters); object DeserializeReply(Message message, object[] parameters); }
Message Inspectors Message Inspection The most useful, allows last minute manipulation of the message before being sent into the channel layer. Client Runtime Client Operation Channel public interface IClientMessageInspector { object BeforeSendRequest(ref Message request, IClientChannel channel); void AfterReceiveReply(ref Message reply, object state); }
Other client side extension points • Via (sends to intermediaries) • ChannelInitializers (manipulate channel stack) • But the service has far more extensibility…
Demo • Client side message inspector • Adding a behavior extension element
Error Handlers Error Handling Allows a central place to perform exception to fault message translation. ChannelDispatcher EndpointDispatcher DispatchRuntime DispatchOperation public interface IErrorHandler { bool HandleError(Exception error); void ProvideFault(Exception error, MessageVersion version, ref Message fault); }
Address Filter Contract Filter Address / Contract Filtering Allows the messages to be matched to an appropriate dispatch runtime. ChannelDispatcher EndpointDispatcher DispatchRuntime DispatchOperation public abstract class MessageFilter { IMessageFilterTable<FilterData> CreateFilterTable<FilterData>(); bool Match(Message message); }
Instance Context Provider Providing InstanceContext Allows special case instancing modes ChannelDispatcher EndpointDispatcher DispatchRuntime DispatchOperation public interface IInstanceContextProvider { InstanceContextGetExistingInstanceContext(Message message, IContextChannelchannel); void InitializeInstanceContext(InstanceContextinstanceContext, Message message, IContextChannel channel); bool IsIdle(InstanceContextinstanceContext); void NotifyIdle(InstanceContextIdleCallback callback, InstanceContextinstanceContext);}
Instance Provider Providing Instance Allows service object pooling ChannelDispatcher EndpointDispatcher DispatchRuntime DispatchOperation public interface IInstanceProvider { object GetInstance(InstanceContextinstanceContext,Message message); void ReleaseInstance(InstanceContextinstanceContext,object instance); }
Message Inspectors Message Inspection (again) The most useful, allows manipulation of the message right after being received from the channel layer. ChannelDispatcher EndpointDispatcher DispatchRuntime DispatchOperation public interface IDispatchMessageInspector { object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext); void BeforeSendReply(ref Message reply, object correlationState); }
Operation Selector Operation Selection Allows operation selection by something other than Action ChannelDispatcher EndpointDispatcher DispatchRuntime DispatchOperation public interface IDispatchOperationSelector { string SelectOperation(ref Message message); } public SynchronizedKeyedCollection<string, DispatchOperation> Operations { get { } }
Formatter Message Formatting (again) Actually creates the message from parameters, and breaks apart the message into parameters and return value. ChannelDispatcher EndpointDispatcher DispatchRuntime DispatchOperation public interface IDispatchMessageFormatter { void DeserializeRequest(Message message, object[] parameters); Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result); }
Invoker Operation Invocation Actually takes control of calling the service object. ChannelDispatcher EndpointDispatcher DispatchRuntime DispatchOperation public interface IOperationInvoker { object[] AllocateInputs(); object Invoke(object instance, object[] inputs, out object[] outs); IAsyncResultInvokeBegin(object instance, object[] inputs, ...); object InvokeEnd(object instance, out object[] outputs, ...); }
Parameter Inspectors Parameter Inspection (again) Useful for consistent client and service side validation. ChannelDispatcher EndpointDispatcher DispatchRuntime DispatchOperation public interface IParameterInspector { object BeforeCall(string operationName, object[] inputs); void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState); }
Other service extensibility points • Extensions • ChannelInitializers • ServiceThrottle • ExternalAuthorizationPolicies • RoleProvider • ServiceAuthorizationManager • InputSessionShutdownHandlers • InstanceContextInitializers • FaultContractInfos • CallContextInitializers • Etc...
Demo • Service side error handler
Channel Layer extensibility • Easy ways: • Binding configuration • Programmatic binding manipulation • Custom bindings • Hard way • Writing a protocol channel • Really hard way • Writing a transport channel
Writing a Channel (Overview) • To write a channel, you must • Write the channel itself • Support the proper “shapes” • Input, Output, Duplex, Request, Reply, RequestContext • Possibly provide asynchronous versions of all method • Write a ChannelFactory • Write a ChannelListener • Write a BindingElement
Extensibility Summary • If possible stick with Service Model layer • There are tons of extension points • It’s not that hard to do • If you have to write a channel • Plan on spending a couple of weeks