Commit 1bfbde3e authored by O'Reilly Media, Inc.'s avatar O'Reilly Media, Inc.

Initial commit

parents
9780596521325
\ No newline at end of file
## Example files for the title:
# Programming WCF 2nd Edition, by Juval Lowy
[![Programming WCF 2nd Edition, by Juval Lowy](http://akamaicovers.oreilly.com/images/9780596803056/cat.gif)](https://www.safaribooksonline.com/library/view/title/9780596157210//)
The following applies to example files from material published by O’Reilly Media, Inc. Content from other publishers may include different rules of usage. Please refer to any additional usage rights explained in the actual example files or refer to the publisher’s website.
O'Reilly books are here to help you get your job done. In general, you may use the code in O'Reilly books in your programs and documentation. You do not need to contact us for permission unless you're reproducing a significant portion of the code. For example, writing a program that uses several chunks of code from our books does not require permission. Answering a question by citing our books and quoting example code does not require permission. On the other hand, selling or distributing a CD-ROM of examples from O'Reilly books does require permission. Incorporating a significant amount of example code from our books into your product's documentation does require permission.
We appreciate, but do not require, attribution. An attribution usually includes the title, author, publisher, and ISBN.
If you think your use of code examples falls outside fair use or the permission given here, feel free to contact us at <permissions@oreilly.com>.
Please note that the examples are not production code and have not been carefully testing. They are provided "as-is" and come with no warranty of any kind.
// © 2008 IDesign Inc. All rights reserved
//Questions? Comments? go to
//http://www.idesign.net
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Reflection;
using System.Threading;
using System.Diagnostics;
using System.ComponentModel;
namespace ServiceModelEx
{
public abstract class AsyncClientBase<T> : ClientBase<T> where T : class
{
protected delegate IAsyncResult BeginOperationDelegate(object[] inValues,AsyncCallback asyncCallback,object state);
protected delegate object[] EndOperationDelegate(IAsyncResult result);
protected class InvokeAsyncCompletedEventArgs : AsyncCompletedEventArgs
{
object[] m_Results;
public InvokeAsyncCompletedEventArgs(Exception error,object userState) : base(error,false,userState)
{}
public object[] Results
{
get
{
return m_Results;
}
internal set
{
m_Results = value;
}
}
}
public AsyncClientBase()
{}
public AsyncClientBase(string endpointConfigurationName) : base(endpointConfigurationName)
{}
public AsyncClientBase(string endpointConfigurationName,string remoteAddress) : base(endpointConfigurationName,remoteAddress)
{}
public AsyncClientBase(string endpointConfigurationName,EndpointAddress remoteAddress) : base(endpointConfigurationName,remoteAddress)
{}
public AsyncClientBase(Binding binding,EndpointAddress remoteAddress) : base(binding,remoteAddress)
{}
protected void InvokeAsync(BeginOperationDelegate beginOperationDelegate,object[] inValues,EndOperationDelegate endOperationDelegate,SendOrPostCallback competionCallback,object state)
{
SynchronizationContext syncContext = SynchronizationContext.Current;
AsyncCallback completion = delegate(IAsyncResult result)
{
Exception error = null;
object[] results = {};
try
{
results = endOperationDelegate(result);
}
catch(Exception exception)
{
error = exception;
}
InvokeAsyncCompletedEventArgs completedEventArgs = new InvokeAsyncCompletedEventArgs(error,result.AsyncState);
completedEventArgs.Results = results;
if(syncContext == null)
{
competionCallback(completedEventArgs);
}
else
{
SendOrPostCallback send = delegate(object asyncResult)
{
competionCallback(asyncResult);
};
syncContext.Send(send,completedEventArgs);
}
};
beginOperationDelegate(inValues,completion,state);
}
}
}
// © 2008 IDesign Inc. All rights reserved
//Questions? Comments? go to
//http://www.idesign.net
using System;
using System.ServiceModel;
using System.Diagnostics;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.Collections.ObjectModel;
using System.ServiceModel.Dispatcher;
namespace ServiceModelEx
{
[AttributeUsage(AttributeTargets.Class)]
public class BindingRequirementAttribute : Attribute,IServiceBehavior,IEndpointBehavior
{
public bool ReliabilityRequired
{
get;set;
}
public bool WCFOnly
{
get;set;
}
public bool TransactionFlowEnabled
{
get;set;
}
static void ValidateWCF(ServiceEndpoint endpoint)
{
if(endpoint.Binding is NetTcpBinding ||
endpoint.Binding is NetNamedPipeBinding ||
endpoint.Binding is NetMsmqBinding)
{
return;
}
throw new InvalidOperationException("BindingRequirementAttribute requires WCF-to-WCF binding only, but binding for the endpoint with contract " + endpoint.Contract.ContractType + " in not.");
}
static void ValidateReliability(ServiceEndpoint endpoint)
{
if(endpoint.Binding is NetNamedPipeBinding)//Inherently reliable
{
return;
}
if(endpoint.Binding is WSDualHttpBinding)//Always reliable
{
return;
}
if(endpoint.Binding is NetTcpBinding)
{
NetTcpBinding tcpBinding = endpoint.Binding as NetTcpBinding;
if(tcpBinding.ReliableSession.Enabled)
{
return;
}
}
if(endpoint.Binding is WSHttpBindingBase)
{
WSHttpBindingBase wsBinding = endpoint.Binding as WSHttpBindingBase;
if(wsBinding.ReliableSession.Enabled)
{
return;
}
}
throw new InvalidOperationException("BindingRequirementAttribute requires reliability enabled, but binding for the endpoint with contract " + endpoint.Contract.ContractType + " has does not support reliability or has it disabled");
}
static void ValidateTransactionFlow(ServiceEndpoint endpoint)
{
Exception exception = new InvalidOperationException("BindingRequirementAttribute requires transaction flow enabled, but binding for the endpoint with contract " + endpoint.Contract.ContractType + " has it disabled");
foreach(OperationDescription operation in endpoint.Contract.Operations)
{
TransactionFlowAttribute attribute = operation.Behaviors.Find<TransactionFlowAttribute>();
if(attribute != null)
{
if(attribute.Transactions == TransactionFlowOption.Allowed)
{
if(endpoint.Binding is NetTcpBinding)
{
NetTcpBinding tcpBinding = endpoint.Binding as NetTcpBinding;
if(tcpBinding.TransactionFlow == false)
{
throw exception;
}
continue;
}
if(endpoint.Binding is NetNamedPipeBinding)
{
NetNamedPipeBinding ipcBinding = endpoint.Binding as NetNamedPipeBinding;
if(ipcBinding.TransactionFlow == false)
{
throw exception;
}
continue;
}
if(endpoint.Binding is WSHttpBindingBase)
{
WSHttpBindingBase wsBinding = endpoint.Binding as WSHttpBindingBase;
if(wsBinding.TransactionFlow == false)
{
throw exception;
}
continue;
}
if(endpoint.Binding is WSDualHttpBinding)
{
WSDualHttpBinding wsDualBinding = endpoint.Binding as WSDualHttpBinding;
if(wsDualBinding.TransactionFlow == false)
{
throw exception;
}
continue;
}
throw new InvalidOperationException("BindingRequirementAttribute requires transaction flow enabled, but binding for the endpoint with contract " + endpoint.Contract.ContractType + " does not support transaction flow");
}
}
}
}
void IServiceBehavior.Validate(ServiceDescription description,ServiceHostBase host)
{
IEndpointBehavior endpointBehavior = this;
foreach(ServiceEndpoint endpoint in description.Endpoints)
{
endpointBehavior.Validate(endpoint);
}
}
void IServiceBehavior.AddBindingParameters(ServiceDescription description,ServiceHostBase host,Collection<ServiceEndpoint> endpoints,BindingParameterCollection parameters)
{}
void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description,ServiceHostBase host)
{}
void IEndpointBehavior.AddBindingParameters(ServiceEndpoint serviceEndpoint,BindingParameterCollection bindingParameters)
{}
void IEndpointBehavior.ApplyClientBehavior(ServiceEndpoint serviceEndpoint,ClientRuntime behavior)
{}
void IEndpointBehavior.ApplyDispatchBehavior(ServiceEndpoint serviceEndpoint,EndpointDispatcher endpointDispatcher)
{}
void IEndpointBehavior.Validate(ServiceEndpoint endpoint)
{
if(WCFOnly)
{
ValidateWCF(endpoint);
}
if(TransactionFlowEnabled)
{
ValidateTransactionFlow(endpoint);
}
if(ReliabilityRequired)
{
ValidateReliability(endpoint);
}
}
}
}
// © 2008 IDesign Inc. All rights reserved
//Questions? Comments? go to
//http://www.idesign.net
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Configuration;
using System.Configuration;
using System.Diagnostics;
using System.Net.Security;
namespace ServiceModelEx
{
public class NetNamedPipeContextBinding : NetNamedPipeBinding
{
internal const string SectionName = "netNamedPipeContextBinding";
public ProtectionLevel ContextProtectionLevel
{get;set;}
public NetNamedPipeContextBinding()
{
ContextProtectionLevel = ProtectionLevel.EncryptAndSign;
}
public NetNamedPipeContextBinding(NetNamedPipeSecurityMode securityMode) : base(securityMode)
{
ContextProtectionLevel = ProtectionLevel.EncryptAndSign;
}
public NetNamedPipeContextBinding(string configurationName)
{
ContextProtectionLevel = ProtectionLevel.EncryptAndSign;
ApplyConfiguration(configurationName);
}
//The heart of the custom binding
public override BindingElementCollection CreateBindingElements()
{
BindingElement element = new ContextBindingElement(ContextProtectionLevel,ContextExchangeMechanism.ContextSoapHeader);
BindingElementCollection elements = base.CreateBindingElements();
elements.Insert(0,element);
return elements;
}
void ApplyConfiguration(string configurationName)
{
Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
ServiceModelSectionGroup sectionGroup = ServiceModelSectionGroup.GetSectionGroup(config);
BindingsSection bindings = sectionGroup.Bindings;
NetNamedPipeContextBindingCollectionElement section = (NetNamedPipeContextBindingCollectionElement)bindings[SectionName];
NetNamedPipeContextBindingElement element = section.Bindings[configurationName];
if(element == null)
{
throw new ConfigurationErrorsException("There is no binding named " + configurationName + " at " + section.BindingName);
}
else
{
element.ApplyConfiguration(this);
}
}
}
public class NetNamedPipeContextBindingElement : NetNamedPipeBindingElement
{
const string ContextProtectionLevelName = "contextProtectionLevel";
public NetNamedPipeContextBindingElement()
{
Initialize();
}
public NetNamedPipeContextBindingElement(string name) : base(name)
{
Initialize();
}
void Initialize()
{
ConfigurationProperty property = new ConfigurationProperty(ContextProtectionLevelName,typeof(ProtectionLevel),ProtectionLevel.EncryptAndSign);
Properties.Add(property);
ContextProtectionLevel = ProtectionLevel.EncryptAndSign;
}
protected override void OnApplyConfiguration(Binding binding)
{
base.OnApplyConfiguration(binding);
NetNamedPipeContextBinding netNamedPipeContextBinding = binding as NetNamedPipeContextBinding;
Debug.Assert(netNamedPipeContextBinding != null);
netNamedPipeContextBinding.ContextProtectionLevel = ContextProtectionLevel;
}
protected override Type BindingElementType
{
get
{
return typeof(NetNamedPipeContextBinding);
}
}
public ProtectionLevel ContextProtectionLevel
{
get
{
return (ProtectionLevel)base[ContextProtectionLevelName];
}
set
{
base[ContextProtectionLevelName] = value;
}
}
}
public class NetNamedPipeContextBindingCollectionElement : StandardBindingCollectionElement<NetNamedPipeContextBinding,NetNamedPipeContextBindingElement>
{}
}
// © 2008 IDesign Inc. All rights reserved
//Questions? Comments? go to
//http://www.idesign.net
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using ServiceModelEx;
using System.Collections.Generic;
namespace ServiceModelEx
{
public abstract class ContextClientBase<T> : ClientBase<T> where T : class
{
public Guid InstanceId
{
get
{
return ContextManager.GetInstanceId(InnerChannel);
}
}
public ContextClientBase()
{}
public ContextClientBase(string endpointName) : base(endpointName)
{}
public ContextClientBase(Binding binding,EndpointAddress remoteAddress) : base(binding,remoteAddress)
{}
public ContextClientBase(Guid instanceId) : this(ContextManager.InstanceIdKey,instanceId.ToString())
{}
public ContextClientBase(Guid instanceId,string endpointName) : this(ContextManager.InstanceIdKey,instanceId.ToString(),endpointName)
{}
public ContextClientBase(Guid instanceId,Binding binding,EndpointAddress remoteAddress) : this(ContextManager.InstanceIdKey,instanceId.ToString(),binding,remoteAddress)
{}
public ContextClientBase(string key,string value) : this(ContextManager.CreateContext(key,value))
{}
public ContextClientBase(string key,string value,string endpointName) : this(ContextManager.CreateContext(key,value),endpointName)
{}
public ContextClientBase(string key,string value,Binding binding,EndpointAddress remoteAddress) : this(ContextManager.CreateContext(key,value),binding,remoteAddress)
{}
public ContextClientBase(IDictionary<string,string> context)
{
SetContext(context);
}
public ContextClientBase(IDictionary<string,string> context,string endpointName) : base(endpointName)
{
SetContext(context);
}
public ContextClientBase(IDictionary<string,string> context,Binding binding,EndpointAddress remoteAddress) : base(binding,remoteAddress)
{
SetContext(context);
}
public T DuplicateProxy()
{
T channel = ChannelFactory<T>.CreateChannel(Endpoint.Binding,Endpoint.Address);
IClientChannel innerChannel = channel as IClientChannel;
Guid instanceId = ContextManager.GetInstanceId(InnerChannel);
ContextManager.SetInstanceId(innerChannel,instanceId);
return channel;
}
void SetContext(IDictionary<string,string> context)
{
VerifyContextBinding();
//Special case is context with only instance ID that is the empty guid
if(context.Count == 1)
{
if(context.ContainsKey(ContextManager.InstanceIdKey))
{
if(context[ContextManager.InstanceIdKey] == Guid.Empty.ToString())
{
return;
}
}
}
ContextManager.SetContext(InnerChannel,context);
}
void VerifyContextBinding()
{
BindingElementCollection elements = Endpoint.Binding.CreateBindingElements();
if(elements.Contains(typeof(ContextBindingElement)))
{
return;
}
throw new InvalidOperationException("Can only use a context binding with " + GetType());
}
}
}
\ No newline at end of file
// 2008 IDesign Inc. All rights reserved
//Questions? Comments? go to
//http://www.idesign.net
using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
namespace ServiceModelEx
{
public static class ContextManager
{
public const string InstanceIdKey = "instanceId";
public static Guid InstanceId
{
get
{
string id = GetContext(InstanceIdKey) ?? Guid.Empty.ToString();
return new Guid(id);
}
}
public static IDictionary<string,string> CreateContext(string key,string value)
{
IDictionary<string,string> context = new Dictionary<string,string>();
context[key] = value;
return context;
}
//Called by the service to read incoming context over context bindings
public static string GetContext(string key)
{
if(OperationContext.Current == null)
{
return null;
}
if(OperationContext.Current.IncomingMessageProperties.ContainsKey(ContextMessageProperty.Name))