8 Haziran 2008 Pazar

WCF Unity

Smart client software factory – web client software factory gibi bir çok popüler uygulama mimarisinin kendi object builder nesnesi vardır. Fakat wcf için böyle bir uygulama mimarisi bulunmamaktadır. Buda bir eskikliktir.

Bu projede WCF için unity container nesnesinin nasıl kullanılacağını gösteriyorum. Unity ile policy injection application bloğu bereber kullandım.Böylelikle WCF servisleri için hem dependency injection hemde policy injection yapabilme imkanı doğdu. Tip tanımlarının ayrı config dosyalarında olduğunu varsayarak hareket ettim. Böylelikle hem config dosyasındakarmaşadan kaçındım hemde projeyi uygulama bağımsız olarak kullanma imkanı oluştu.

WCF için unity containerın kullanabilecek en iyi yer WCF servisin life time kontrolünü sağlayan IInstanseProvider arayüzüdür. Öncelikle dependency injection sağlayacak olan yeni bir IınstanceProvider yazdım.

[cs]

/// 
/// init dependency container
/// 
/// Dependency config file /// Dependency conainer name private void InitContainer(string dependencyFile, string containerName) {  string currentContainerKey = GetDependencyKey(dependencyFile, containerName);  if (!containers.ContainsKey(currentContainerKey)) {   lock (syncRoot) {    if (!containers.ContainsKey(currentContainerKey)) {     containers[currentContainerKey] = currentContainer = new UnityContainer();     ExeConfigurationFileMap map = new ExeConfigurationFileMap();     map.ExeConfigFilename = dependencyFile;     System.Configuration.Configuration config      = ConfigurationManager.OpenMappedExeConfiguration(       map, ConfigurationUserLevel.None);      UnityConfigurationSection section      = (UnityConfigurationSection)config.GetSection("unity");     section.Containers[containerName].Configure(currentContainer);     currentContainer.AddNewExtension();    }   }  } else {   currentContainer = containers[currentContainerKey];  } }

DependencyInjectionInstanceProvider iki tane parametreye ihtiyaç duymaktadır: dependencyFile tip tanımlamalarımızın bulunduğu config dosyasıdır. containerName config dosyası içinde tanımlı container adıdır. Her bir container sadece bir kez oluşturul ve saklanır. Oluşturulan container nesnelerine son olarak PolicyInjectionExtansion ile Policy injection destekler hale getirilir. PolicyInjectionExtansion sadece EnterpriseLibrary.PolicyInjection.ObjectBuilder altında ki strategy ve policy sınıflarını register eder. Son olarak Dependency injection instance provider'ı servislere uygulayacak yeni bir servis behavior yazmaya.

[cs]

public class DependencyInjectionServiceBehavior : Attribute, IServiceBehavior {
 public void ApplyDispatchBehavior(ServiceDescription serviceDescription, 
  ServiceHostBase serviceHostBase) 
 {
  foreach (ChannelDispatcherBase cdb in serviceHostBase.ChannelDispatchers) {
   ChannelDispatcher cd = cdb as ChannelDispatcher;
   if (cd != null) {
    foreach (EndpointDispatcher ed in cd.Endpoints) {
     ed.DispatchRuntime.InstanceProvider =
      new DependencyInjectionInstanceProvider(
       serviceDescription.ServiceType, 
       configFile, 
       containerName);
   }
  }
 }
}

Evet artık WCF ile unity dependency container bir arada kullanılabilir.

[cs]

static void Main(string[] args) {
 ServiceHost hostA = null, hostB = null;
  try {
   hostA = new ServiceHost(typeof(ServiceA));
   hostB = new ServiceHost(typeof(ServiceB));
   hostA.Open();
   hostB.Open();
 

[ServiceBehavior]
public class ServiceA : IServiceAContract {
 public ServiceA() { }

 private IServiceBContract serviceB;
 private IServiceC serviceC;

 [InjectionConstructor]
 public ServiceA(IServiceBContract serviceB) {
  Console.WriteLine("Build up Service A");
  this.serviceB = serviceB;
  Console.WriteLine("Service A constructor calling to serviceB.OperationD");
  this.serviceB.OperationD("test1", "test2");
 }

 [Dependency]
 public IServiceC ServiceC {
  set {
   serviceC = value;
   Console.WriteLine("IServiceC injected to ServiceA parameter ");
  }
 }


public class ServiceB : IServiceBContract {

 public ServiceB() { }
 private IServiceC serviceC;

 [InjectionConstructor]
 public ServiceB(IServiceC serviceC) {
  Console.WriteLine("Build up Service B ");
  this.serviceC = serviceC;
  Console.WriteLine("Service B constructor calling to serviceC.OperationG");
  this.serviceC.OperationG("test");
  this.serviceC.OperationG("test");
 }