Created
September 1, 2008 21:21
-
-
Save jezell/8344 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.ServiceModel; | |
using System.Reflection; | |
using System.Runtime.Serialization; | |
namespace IServiceOriented.ServiceBus | |
{ | |
/// <summary> | |
/// Provides support for dispatching messages to WCF endpoints. | |
/// </summary> | |
[Serializable] | |
[DataContract] | |
public class WcfDispatcher : Dispatcher | |
{ | |
public WcfDispatcher() | |
{ | |
} | |
public WcfDispatcher(WcfDispatchStyle dispatchStyle) | |
{ | |
DispatchStyle = dispatchStyle; | |
} | |
// TODO: if the same dispatcher instance is reused with another type this will be invalid | |
void initActionLookup() | |
{ | |
Dictionary<string, MethodInfo> actionLookup = new Dictionary<string, MethodInfo>(); | |
foreach (MethodInfo method in Endpoint.ContractType.GetMethods()) | |
{ | |
object[] attributes = method.GetCustomAttributes(typeof(OperationContractAttribute), false); | |
if (attributes.Length > 0) | |
{ | |
OperationContractAttribute oca = (OperationContractAttribute)attributes[0]; | |
string action = oca.Action; | |
if (action == null) | |
{ | |
action = method.Name; | |
} | |
actionLookup.Add(action, method); | |
} | |
} | |
_actionLookup = actionLookup; | |
} | |
// TODO: if the same dispatcher instance is reused with another type this will be invalid | |
void initTypeLookup() | |
{ | |
Dictionary<Type, MethodInfo> typeLookup = new Dictionary<Type, MethodInfo>(); | |
foreach (MethodInfo method in Endpoint.ContractType.GetMethods()) | |
{ | |
object[] attributes = method.GetCustomAttributes(typeof(OperationContractAttribute), false); | |
if (attributes.Length > 0) | |
{ | |
OperationContractAttribute oca = (OperationContractAttribute)attributes[0]; | |
ParameterInfo[] parameters = method.GetParameters(); | |
if (parameters.Length == 1) | |
{ | |
typeLookup.Add(parameters[0].ParameterType, method); | |
} | |
} | |
} | |
_typeLookup = typeLookup; | |
} | |
/// <summary> | |
/// Specifies whether to apply the credentials of the user that published the message. | |
/// </summary> | |
/// <remarks>Credentials will be passed as UserName credentials, not using Windows impersonation or delegation.</remarks> | |
[DataMember] | |
public bool ApplyCredentials | |
{ | |
get; | |
set; | |
} | |
protected virtual void ApplySecurityContext(ChannelFactory factory) | |
{ | |
if (ApplyCredentials) | |
{ | |
if (DispatchContext.MessageDelivery.Context.ContainsKey(MessageDelivery.PrimaryIdentityNameKey)) | |
{ | |
factory.Credentials.UserName.UserName = (string)DispatchContext.MessageDelivery.Context[MessageDelivery.PrimaryIdentityNameKey]; | |
factory.Credentials.UserName.Password = ""; | |
} | |
} | |
} | |
protected override void Dispatch(SubscriptionEndpoint endpoint, MessageDelivery messageDelivery) | |
{ | |
// TODO: Clean this up. Creating channel factory for each call is expensive | |
Type channelType = typeof(ChannelFactory<>).MakeGenericType(endpoint.ContractType); | |
object factory = Activator.CreateInstance(channelType, endpoint.ConfigurationName); | |
((ChannelFactory)factory).Endpoint.Address = new EndpointAddress(endpoint.Address); | |
ApplySecurityContext((ChannelFactory)factory); | |
IClientChannel proxy = (IClientChannel)channelType.GetMethod("CreateChannel", new Type[] { }).Invoke(factory, new object[] { }); | |
bool success = false; | |
try | |
{ | |
MethodInfo methodInfo; | |
if (DispatchStyle == WcfDispatchStyle.Action) | |
{ | |
if (_actionLookup == null) | |
{ | |
initActionLookup(); | |
} | |
if (!_actionLookup.TryGetValue(messageDelivery.Action, out methodInfo)) | |
{ | |
foreach (string a in _actionLookup.Keys) | |
{ | |
if (a == "*") | |
{ | |
methodInfo = _actionLookup[a]; | |
break; | |
} | |
} | |
} | |
} | |
else if (DispatchStyle == WcfDispatchStyle.Type) | |
{ | |
if (_typeLookup == null) | |
{ | |
initTypeLookup(); | |
} | |
if (_typeLookup.TryGetValue(messageDelivery.Message.GetType(), out methodInfo)) | |
{ | |
foreach (Type t in _typeLookup.Keys) | |
{ | |
if (t == typeof(object)) | |
{ | |
methodInfo = _typeLookup[t]; | |
break; | |
} | |
} | |
} | |
} | |
else | |
{ | |
throw new NotSupportedException(); | |
} | |
if (methodInfo != null) | |
{ | |
methodInfo.Invoke(proxy, new object[] { messageDelivery.Message }); | |
} | |
else | |
{ | |
throw new InvalidOperationException("Matching method not found"); | |
} | |
proxy.Close(); | |
success = true; | |
} | |
finally | |
{ | |
if (!success) | |
{ | |
proxy.Abort(); | |
} | |
} | |
} | |
[NonSerialized] | |
Dictionary<string, MethodInfo> _actionLookup; | |
[NonSerialized] | |
Dictionary<Type, MethodInfo> _typeLookup; | |
/// <summary> | |
/// Gets or sets the way that this dispatcher will determine which operation to invoke. | |
/// </summary> | |
public WcfDispatchStyle DispatchStyle | |
{ | |
get; | |
set; | |
} | |
} | |
public enum WcfDispatchStyle | |
{ | |
/// <summary> | |
/// Dispatch by finding an operation that matches the requested action (or "*" if no direct match) | |
/// </summary> | |
Action, | |
/// <summary> | |
/// Dispatch by finding an operation that accepts the requested message type (or object if no direct match) | |
/// </summary> | |
Type | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment