WCF Extensibility - Brain Hz Consulting Blog

advertisement
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 B A
A B C
C B A
A B C
Service
A B C
Client Code
Service Type
parameters
parameters
Service Model Layer
Client
Runtime
Dispatcher
Runtime
Channel
Channel
Channel
Channel
Encoder
Channel Layer
Encoder
Transport
Channel
Transport
Channel
byte[]
byte[]
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
When Behaviors Run
1. Reflect Over T
[MyBehavior]
ServiceHost() or
ChannelFactory()
2. Load Config
.Description
<myBehavior />
.Description.Behaviors.Add(new MyBehavior());
3. Build Runtime
.Open();
4. Open Resources
Behaviors
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 Inspection
Useful for consistent client and service side validation
Parameter
Inspectors
Client Operation
Client Runtime
Channel
public interface IParameterInspector
{
object BeforeCall(string operationName, object[] inputs);
void AfterCall(string operationName, object[] outputs,
object returnValue, object correlationState);
}
Message Formatting
Actually creates the message from parameters, and breaks apart the message
into parameters and return value.
Formatter
Client Operation
Client Runtime
Channel
public interface IClientMessageFormatter
{
Message SerializeRequest(MessageVersion messageVersion,
object[] parameters);
object DeserializeReply(Message message, object[] parameters);
}
Message Inspection
The most useful, allows last minute manipulation of the message before being
sent into the channel layer.
Message
Inspectors
Client Operation
Client Runtime
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 Handling
Allows a central place to perform exception to fault message translation.
Error
Handlers
ChannelDispatcher
EndpointDispatcher
DispatchRuntime
DispatchOperation
public interface IErrorHandler
{
bool HandleError(Exception error);
void ProvideFault(Exception error, MessageVersion version,
ref Message fault);
}
Address / Contract Filtering
Allows the messages to be matched to an appropriate dispatch runtime.
Address
Filter
ChannelDispatcher
Contract
Filter
EndpointDispatcher
DispatchRuntime
DispatchOperation
public abstract class MessageFilter
{
IMessageFilterTable<FilterData> CreateFilterTable<FilterData>();
bool Match(Message message);
}
Providing InstanceContext
Allows special case instancing modes
Instance
Context
Provider
ChannelDispatcher
EndpointDispatcher
DispatchRuntime
DispatchOperation
public interface IInstanceContextProvider
{
InstanceContext GetExistingInstanceContext(Message message,
IContextChannel channel);
void InitializeInstanceContext(InstanceContext instanceContext,
Message message, IContextChannel channel);
bool IsIdle(InstanceContext instanceContext);
void NotifyIdle(InstanceContextIdleCallback callback,
InstanceContext instanceContext);}
Providing Instance
Allows service object pooling
Instance
Provider
ChannelDispatcher
EndpointDispatcher
DispatchRuntime
DispatchOperation
public interface IInstanceProvider
{
object GetInstance(InstanceContext instanceContext,Message message);
void ReleaseInstance(InstanceContext instanceContext,object instance);
}
Message Inspection (again)
The most useful, allows manipulation of the message right after being received
from the channel layer.
Message
Inspectors
ChannelDispatcher
EndpointDispatcher
DispatchRuntime
DispatchOperation
public interface IDispatchMessageInspector
{
object AfterReceiveRequest(ref Message request, IClientChannel
channel, InstanceContext instanceContext);
void BeforeSendReply(ref Message reply, object correlationState);
}
Operation Selection
Allows operation selection by something other than Action
Operation
Selector
ChannelDispatcher
EndpointDispatcher
DispatchRuntime
DispatchOperation
public interface IDispatchOperationSelector
{
string SelectOperation(ref Message message);
}
public SynchronizedKeyedCollection<string, DispatchOperation>
Operations { get { } }
Message Formatting (again)
Actually creates the message from parameters, and breaks apart the message
into parameters and return value.
Formatter
ChannelDispatcher
EndpointDispatcher
DispatchRuntime
DispatchOperation
public interface IDispatchMessageFormatter
{
void DeserializeRequest(Message message, object[] parameters);
Message SerializeReply(MessageVersion messageVersion,
object[] parameters, object result);
}
Operation Invocation
Actually takes control of calling the service object.
Invoker
ChannelDispatcher
EndpointDispatcher
DispatchRuntime
DispatchOperation
public interface IOperationInvoker
{
object[] AllocateInputs();
object Invoke(object instance, object[] inputs, out object[] outs);
IAsyncResult InvokeBegin(object instance, object[] inputs, ...);
object InvokeEnd(object instance, out object[] outputs, ...);
}
Parameter Inspection (again)
Useful for consistent client and service side validation.
Parameter
Inspectors
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
Download