Created
August 1, 2012 01:59
-
-
Save edwinf/3222717 to your computer and use it in GitHub Desktop.
WCF Proxy through DI
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; | |
namespace WCFDIProxy | |
{ | |
public partial class ServiceContainer | |
{ | |
partial void GetServiceLocators(ref List<ServiceContainer.ServiceLocator> locators) | |
{ | |
locators = new List<ServiceContainer.ServiceLocator>(); | |
/* | |
* Put your service locator code here. You can read it from XML files on the disk, you can pull | |
* them from a database, however you want to define them. | |
} | |
} | |
} |
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
namespace WCFDIProxy | |
{ | |
#region | |
using System; | |
using System.Collections.Generic; | |
using System.Reflection; | |
using System.ServiceModel; | |
using System.ServiceModel.Description; | |
using Microsoft.Practices.Unity; | |
#endregion | |
public partial class ServiceContainer | |
{ | |
#region Constants and Fields | |
private readonly Dictionary<string, ServiceLocator> _ServiceLocators; | |
private readonly IUnityContainer _UnityContainer; | |
private static ServiceContainer _This; | |
#endregion | |
#region Constructors and Destructors | |
private ServiceContainer() | |
{ | |
this._ServiceLocators = new Dictionary<string, ServiceLocator>(); | |
this._UnityContainer = new UnityContainer(); | |
this.BuildServiceReferences(this._UnityContainer); | |
} | |
private ServiceContainer(IUnityContainer container) | |
{ | |
this._UnityContainer = container; | |
} | |
#endregion | |
#region Properties | |
/// <summary> | |
/// Singleton Property of the ServiceContainer class | |
/// </summary> | |
public static ServiceContainer Proxys | |
{ | |
get | |
{ | |
return _This; | |
} | |
} | |
#endregion | |
#region Public Methods | |
/// <summary> | |
/// This call should be put in your app start routine. This will intiialize the container per the default settings / code. | |
/// </summary> | |
public static void Initialize() | |
{ | |
_This = new ServiceContainer(); | |
} | |
/// <summary> | |
/// This function is used when you want to override your default configuration with a new unity container. This is useful when | |
/// you want to call a WCF service locally to try to debug issues. | |
/// </summary> | |
/// <param name="container"></param> | |
public static void Initialize(IUnityContainer container) | |
{ | |
_This = new ServiceContainer(container); | |
} | |
/// <summary> | |
/// Resolves an interface into a WCF proxy based on configuration. | |
/// </summary> | |
/// <typeparam name="T">Interface to resolve</typeparam> | |
/// <returns>ServiceProxy wrapper of created interface</returns> | |
public ServiceProxy<T> Resolve<T>() where T : class, IDisposable | |
{ | |
T proxy = this._UnityContainer.Resolve<T>(); | |
return new ServiceProxy<T>(proxy); | |
} | |
#endregion | |
#region Methods | |
partial void GetServiceLocators(ref List<ServiceLocator> locators); | |
private void BuildServiceReferences(IUnityContainer container) | |
{ | |
//Log.Debug("Begin building Service References"); | |
List<ServiceLocator> locators = null; | |
GetServiceLocators(ref locators); | |
if (locators != null) | |
{ | |
for (int i = 0; i < locators.Count; i++) | |
{ | |
locators[i].FindInterfaceType(); | |
this._ServiceLocators.Add(locators[i].InterfaceName, locators[i]); | |
} | |
//Log.Debug("Register interfaces with unity"); | |
foreach (string interfaceName in this._ServiceLocators.Keys) | |
{ | |
try | |
{ | |
//registers the interface with unity specifying that to create an instance of this interface, it should call the CreateService method on the service locator class | |
container.RegisterType(this._ServiceLocators[interfaceName].Interface, new InjectionFactory(this._ServiceLocators[interfaceName].CreateService)); | |
} | |
catch (Exception ex) | |
{ | |
//Log.Error("Error instantiating service: " + interfaceName, ex); | |
//throw; | |
} | |
} | |
} | |
//Log.Debug("End building service references"); | |
} | |
#endregion | |
/// <summary> | |
/// Class used to store definition information on the WCF Service | |
/// </summary> | |
internal class ServiceLocator | |
{ | |
#region Constants and Fields | |
public string AssemblyName; | |
[NonSerialized] | |
public Type Interface; | |
public string InterfaceName; | |
public int MaxItemsInObjectGraph; | |
public int MaxReaderArrayLength; | |
public int MaxReaderDepth; | |
public int MaxReceivedMessageSize; | |
public int MaxStringContentLength; | |
public string URL; | |
#endregion | |
#region Public Methods | |
/// <summary> | |
/// Function called by the injector factory to create an instance of the resolved interface. This function returns the actual | |
/// ChannelFactory>T< WCF proxy."/> | |
/// </summary> | |
/// <param name="container">Unity container to use in resolving the interface</param> | |
/// <returns>WCF Proxy</returns> | |
public object CreateService(IUnityContainer container) | |
{ | |
object ret; | |
//Log.Debug("Creating Service"); | |
//Build Endpoint | |
//create channel | |
EndpointAddress ep = new EndpointAddress(this.URL); | |
//TODO: Hard coded NetTCP binding, change this as appropriote for your environment. | |
NetTcpBinding binding = new NetTcpBinding { Security = { Mode = SecurityMode.None } }; | |
if (this.MaxReceivedMessageSize > 0) | |
{ | |
binding.MaxReceivedMessageSize = this.MaxReceivedMessageSize; | |
} | |
if (this.MaxReaderArrayLength > 0) | |
{ | |
binding.ReaderQuotas.MaxArrayLength = this.MaxReaderArrayLength; | |
} | |
if (this.MaxReaderDepth > 0) | |
{ | |
binding.ReaderQuotas.MaxDepth = this.MaxReaderDepth; | |
} | |
if (this.MaxStringContentLength > 0) | |
{ | |
binding.ReaderQuotas.MaxStringContentLength = this.MaxStringContentLength; | |
} | |
var channelFactoryType = typeof(ChannelFactory<>); | |
channelFactoryType = channelFactoryType.MakeGenericType(this.Interface); | |
//Log.Debug(" for interface: " + this.InterfaceName + ":" + this.Interface); | |
ChannelFactory factory = (ChannelFactory)Activator.CreateInstance(channelFactoryType, binding, ep); | |
var createchannel = factory.GetType().GetMethod("CreateChannel", new Type[0]); | |
ret = createchannel.Invoke(factory, null); | |
this.AddBehavior(factory); | |
//Log.Debug("Finished Creating Service"); | |
return ret; | |
} | |
/// <summary> | |
/// Function to find the assembly needed to create a type of the instance. | |
/// </summary> | |
public void FindInterfaceType() | |
{ | |
Assembly interfaceAssembly = Assembly.Load(this.AssemblyName); | |
this.Interface = interfaceAssembly.GetType(this.InterfaceName); | |
} | |
#endregion | |
#region Methods | |
/// <summary> | |
/// Add Logging message inspector to faciliate End-to-End logging | |
/// </summary> | |
/// <param name="factory"> | |
/// The factory. | |
/// </param> | |
private void AddBehavior(ChannelFactory factory) | |
{ | |
if (factory != null) | |
{ | |
if (this.MaxItemsInObjectGraph > 0) | |
{ | |
foreach (OperationDescription op in factory.Endpoint.Contract.Operations) | |
{ | |
DataContractSerializerOperationBehavior dataContractBehavior = | |
op.Behaviors.Find<DataContractSerializerOperationBehavior>(); | |
if (dataContractBehavior != null) | |
{ | |
dataContractBehavior.MaxItemsInObjectGraph = this.MaxItemsInObjectGraph; | |
} | |
} | |
} | |
} | |
} | |
#endregion | |
} | |
} | |
} |
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
namespace WCFDIProxy | |
{ | |
using System; | |
using System.ServiceModel; | |
public class ServiceProxy<T> : IDisposable where T : class, IDisposable | |
{ | |
public ServiceProxy(T proxy) | |
{ | |
this.Proxy = proxy; | |
} | |
public T Proxy { get; private set; } | |
#region IDisposable Members | |
public void Dispose() | |
{ | |
IClientChannel p = this.Proxy as IClientChannel; | |
if (p != null) | |
{ | |
if (p.State == CommunicationState.Faulted) | |
{ | |
p.Abort(); | |
} | |
else | |
{ | |
try | |
{ | |
//No reason to call dispose across a service boundry as we're disposing of the local version | |
//this.Proxy.Dispose(); | |
p.Close(); | |
} | |
catch (Exception ex) | |
{ | |
//Log.Error("Error calling dispose on the service:", ex); | |
p.Abort(); | |
} | |
} | |
} | |
else | |
{ | |
//Local version of proxy interface, dispose | |
if (this.Proxy != null) | |
{ | |
this.Proxy.Dispose(); | |
} | |
} | |
} | |
#endregion | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment