Makale Özeti

Önceki makalelerimde unity'nin genel kullanımı, dependency injection kavramı ve singleton pattern'inin unity de nasıl uygulanabileceğinden bahsetmiştik. Şimdi ise unity ile bir interceptor'u nasıl yazabileceğimize bakalım. Birçok IOC Container'da bulunan interception özelliği sayesinde uygulama geliştiricile ristedikleri bir metod çağrılmadan önce veya sonrasında gerekli işlemleri kolaylıkla yapabilmektedirler. Seperation of Concerns prensibine çok uygun olan bu yapı sayesinde iş metodlarınızın içinde hata yakalama fonksiyonlarını tek tek yazmanıza gerek yoktur. Genellikle loglama, security checki policy injection gibi fonksiyonaliteler her sınıfta her metodda tek tek implement etmek yerine interceptor'lar ile yapılmaktadır.

Makale

Merhabalar,

Önceki makalelerimde unity'nin genel kullanımı, dependency injection kavramı ve singleton pattern'inin unity de nasıl uygulanabileceğinden bahsetmiştik. Şimdi ise unity ile bir interceptor'u nasıl yazabileceğimize bakalım.

Birçok IOC Container'da bulunan interception özelliği sayesinde uygulama geliştiricile ristedikleri bir metod çağrılmadan önce veya sonrasında gerekli işlemleri kolaylıkla yapabilmektedirler. Seperation of Concerns prensibine çok uygun olan bu yapı sayesinde iş metodlarınızın içinde hata yakalama fonksiyonlarını tek tek yazmanıza gerek yoktur. Genellikle loglama, security checki policy injection gibi fonksiyonaliteler her sınıfta her metodda tek tek implement etmek yerine interceptor'lar ile yapılmaktadır.

Şimdi isterseniz bunu nasıl yapabileceğimizi inceleyelim. Öncelikle uygulamamıza interceptor ile ilgili referansları ui projemize eklememiz gerekmektedir.

Sonrasınsa ise InterceptorBehavior'u yani interceptor'umuzun nasıl bir davranış sergileyeceğini kodlamamız gerekiyor. Örnek uygulamamızda Servis katmanına yapılan çağrılar üzerinde işlem yapacağımız için Service projesine yeni bir class oluşturuyoruz ve adını InterceptorBehavior koyuyoruz. Bu sınıfımızı ise IInterceptionBehavior'dan implement ediyoruz. Burada implement etmemiz gereken 2 metod ve 1 property var. Bunlar

GetRequiredInterfaces() : Bu metod bize bu behavior'un intercept edeceği tipleri döndürecektir.

Invoke() : Bu metodda esas çağrılmak istenen fonksiyonu çağıracak ve dönüş parametrelerini alacağız.

WillExecute : Bu interceptor'un çalışıp çalışmayacağının belirlendiği property olacak.

En basit şekilde interceptor'umuzu aşağıdaki gibi oluşturalım. Metodların içerilerini sonradan daha detalı dolduracağız.

namespace UI
{
    public class InterceptorBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }
 
        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            IMethodReturn methodReturn = getNext().Invoke(input, getNext);
 
            if (methodReturn.Exception == null)
            {
                //metod basariyla calistirildi
            }
            else
            {
             //metodun calismasi sirasinda hata oldu.
            }
            return methodReturn;
        }
 
        public bool WillExecute
        {
            get { return true; }
        }
    }
}

Kodu inceleyecek olarak GetRequiredInterface metodunda EmptyTypes döndüğü için interceptor'umuz tüm tipler için çalışacak, WillExecute true döndürdüğü için interceptor devreye girecektir. Invoke metodunu inceleyecek olursak ilk satırda esas çağrılan metodu invoke ediyoruz. Sonrasında ise bu metodun çalışması sırasında herhangi bir hata olduysa bu hatayı görüntülüyoruz.

