Sizlere bugun Dynamics CRM icerisindeki Plug-in Mimarisinden
soz etmek isitiyorum. Plug-in’ler IPlugin arayuzunden turetilmis kod
parcaciklaridir ve CRM’in icerisinde belli bir sira icerisinde calisirlar.
Kabaca tariff edersek bunlar birer .dll dosyalaridir ve CRM’e bu dosyaya ne
zaman bakmasi gerektigini biz soyleriz. Plug-in’ler olay bazli olarak
calisirlar. Yani herhangi bir kayit olusturuldugunda, guncellendiginde,
silindiginde vb.. olaylar oldukca biz ilgili ayari yapmissak calisirlar.
Plug-in’lerin en güzel yani pre ve post olarak calismaya
ayarlanabilmeleridir. Plug-in’ler olay bazli calisirlar demiştim iste bu olay
olmadan önceki kaydin son hali üzerinden ve olay olduktan sonraki hali
üzerinden işlem yapmaniza olanak sağlarlar.
Plug-in’lerin calismasi icin Microsoft.Xrm.Sdk.dll ve
Microsoft.Crm.Sdk.Proxy.dll dosyalarinin referanslara eklenmis olmasi
gerekmektedir. Tam yeri gelmisken bahsedeyim eger siz ucuncu parti bir .dll
kullaniyorsaniz (yani kendi yazdiginiz siniflarin oldugu ya da diger uygulamalardan
aldiginiz) bu .dll’lerin ilgili serverin assembly klasöründe olduğundan emin
olun yoksa plug-in calismayabilir.
public class MyPlugin: IPlugin
{
public void
Execute(IServiceProvider serviceProvider)
{}
}
Detaya inecek olursak IPlugin arayuzunden turerilmis bir
sinif içerisinde Execute metodu yer almalidir. Bu metod parametre olarak
IServiceProvider arayuzunden türetilmiş bir bilgi yiginini içerir. Yani CRM kod
içerisinde yapacagimiz işlemlerde bize CRM içerisinde olan olaylardan bize
bilgi tasir ki biz de bu bilgileri kodun içerisinde kullanalim. Ne gibi veriler
içinde tasimakta derseniz cok fazla detay verebilirim mesela su anda hangi
kullanicinin işlem yaptigi, tasidigi nesnenin turunu, eger pre-plugin ise
değerlerin değişmeden önceki halini vb… bir cok veri içermekte.
Simdi sirasiyla gelen veri yiginlarini inceleyelim.
Plug-in Execution Context
Calisma zamaninda oluşan veriler bu yapi içerisinde yer
almaktadır. Bunlara kodun calisma hiyerarşisi ve entity bilgileri de dahildir.
IPluginExecutionContext context = (IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
Bir olay olduğunda kayit edilmiş bir plug-in’e bu veriler
aktarılır aslinda o anda calisan butun plug-in’lere bu veriler aktarılır ama
execution pipeline denen sralamaya uyarak aktarılır once pre sonra post
pluginlere veri aktarılır. Hatta siz pre-plugin ile bir veriyi değiştirirseniz
post-plugin’e o veri aktarılır.
Tabii burada yeri gelmişken bahsedeyim burada sozu edilen
kodlarin sonsuz döngüye girmemeleri için sistem içerisinde Depth denen bir
anahtar yer almaktadır. Varsayilanda bu bir plugin’i arda arda 8 kere
calistirir ve durdurur. Boylece sistemin bir kod yanlisigi ile çökmesi
engellenmiştir. Bu değer değiştirebilir bir değerdir.
Sistemin calismasi da aslinda su mantiga dayanmakta;

Yani Event Execution Pipeline’a bir mesaj girdiginde
Pre-Event -> Platform Islemleri (Yani CRM’in kendi ic isleyisi) ->
Post-Event seklinde islenmekte. Bu dongu senkron ve asenkron yapilar için böyle
ilerlemekte.
Organization Servise Erisme
CRM içerisinde işlem yapabilmek her zaman bir servis
nesnesine ihtiyaç duymaktayız. Iste kullanicinin hareketi neticesinde acilmiş
bu servisi bize kullanmamiz için geçirmekte serviceProvider nesnesi.
IOrganizationServiceFactory serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service =
serviceFactory.CreateOrganizationService(context.UserId);
Notification Servise Erisme
Senkron olarak işaretlenmiş plug-in’ler Microsoft Azure
Service Bus’a veri mesaj gondebilirler. IServiceEndpointNotificationService
turunden olan bu bilgi Azure Service Bus’a gönderilir. Bu sayede Azure Service
Bus içerisinde endpoint oluşturulmuş ve endpoint’i dinleyen 3. Parti bir servis
ile iletişime geçebilmektedir.
Input ve Output Parametreleri
InputParameters nesnesi su anda yapilan hareketin yani su
anda tetiklenmiş olayin bilgisini ve su anda üzerinde işlem görülen entity’nin
bilgisini içerir. Bu bilgiye erişmek için “Target” nesnesine bakmamiz
gerekmektedir ve bu nesneyi alip Entity class’ina çevirebiliriz. Input
nesneleri Request message yapisindadir.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from
the input parameters.
Entity entity =
(Entity)context.InputParameters["Target"];
}
Fakat unutmaniz gereken bir nokta var her mesaj Entity
nesnesini içermeyebilir. Ornegin DeleteRequest; Entity değil EntityReference
dondurur.
if (context.InputParameters.Contains("Target") && context.InputParameters["Target"]
is EntityReference)
{
// Obtain the target entity from
the input parameters.
EntityReference entity =
(EntityReference)context.InputParameters["Target"];
}
Benzer sekilde OutputParameters da Response message içerir.
Ama sunu unutmayin ki senkron post-event ve asenkron plug-in’ler
OutputParameters turunden nesneler içerirler.
Pre ve Post Entity Imajlari
Bu konuyu okurken sakin Ingilizce Images kelimesinin resim
anlamiyla karistirmayin buradaki anlami verinin
o anki goruntusu seklinde ifade etmek daha doğru olur. Aslinda tam
Ingilizce tabiriyle snapshot. PreEntityImages ve PostEntityImages verileri
sistem tarafından size gönderilir ama siz ozellikle beklediğiniz alanlari
plug-in’in kayit işlemi sirasinda sisteme soyleyebilrsiniz.
Burada tabii ki bir mantik çerçevesi olduğunu da unutmayin
Create aninda bir nesnenin preImage’i olamayacagi gibi Delete işleminden sonra
da bir postImage beklemeyin.
Simdi bu bilgileri verdikten sonra butun bunlari
birleştirerek bir plug-in temel goruntusune bakalim.
Aciklamalar kodun içinde.
using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;
public class MyPlugin: IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
//
Sandbox içerisinde calisan plug-in’ler TracingService’den yararlanabilirler.
ITracingService tracingService =
(ITracingService)serviceProvider.GetService(typeof(ITracingService));
//Context’i
elde ediyoruz.
IPluginExecutionContext context =
(IPluginExecutionContext)
serviceProvider.GetService(typeof(IPluginExecutionContext));
//
InputParameters’dan gelen verileri aliyoruz
if (context.InputParameters.Contains("Target")
&&
context.InputParameters["Target"] is Entity)
{
//
Target ile entity’e erisiyoruz.
Entity entity =
(Entity)context.InputParameters["Target"];
//
Beklediginiz entity geldi mi diye kontrol ediyoruz.
if (entity.LogicalName != "account")
return;
// CRM
Servisi elde ediyoruz
IOrganizationServiceFactory
serviceFactory =
(IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service =
serviceFactory.CreateOrganizationService(context.UserId);
try
{
/
Iste buradan sonrasi size kalmis istediğiniz kodu yazabilirsiniz.
}
catch (FaultException<OrganizationServiceFault> ex)
{
throw new InvalidPluginExecutionException("An error occurred in MyPlug-in.", ex);
}
catch (Exception ex)
{
tracingService.Trace("MyPlugin: {0}",
ex.ToString());
throw;
}
}
}
}