Peki bu interceptor'u çalıştırmak için servis metodunu çağırdığımız yerde ne yapmamız gerek. Cevap hiçbirşey yapmamız gerekmiyor. Sadece config'de bazı yeni tanımlamalar yapacağız. Config dosyamızın nasıl olacağını aşağıda inceleyelim.

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="unity" type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,Microsoft.Practices.Unity.Configuration"/>
  </configSections>
  <unity>
    <typeAliases>
      <typeAlias alias="INotificationService" type="ContractService.INotificationService,ContractService"/>
      <typeAlias alias="NotificationService" type="Service.NotificationService,Service"/>
      <typeAlias alias="singleton" type="Microsoft.Practices.Unity.ContainerControlledLifetimeManager, Microsoft.Practices.Unity" />
      <typeAlias alias="transient" type="Microsoft.Practices.Unity.TransientLifetimeManager, Microsoft.Practices.Unity"/>
 
    </typeAliases>
    <!-- Interception extension ile unity mizi extend ediyoruz-->
    <sectionExtension type="Microsoft.Practices.Unity.InterceptionExtension.Configuration.InterceptionConfigurationExtension, Microsoft.Practices.Unity.Interception.Configuration"/>
    <containers>
     
      <container>
        <!--kullanacagimiz extension in tipini belirliyoruz.-->
        <extension type="Interception"/>
        <register type="UI.InterceptorBehavior,UI">
        </register>
        <types>
          <type type="INotificationService" mapTo="NotificationService">
            <!-- Bu tip icin interceptor ayarlari-->
            <!-- interceptor'umuzun tipi interface interceptor yani interface e yapilan cagrilari intercept edecek-->
            <interceptor type="InterfaceInterceptor"/>
            <!--Interceptorumuzun intercept ettigi cagrilar icin bu behavior kullanilacak -->
            <interceptionBehavior type="UI.InterceptorBehavior,UI"/>
            <!--lifetime i transient olarak tanimliyoruz-->
            <lifetime type="singleton"></lifetime>
            <property name="UserData" >
              <dependency />
            </property>      
          </type>
          <type type="ContractData.IUserData,ContractData" mapTo="Data.UserData,Data">
            <lifetime type="singleton"></lifetime>
          </type>
        </types>
      </container>
    </containers>
  </unity>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>

 

 Tüm yapmamız gereken bu config tanımlamasını yapmak. Artık servis üzerine yaptığımız çağrılar Behavior class'ımızın invoke metoduna girecektir. Bunu bir breakpoint koyarak test edebiliriz. Şimdi isterseniz bu kısımda yapılabilecekler hakkında ufak bir demo ile bu makalemizi bitirelim.

namespace UI
{
    public class InterceptorBehavior : IInterceptionBehavior
    {
        public IEnumerable<Type> GetRequiredInterfaces()
        {
            return Type.EmptyTypes;
        }
 
        public IMethodReturn Invoke(IMethodInvocation input, GetNextInterceptionBehaviorDelegate getNext)
        {
            Console.WriteLine(input.MethodBase.ToString() + " cagrildi");
           
            IMethodReturn methodReturn = getNext().Invoke(input, getNext);
            int parameterCount = input.Inputs.Count;
            for (int i = 0; i < parameterCount; i++)
            {
                Console.WriteLine("Parametre :" + input.Arguments.GetParameterInfo(i).Name + ", Deger:" + input.Inputs[i].ToString());
            }
            if (methodReturn.Exception == null)
            {
                string retval = "";
                if (methodReturn.ReturnValue != null)
                {
                    retval = methodReturn.ReturnValue.ToString();
                }
                Console.WriteLine(input.MethodBase.ToString() + " basariyla calisti,Donus degeri:" +  retval);
            }
            else
            {
                Console.WriteLine(input.MethodBase.ToString() + " hata verdi Hata:" + methodReturn.Exception.ToString());
            }
            return methodReturn;
        }
 
        public bool WillExecute
        {
            get { return true; }
        }
    }
}

Şimdi servis metodlarına çağrı yaptığımızda konsol çıktımız aşağıdaki gibi olacaktır.

Örneğini de yaptığımız gibi bazı işlemleri interceptor ile yapmak çok kolay olacaktır ve kodlama maliyetlerini ciddi azaltacaktır.

Ornek Kodlar