dynamics crm 2015 kodlama mimarisi v1.0 · 2020-01-28 · dynamics crm 2015 kodlama mimarisi v1.0 -...

67
Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

Upload: others

Post on 29-Mar-2020

13 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

Page 2: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

1 | P a g e

Icerik Yazar Hakkinda ........................................................................................................................................ 3

E-Kitap Hakkinda ..................................................................................................................................... 3

Dynamics CRM Servis Mimarisi ............................................................................................................... 4

Device ID bilgisini vermek istemezsek ................................................................................................. 4

Device ID bilgisini vermek istersek ...................................................................................................... 5

Ek Bilgi ................................................................................................................................................. 5

Organization Servis .................................................................................................................................. 5

Execute Metodu .................................................................................................................................. 7

Early ve Late Binding Arasındaki Farklar.................................................................................................. 8

CrmSvcUtil.exe ile Early-Bound Sınıflar Oluşturmak ......................................................................... 11

Veri Turleri Hakkinda ............................................................................................................................. 14

OptionSetValue ................................................................................................................................. 15

EntityReference ................................................................................................................................. 15

Null Değer Atama .............................................................................................................................. 15

Veri Sorgulama ...................................................................................................................................... 15

FetchXML ............................................................................................................................................... 17

Sorguyu Hazırlama ............................................................................................................................. 17

Sorguyu Çalıştırma ............................................................................................................................. 20

Sorgu Sonucu ..................................................................................................................................... 22

İleri Seviye Sorgular ........................................................................................................................... 22

FetchXML ile Aggregate(Toplama Sorguları) İşlemleri .......................................................................... 30

Create/Update/Delete Metodları.......................................................................................................... 33

Dynamics CRM 2015 Plug-in Mimarisi................................................................................................... 39

Plug-in Execution Context ................................................................................................................. 40

Organization Servise Erisme .............................................................................................................. 41

Notification Servise Erisme................................................................................................................ 41

Input ve Output Parametreleri .......................................................................................................... 41

Pre ve Post Entity Imajlari ................................................................................................................. 42

Plug-in’ler Icerisindeki Hatalari Yakalamak ........................................................................................... 43

Plug-in Yapici Metodlari ........................................................................................................................ 45

Hadi Plug-in Yazalim .............................................................................................................................. 47

Veritabanina gitmeden kayitlari değiştirmek .................................................................................... 47

Update aninda update edilmemiş değerlere ulaşmak ...................................................................... 49

Uzerinde calistigim nesnenin id’si nerede? ....................................................................................... 52

Plug-in’ler arasinda bilgi paylasimi .................................................................................................... 52

Page 3: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

2 | P a g e

Plug-in Registration Tool’u Kullanmak .................................................................................................. 54

Plug-in’i Debug Etmek ........................................................................................................................... 60

Servis’lere Attach olarak Debug Etme ............................................................................................... 60

Plug-in Profiller’i kullanarak Debug etme .......................................................................................... 62

Page 4: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

3 | P a g e

Yazar Hakkinda

Yaklasik 15 yildir profesyonel olarak yazilim

geliştirmekteyim. Bundan yaklasik 10 yil once

Microsft Dynamics CRM 1.2 versiyonu ile

tanistiktan sonra CRM yazilim danismani olarak

yillardir Microsoft Dynamics CRM projeleri

içerisinde cesitli pozisyonlarda görev aldim.

Turkiye’de CRM alaninda danismanlik yapan

Omerd Business Solutions’in kurucu ortagi

olarak yillardir Yazilim Departman Mudur’u

unvanıyla bu sirkette görev yapmaktayım.

2 senedir de bu sirketin yurtdisi uzantisi olarak

kurulan Mawens Business Solution’da Genel

Mudur’u sifatiyla Londra’da yasamaktayim ve

CRM projeleri geliştirmeye burada devam

etmekteyim.

Bugune kadar 100’den fazla firmaya 150’den fazla CRM projesi geliştirdim ve bu alanda yaptigim

calismalardan dolayi Microsoft’tan 5 kere Dynamics CRM MVP odulunu ve unvanini aldim.

Bilkom-Apple tarafından da Dijital Yasam Kocu unvanini almis bulunmaktayım.

Turkiye’de Edirne’den Elazig’a kadar ve yurtdisinda Londra’da birçok universite, kurum ve etkinlikte

konusmaci/egitmen olarak bulundum.

Bircok sitede de editör ve yazar olarak yazilarim yayinlanmaktadir.

Bana ulaşmak icin asagidaki kişisel bloğum olan www.cub-e.net ‘i takip edebilir ve [email protected]

adresine mail atabilirsiniz.

E-Kitap Hakkinda Bu kitap Dynamics CRM alaninda yazilim yapan/yapmak isteyen herkese aciktir. Kodlar c# dilinde

Visual Studio’da yazilmis ve bunlar uzerinden anlatilmaktadir. Bu kitaptaki ornekleri yapabilmeniz icin

1. CRM 2015

2. CRM 2015 SDK

3. Visual Studio 2012-2013

Araclarina ihtiyaciniz bulunmaktadir.

Bu e-kitap www.cub-e.net ‘teki yazilarin biraraya toplanmis halidir.

Ilereyen zamanlarda diger yazilarimi da 2015 versiyonuna guncelleyerek daha genis bir e-kitap

olusturmayi amaclamaktayim.

Umarim hepinize faydali olur.

Page 5: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

4 | P a g e

Dynamics CRM Servis Mimarisi

Dynamics CRM üzerinde uygulama geliştirebileceğiniz çok güçlü bir mimari ile gelmektedir.

Bu mimarinin temel yapı taşı ise WCF servisleridir. Bu yazımda sizlere CRM'in temel web

servisleri olan Discovery ve Organization Servislerinin yapısını ve ne işe yaradıklarını

anlatacağım.

CRM için kod geliştirirken her ne kadar sdk'nın içinden çıkan dll'leri kullansak da bu dll'ler

vasıtasıyla ilk önce servis bağlantısı oluşturmamız gerekmektedir. Yani verilere ulaşmak ve

veri yazmak için WCF servislerini kullanmak zorundayız. Bu servislerle daha hızlı ve güvenli

bir şekilde CRM platformuna entegre olmamızı sağlamaktadır.

WCF standartlaşmış bir teknoloji olduğu için biz yazılım geliştiricilere yeni özellikler

sunmakta ve sürekli kendi içerisinde gelişmektedir. Dynamics CRM yapısında entity ve

attribute katmanlı bir mimari bulunmaktadır. Yani biz CRM'in Business Logic katmanına

müdahele edip yazılımlarımızı onunla entegre hale getirmekteyiz. Temel olarak nesne

katmanı Entity isimli nesneden türemiştir. late-bound türlerde bu nesneyi sıklıkla

kullanmaktayız. Early-bound olarak program geliştirme metodolojisini tercih edersek Entity

class'ı ile işimiz olmamaktadır ama arka planda bütün nesnelerin bu class'dan türediği

unutulmamalıdır. Bu konuya aşağıda bir örnekle tekrar değineceğim. CRM servislerine

OrganizationServiceProxy ve DiscoveryServiceProxy sınıflarıyla bağlanmaktayız. Aşağıdaki

kod bize bunu göstermektedir;

using (OrganizationServiceProxy _serviceProxy = new OrganizationServiceProxy(organizationUri, homeRealmUri, userCredentials, deviceCredentials)) ;

Discovery Servis

Dynamics CRM 4.0 versiyonundan itibaren multi-tenant bir mimaridedir. Yani tek bir

uygulama birden fazla organizasyonu içerisinde barındırmaktadır. Yazılımcı olarak birden

fazla organizasyon arasında geçiş yapmamız gerekiyorsa sistemde hangi organizyonlar

olduğunu sorgulama işini Discovery servis ile yapmamız gerekmektedir. Bu servis yazma

okuma işlemlerinin yapılacağı ana servise bağlanmamıza yardımcı olacak ve

organizasyonların bilgisini bize döndürecektir. Aşağıdaki kod bize bu servise nasıl

bağlanacağımızı ve organizasyonların bilgisine nasıl ulaşacağımızı göstermektedir.

Device ID bilgisini vermek istemezsek

Uri dInfo = new Uri("http://192.168.5.102/XRMServices/2011/Discovery.svc"); ClientCredentials clientcred = new ClientCredentials(); DiscoveryServiceProxy dsp = new DiscoveryServiceProxy(dInfo, null, clientcred, null); dsp.Authenticate(); RetrieveOrganizationsRequest rosreq = new RetrieveOrganizationsRequest(); RetrieveOrganizationsResponse r = (RetrieveOrganizationsResponse)dsp.Execute(rosreq); foreach (OrganizationDetail o in r.Details) { Console.WriteLine("Organizasyon Adı : " + o.FriendlyName); } Console.ReadLine();

Page 6: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

5 | P a g e

Device ID bilgisini vermek istersek

Normalde dokümantasyonlarda bu sekilde bir ayrim göremezsiniz. Ben bunu deneyimlerime

dayanarak yapıyorum. Aslinda yukarıdaki kod da Online Organizasyon’a baglanir ama

DiscoveryService’in varsayilan yapici metoduna 4. Parametreyi gönderirseniz yani

DeviceCredential null olmazsa calisir.Sorun ise DeviceCredential’i oluşturmak icin CRM

SDK\SampleCode\CS\HelperCode klasöründeki DeviceIdManager.cs kodunu kendi

kodunuza implemente etmeniz gerekmekte.

Ek Bilgi

Bu kodla discovery servise bağlandıktan sonra ClientCredentials'ı kullanarak hali hazırda

oturum açmış kullancının bilgisini sisteme göndermekteyiz. Ama her zaman bunu kullanmak

istemeyebiliriz yani başka bir kullanıcı adı ve şifre ile sisteme girmek istediğimizde

ClientCredentials'a kullanıcı adı, şifre bilgilerini verebiliriz.

clientcred.Windows.ClientCredential = new System.Net.NetworkCredential("kullanici adi", "sifre", "domain");

Yukarıdaki kodun çalışabilmesi için

System.ServiceModel.Description,System.Runtime.Seriliazation, Microsoft.Crm.Sdk.Proxy

ve Microsoft.Xrm.Sdk dll'lerinin referanslara eklenmiş olduğundan emin olun. Ayrıca

uygulamayı .Net Framework 4.5.2'de derlemek gerekiyor.

Organization Servis

Dynamics CRM 2015'in ana web servisi Organization Servis'tir. Bu servis içerisinde entity

instance'ları üzerinde işlem yapabileceğimiz 6 metod ve execute metodu bulunmaktadır. CRM

Servis sınıfını oluşturabilmek için Organization Service Proxy'nin bir instance'ını

Page 7: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

6 | P a g e

oluşturmamız gerekmekte. Daha sonrasında ise Organization Servis sınıfını bunu göre

ayarlayacağız.

Uri organizationUri = new Uri("https:// !organizasyon crm url! /XRMServices/2011/Organization.svc");

ClientCredentials clientcred = new ClientCredentials(); clientcred.UserName.UserName = " kulllanici adi "; cientcred.UserName.Password = " sifre "; OrganizationServiceProxy _serviceproxy = new OrganizationServiceProxy(organizationUri, null, clientcred, null);

IOrganizationService _service = (IOrganizationService)_serviceproxy;Yukarıdaki kodun

çalışabilmesi için System.ServiceModel.Description, Microsoft.Xrm.Sdk ve

Microsoft.Xrm.Sdk.Proxy dll'lerinin referanslara eklenmiş olduğundan emin olun. Ayrıca

uygulamayı .Net Framework 4.5.2'de derlemek gerekiyor. Oluşturduğumuz bu servisi daha

sonra programımızın ilerleyen bölümlerinde çağırıp işlemler yapacağız.

Tabi burada belirtilmesi gereken bir konu da işlem yapmak istediğiniz nesnenin üzerinde

yetkilerinizin olmasıdır. Bir kayıt oluşturabilmek için oluşturma yetkisine sahip olmanız

gerekmektedir. Sadece okuma yetkisiyle bir kayıt oluşturamazsınız. Bir sonraki yazımda

sizlere entity mimarisi ve yazma okuma işlemlerini anlatacağım.

Yukaridaki kod orneginde biz bir kullanici adi ve sifre ekledik. Eger her kullanicinin kendi

kullanici haklariyla sistem üzerinde işlem yapmasini istiyorsaniz yukarıdaki kodda kullanici

adi ve sifre kodunu silip asagidaki kodu eklemeniz gerekir.

ClientCredentials clientcred = new ClientCredentials();

Boylece sistemde oturum acmis kullanici bilgileri ile devam etmis olacagiz.

Bilmemiz gereken diğer bir konu da eger Early Bind veri tipi kullanacaksak servisi

oluştururken ek bir komut daha girmemiz gerekmektedir. Yani linq ile sorgulama ve

generated code üzerinde işlemler yapabilmek icin oluşturduğunuz servis nesnesine bu sekilde

işlem yapacaginizi belirtmeniz lazim iste bunun icin asagidaki satiri eklememiz gerekmekte.

_serviceproxy.EnableProxyTypes();

Bu arada CRM servisi olusturmanin yeni bir yöntemi daha bulunmakta. Bu da

CrmConnection nesnesini kullanmak. Bu nesneye erişebilmek icin Microsoft.Xrm.Client

dll’ini referans olarak eklemeniz gerekmekte.

CrmConnection crmConnection = CrmConnection.Parse("Url=https://! Crm organizasyon url !/XRMServices/2011/Organization.svc; Username= kullanici adi; Password= sifre");

OrganizationService service = new OrganizationService(crmConnection);

Boylece servis oluşturma işlemini 2 satirda da halledebilmekteyiz. Tabii bu bilgileri ben bu

sekilde kod içerisine koymus gibi oldum size gostemek icin ama projelerde tabii ki bunlari ya

app.config, web.config içerisine ya da belli bir lokasyonda tuttuğumuz xml dosyasi içerisinde

tutuyoruz ki bu bilgiler degistiginde sürekli kod degisikligi yapmak zorunda kalmayalım.

Page 8: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

7 | P a g e

Execute Metodu

CRM Servisi içerisindeki Execute Metodu Request ve Response yani Talep ve Yanit seklinde

calismaktadir. Sistem üzerinde yapacaginiz butun hareketleri bu sekilde yapabilirsiniz ki buna

ayri metodlari bulunan Create, Update, Delete bile dahildir.

Konu aslinda basit olduğundan çokça açıklanacak bir tarafi da yok gibi ama calisma yapisina

bakacak olursak siz bir talepte bulunursunuz o da size yanit verir diye kisaca özetleyebiliriz.

Execute metodunun alabileceği Request’lere makalenin sonunda yer vereceğim. Ama

oncelikle sunu da belirteyim ki Request nesnesi opsiyonel parametrelere de sahiptir. Bu

parametreler sunlardir.

Parameter Description Messages

SolutionUniqueName Islemin yapilacagi Cozumun Adi

AddPrivilegesRoleRequest

CreateRequest

DeleteRequest

MakeAvailableToOrganizationTemplateRequest

UpdateRequest

SuppressDuplicateDetection

Eslenen kayitlar bulunsun mu bulunmasin mi

CreateRequest

UpdateRequest

Kullanima dair ornek kod ise su sekilde;

Account target = new Account(); target.Name = "Fabrikam"; CreateRequest req = new CreateRequest(); req.Target = target; req["SuppressDuplicateDetection"] = true; req["SolutionUniqueName"] = "MySolutionName"; CreateResponse response = (CreateResponse)_service.Execute(req);

Eger isterseniz Execute Metodunu asenkron olarka da calistirabilirsiniz. Bu ekranda

donmalari ve kullanicilarin ekrandan işlem bitmeden cikmalarini önleyecektir. Bunun için

yapmaniz gereken ExecuteAsyncRequest mesajini geçmek olacaktır.

ExecuteMultipleRequest ile de toplu daha aktarimlarinda kullanabileceğiniz mesajdir.

Page 9: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

8 | P a g e

xRM Mesajlarinin tamamina bu adresten ulaşabilirsiniz : https://msdn.microsoft.com/en-

us/library/gg334698.aspx

CRM mesajlarina da bu adresten ulaşabilirsiniz : https://msdn.microsoft.com/en-us/library/gg309482.aspx

Early ve Late Binding Arasındaki Farklar Dynamics CRM 2011 ve sonrasinda CRM içerisinde programcılar kendilerine birden fazla

programlama biçimi seçebilirler. Dynamics CRM’de WSDL kullanarak early-bound tipleri ve

Dynamics Entity sınıflarını kullanarak da late-bound programlama yapabilirsiniz. Plug-in ve

Workflow yazabilmek için late-bound tipleri kullanmamız gerekmektedir.

Dynamics CRM 4.0’da entity sınıflarının duruşu aşağıdaki şekildeki gibiydi;

Şimdi ise Dynamics CRM 2011’de bu yapı şu şekilde değişti;

DynamicEntity sınıfı artık Entity sınıfı isimli bir sınıfla yer değiştirdi. Bunun anlamı ise build

time yani early bound tiplerle, runtime yani late bound tiplerin artık tek sınıftan türemesinin

gerçekleşmiş olduğudur.

Dynamics CRM’de artık WSDL’e direkt ulaşamıyoruz. Daha önceki makalemde de

anlattığım gibi 2 tane dll’i referans olarak eklemek ve servise bağlantı kurmak gerekmektedir.

Page 10: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

9 | P a g e

Late-Bound olarak isimlendiren mimaride siz Entity sınıfından bir nesne türetmeli ve bu

nesnenin attribute collection’da da değerlere yer vermelisiniz. Tabii burada değer alanlarının

crm içerisindeki logical name’lerini kesinlikle bilmeniz gerekmektedir.

Aşağıdaki örnek bize late-bindig yapısının nasıl işlediğini gösterecektir;

Entity lead = new Entity("lead"); lead.Attributes["subject"] = "Deneme Firmasi"; lead.Attributes["firstname"] = "Baris"; lead.Attributes["lastname"] = "KANLICA"; lead.Attributes["companyname"] = "Mawens Business Solutions"; lead.Attributes["numberofemployees"] = 20; Guid leadid = service.Create(lead);

Entity sınıfını kullanmaya başladığımız zaman late-binding’e giriş yapmış oluyoruz. Entity

türünden oluşturduğumuz nesneye biz Lead türünden bilgileri içine dolduracağız diyoruz.

Contact, Opportunity gibi CRM içerisindeki bütün nesneleri bu şekilde oluşturabiliriz.

Daha sonra ise alanların logical name’lerini vererek bunların değerleri veriyoruz. Burada .net

tabanlı türleri kullanabilmekteyiz. CRM 4.0’da CrmBoolean, CrmNumber gibi türlere

çeviriler yaparak nesnelerin içini doldururken artık buna ihtiyacımız bulunmamaktadır.

service isimli WCF tabanlı servisimizden türemiş nesnenin Create Metodunu kullanarak

nesnemizi CRM içerisinde bir kayıt olarak oluşturuyoruz.

Page 11: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

10 | P a g e

Early-Bound olarak isimlendirilen mimaride de ise CrmSvcUtil.exe aracını kullanarak bir

OrganizationServiceContext türetmelisiniz. Daha sonra ise bu aracın türettiği nesneleri

kullanabilir hale gelebilirsiniz. Tabii burada her bir nesnenin şema isimleriyle hareket

ettiğimiz unutulmamalıdır.

Aşağıdaki örnek bize early-binding yapısının nasıl işlediğini gösterecektir;

CrmDataContext orgContext = new CrmDataContext(ServiseBaglan()); var contact = new Contact() { FirstName = "Alan", LastName = "Smith" }; orgContext.AddObject(contact); orgContext.SaveChanges();

Burada ServiseBaglan() daha önceki makelemde belirttiğim gibi IOrganizationService

Interface’inden türemiş bir sınıfı teşkil etmektedir. Yani CRM’in WCF servisine hazır ve

açık bir bağlantıdır.

Contact ise CRM içerisinde kişiler entity’sidir, Account, Lead, Invoice,Quote gibi daha bir

çok entity bulunmaktadır.

Firstname ve Lastname ise kişinin adı ve soyadı için değerleri temsil etmektedir ve bu bilgi

OrganizationContext’ten gelmektedir. Bir sonraki yazında CrmDataContext isimli bu

OrganizationContext’in CrmSvcUtil.exe aracılığıyla nasıl oluşturulduğu göstereceğim.

Daha sonra ise bu doldurduğumuz contact nesnesini OrganizationContext’e teslim ediyoruz

ve işlem yapılması için SaveChanges() metodumuzu çağırıyoruz.

Page 12: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

11 | P a g e

Farklılıkları ise şu şekilde sıralayabiliriz;

Early-Bound Entity Sınıflarının en büyük avantajı compile time da bize bütün hataları

göstermesidir. Yani uygulamamızı yazarken ya da derlerken türler arası uyumsuzluk

ya da yanlış değer atama gibi bütün yanlışlıklarımızı gözler önüne sermektedir.

CrmSvcUtil bize tüm CRM mimarisini örneklerken bütün nesneleri ve onun ilişkilerini

de getirmektedir. Böylece nesne dönüşümleri ve tür güvenliği de sağlanmış

olmaktadır.

Visual Studio içerisinde inteli sense özelliğini kullanmamızı sağlar.

Dynamics CRM 4.0’dan beri WSDL ile çalışan kişiler bu yeni yapıda hiçbir farklılık

hissetmeyeceklerdir.

CrmSvcUtil.exe ile Early-Bound Sınıflar Oluşturmak Early-Bound tiplerle çalışabilmek için obje modelini bilmeye ihtiyacımız vardır. İşte

CrmSvcUtil.exe bize bu kodu üretecek olan programdır.

Program early-bound .Net Framework sınıflarını ve entity modellerini Microsoft Dynamics

CRM 2015 içerisinden almakta ve bize bir .cs dosyası halinde vermektedir. Bu noktadan

sonra üretilen bu .cs dosyasını ya Visual Studio ile kodunuzun bir parçası olarak kullanabilir

ya da bir dll haline getirip projenize referans olarak ekleyebilirsiniz. Bu sayede Visual Studio

içerisinde intelli-sense özelliği ile kod geliştirebilirsiniz.

Eğer isterseniz uygulama her bir entity için ayrı bir partial class’da oluşturabilir.

CRM’in SDK’sında bin klasörü içerisinde bulabileceğiniz bu aracı command prompt ile

çalıştırabilirsiniz.

crmsvcutil.exe

/url: buraya Organization Service’in adresi gelecek

/out: çıktının hangi dosyaya olacağı bilgisi

/username : servise bağlanılacak kullanıcı adı

/şifre : servise bağlanılacak şifre

Eğer CRM’de zaten kullanıcı olan bir kişi ile oturum açtıysanız k.adı ve şifre

belirtmenize gerek yok.

Page 13: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

12 | P a g e

Bu şekilde gerekli cümleyi command promt’a yazdığınızda yukarıdaki ekranda olduğu gibi

.cs dosyanızı alabilirsiniz.

Ek olarak aşağıdaki parametreleri de verebilirsiniz;

/serviceContextName: Eğer .cs dosyanızı LINQ Service Context vasıtasıyla LINQ

sorgularını da desteklemesini istiyorsanız bu özelliği kullanmalısınız. Buraya türetilecek

servis context’inin adını girmelisiniz örneğin “CrmDataContext” gibi.

Burada ek olarak şunu da belirtmeliyim ki bu komutu varsayalında ben hep kullanıyorum. Bu

komutu kullandığımız zaman 2 şeyi unutmamız gerekmekte;

1. Bir OrganizationContext oluşmakta artık onu kullanmamız gerekmekte, aşağıdaki

örnekte olduğu gibi;

CrmDataContext orgContext = new CrmDataContext(ServiseBaglan());

2. Crm Servis çağrısına şu özelliği eklememiz gerekmekte;

_serviceproxy.EnableProxyTypes();

Bu iki maddenin detayını LINQ ile veri sorgulama makalemde daha detaylı anlatacağım.

/namespace : Varsayılanda .cs dosyası bir namespace olmadan türetilir bu özelliği

kullanarak kodu bir namespace altında toplayabilirsiniz.

/language : CrmSvcUtil.exe varsayılanda C# kodu üretil eğer VB kodu üretmek

istiyorsanız bu özelliğe VB değerini vermeniz gerekmekte.

Bu tool aşağıdaki örnekte olduğu gibi bir kod üretmektedir;

/// <summary> /// Bir müşteriyi veya potansiyel müşteriyi temsil eden işletme. Ticari işlemlerde faturalanan şirket. /// </summary> [System.Runtime.Serialization.DataContractAttribute()] [Microsoft.Xrm.Sdk.Client.EntityLogicalNameAttribute("account")] [System.CodeDom.Compiler.GeneratedCodeAttribute("CrmSvcUtil", "5.0.9688.1244")] public partial class Account : Microsoft.Xrm.Sdk.Entity, System.ComponentModel.INotifyPropertyChanging, System.ComponentModel.INotifyPropertyChanged {

Page 14: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

13 | P a g e

/// <summary> /// Default Constructor. /// </summary> public Account() : base(EntityLogicalName) { } public const string EntityLogicalName = "account"; public const int EntityTypeCode = 1; public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged; public event System.ComponentModel.PropertyChangingEventHandler PropertyChanging; private void OnPropertyChanged(string propertyName) { if ((this.PropertyChanged != null)) { this.PropertyChanged(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); } }

Page 15: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

14 | P a g e

Veri Turleri Hakkinda

Microsoft Dynamics CRM 2011 ve Microsoft Dynamics CRM Online'da programlama

modeli .NET'in temel türlerini kullanacak şekilde değiştirildi.

Bu tabloda beni en çok şaşırtan ise Customer, Lookup, Owner nesnelerinin artık

EntityReference türünden sadece bir değer almaları. CRM'i yeni öğrenler için işler gerçekten

kolaylaştırılmış. Artık kod yazarken CRM ile başlayan nesnelerimiz yok.

Aşağıdaki tablo bize Microsoft Dynamics CRM 4.0 ile CRM 2011, 2013 ve 2015 arasındaki

tür dönüşümünü göstermektedir.

Özellik Adı Microsoft Dynamics CRM 2011,

2013, 2015 Türü

Microsoft Dynamics

CRM 4.0 Türü

AttributeTypeCode.Boolean bool ya da System.Boolean CrmBoolean

AttributeType.CalendarRules EntityCollection DynamicEntity[] or calendarrule[]

AttributeType.Customer EntityReference Customer

AttributeType.DateTime System.DateTime CrmDateTime

AttributeType.Decimal decimal ya da System.Decimal CrmDecimal

AttributeType.Double double ya da System.Double CrmFloat

AttributeType.Integer int ya da System.Integer CrmNumber

AttributeType.Internal

System.Object

Kayıtlarda Kullanılmaz

Kayıtlarda Kullanılmaz.

AttributeType.Lookup EntityReference Lookup

AttributeType.Memo string ya da System.String System.String

AttributeType.Money Money CrmMoney

AttributeType.Owner EntityReference Owner

AttributeType.PartyList EntityCollection or ActivityParty[] activityparty[] or

DynamicEntity []

AttributeType.Picklist OptionSetValue Picklist

AttributeType.PrimaryKey System.Guid Key

AttributeType.String System.String System.String

AttributeType.State OptionSetValue yada oluşturulan

enumeration kullanılmalı EntityNameStateInfo

AttributeType.Status OptionSetValue ya da int Status

AttributeType.Uniqueidentifier

System.Guid UniqueIdentifier

AttributeType.Virtual

System.Object

Kayıtlarda Kullanılmaz

Kayıtlarda Kullanılmaz

Eski Tür Yeni Tür

CrmAttributeType Class (MetadataService)

Microsoft.Xrm.Sdk.Metadata.AttributeTypeCode

Moniker Class (CrmService) Microsoft.Xrm.Sdk.EntityReference

SecurityPrincipal Class (CrmService) Microsoft.Xrm.Sdk.EntityReference

Page 16: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

15 | P a g e

OptionSetValue OptionSetValue’a değer atamak için ilk önce OptionSetValue türünden bir nesne

oluşturmanız gerekmektedir. Burada dikkat çekmek istediğim konu ise eğer state alanı ile

çalışacaksanız (yani firma için aktif/pasif, teklif için açık/kazanıldı/kaybedildi gibi) early-

bound sınıflarda bunlar için mutlaka bir enumaration oluşturulmakta. Ama late bound

sınıflarda bu durumu programcı yönetmektedir.

Örnek olarak adres üzerindeki bir optionset alana değer atama aşağıdaki şekilde olmaktadır;

OptionSetValue osv = new OptionSetValue(1);

contact.Attributes["address1_freighttermscode"] = osv;

EntityReference CRM sisteminde iki entity’yi birbirine bağlamak için lookup nesnesini kullanmak zorundayız.

Lookup’lar üzerinde programatik işlem yapabilmek için EntityReference nesnesini

kullanmaktayız. Bu nesneye Lookup alana reference vermek istemiz nesnenin türü ve Id’sini

vermemiz gerekmektedir.

Aşağıdaki örnekte parentAccountId atama yapılacak nesnenin guid cinsinden Id’si olmalı;

EntityReference parentaccountid = new EntityReference("account", parentAccountId)); accountEntity.Attributes["parentaccountid"] = parentaccountid; ioService.Update(accountEntity);

Null Değer Atama CRM 4.0’dan farklı olarak .Net Type türleri kullanıldığı için null değer atama işlemi artık

sadece alana değer vermekten ibaret oldu. İşte birkaç örnek;

EntityAdi.IndustryCode = null; EntityAdi.AccountId = Guid.Empty; EntityAdi.AccountNumber =""; EntityAdi.Address1_Country = String.Empty;

Veri Sorgulama

Bu noktada sizlere Dynamics CRM’den veri çekmek için kullanabileceğiniz yapıları

anlatacağım. FetchXML ile veri çekmek bence şu anda kullanılabilecek en pratik yöntem ama

bunun haricinde .Net Language-Integrated Query(LINQ) ile early ve late binding türler

üzerinden veri çekebileceğiniz gibi Dynamics CRM’in Query Expression mimarisini

kullanarak da veri çekebilirsiniz.

Bu üçü haricinde OData ve Filtered View’ları kullanarak da veri çekebilirsiniz. OData(Open

Data Protocol) Rest tabanlı servisler için protokol görevi gören bir veritabanı sorgulama

yapısıdır. Filtered View’lar ise standart SQL ile SQL Server üzerinden direkt veri çekmek için

kullanabileceğimiz yapılar ama Filtered View ve OData ile geriye CRM obje sınıflarıyla veri

döndürememekteyiz. Yani SQL ile bir veri çektiğinizde DataSet ya da DataTable gibi yapılara

veriyi çekebiliriz ama FetchXML ile CRM entity sınıfından geriye dönüş alırız bu yüzden

kullanım açısından ilk yöntem daha kullanışlıdır.

Page 17: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

16 | P a g e

LINQ ile veriler üzerinde işlem yapabilmek için Organization Service Context sınıfını türetip

projeye eklemek gerekmektedir.

Benzerliklerini bir tablo üzerinde karşılaştırırsak;

Sorgu Biçimi Özellikleri

FetchXML

QueryExpression'ın bütün özelliklerine destek verdiği gibi matematiksel

işlemler ve gruplamaya da destek verir. Sorgular XML standartlarına göre

yazılır.

QueryExpression Sorgular bir obje modeli üzerinde icra edilir.

LINQ QueryExpression'ın limitleriyle sınırlıdır.

Yetenekleri bakımından karşılaştırırsak;

Odata QueryExpression FetchXML LINQ Filtered Views

Create, Update, Delete

desteği X X

Sorgu sonucu kayıtları

döndürme X X X X X

Rapor yaparken

kullanılabilirlik X X

Sorgu sonucu birden fazla

türde kayıt döndürme X X X X X

outer joins yapabilme X X X

Çalışma zamanında

doğrulama X X

İlişkisiz nesneleri bağlama

(Union) X X

Matematiksel İşlemleri

destekleme

X

(Sınırlı) X X X

Page 18: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

17 | P a g e

FetchXML FetchXML en güzel tarafı Dynamics CRM içerisinde Gelişmiş Ara (Advanced Find) ile

oluşturduğumuz sorguların da bu şekilde sistemde kaydedilmesi. Ayrıca bu şekilde

oluşturduğumuz sorguları da .xml olarak CRM’den alabiliyoruz böylece yazdığımız

uygulama ya da rapor içerisinde de kullanabilmekteyiz. Böylece uzun uzun FecthXML

hazırlamak yerine sistemin nimetlerinden yararlanarak sorgumuzu hazırlayabilmekteyiz.

Bunun için gelişmiş bul içerisinde Fetch XML indir düğmesine tıklıyoruz.

CRM’de de bu kullanıcı sorguları userquery, organizasyon sorguları ise savedquery içerisinde

saklanmaktadır.

IOrganizationService.RetrieveMultiple methodu ile FetchXML sorgulaması yapabilmekteyiz

bunun için FetchXMLToQueryExpressionRequest mesajını kullanmak gerekmektedir. Ayrıca

daha önce de belirttiğim gibi aggregations yani sum, max, min, count gibi matematiksel

işlemleri de FetchXML ile yapabilmekteyiz.

Bu makaledeki örneklerde CRM Servisini çağırmak daha önceki Singleton Tasarım Deseni

üzerinden geliştirdiğim servise bağlanma metodunu kullanıyorum. Sözünü ettiğim

makaleye buradan ulaşabilirsiniz. Bu noktayı siz de kendinize uygun olarak

değiştirebilirsiniz.

Sorguyu Hazırlama

Bu noktada örnek bir fetchXML’i inceleyelim;

<fetch mapping='logical'>

<entity name='account'>

Page 19: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

18 | P a g e

<all-attributes/>

</entity>

</fetch>

FetchXML mutalaka “fetch” kelimeleri arasında yer almalı. Sonrasında ise “entity” kelimesi

ile geri dönecek nesnenin türünü söylüyoruz. Sonrasında ise hangi alanların geri döneceğini

ve nasıl koşullar olacağını belirtiyoruz. Tabii yukarıdaki örnekte bunlar yok “all-attributes” ile

biz bütün alanları geri döndür diyoruz.

Size bu sorguyu SQL ile anlatmam gerekirse : “select * from account” şeklinde olacak. Şimdi

işi biraz daha renklendirelim;

<fetch mapping='logical'>

<entity name='contact'>

<attribute name='fullname'/>

<attribute name='createdon'/>

<filter type='and'>

<condition attribute='jobtitle' operator='eq' value='Purchasing Assistant'/>

</filter>

</entity>

</fetch>

Bu sorguda ise geriye contact yani ilgili kişi nesnesi geri dönecek ama sadece “fullname” ve

“createdon” alanları ile. Ayrıca burada bir kriterimiz de var “jobtitle” alanı “Purchasing

Assistant” olacak kayıtları alıyoruz. Yani yine SQL ile anlatırsam :

“select fullname, createdon from contact where jobtitle='Purchasing Assistant'” Burada

dikkat ettiyseniz operatör diye bir ifade yer almakta. Sorgulama yaparken değerlerin nasıl

koşullarda alınması gerektiğini burada belirtiyoruz. Yani aşağıdaki tabloda da görebileceğiniz

üzere sorgu ifadeleri kısmında "Koşul İfadesi" kısmında yazan değerler bizim normal sql

cümlesinde kullandığımız ifadelere benzemektedir. Tek fark "=","<",">" gibi ifadelerin

yerlerine "eq","gt","lt"gibi text bazlı ifadelerin gelmiş olmasıdır.

Koşul Koşul İfadesi Değer

equals x eq x

does not equal x ne x

is greater than x gt x

Page 20: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

19 | P a g e

is greater than or equal to x ge x

is less than x lt x

is less than or equal to x le x

begins with x like x%

does not begin with x not-like x%

ends with x like %x

does not end with x not-like %x

contains x like %x%

does not contain x not-like %x%

exists not-null

does not exist null

anytime not-null

yesterday yesterday

today today

tomorrow tomorrow

in next 7 days next-seven-days

in last 7 days last-seven-days

next week next-week

last week last-week

this week this-week

this month this-month

last month last-month

next month next-month

this year this-year

next year next-year

Page 21: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

20 | P a g e

last year last-year

on x on x

on or after x on-or-after x

on or before x on-or-before x

in between between

not between not-between

in in

not in not-in

equals user id eq-userid

does not equal user id ne-userid

equals business id eq-businessid

does not equal business id ne-businessid

Sorguyu Çalıştırma

Bu sorguyu çalıştırcak metod ise RetrieveMultiple metodudur ve servisi örneklediğimizde

karşımıza çaıkmaktadır. Bu metod makalenin başında bahsettiğim QueryExpression sınıfını

da alarak işlem yapabilmektedir. Bu metodun bir de kardeşi vardır ve hazır yeri gelmişken

bundan da bahsedeyim.

Retrieve Metodu ID’si verilen entity nesnesinin bildirdiğiniz sütünlarını bize geri

döndürür. Kullanımı çok basit olan bu metod geriye Entity türünden bir nesne döndürür. Bu

nesne zaten bizim parametre olarak verdiğimiz nesne adının kendisidir ve bizim belirttiğimiz

sutünları doldurarak getirir. Bu metod aslında sql cümlesi olarak bakarsak

“ select alanisimleri from (nesne)entity where entityid = '...' ” işlemini yerine

getirmektedir.

Aşağıdaki örnekle devam edelim;

Entity slead = servis.Retrieve("lead", new Guid("7bE545CCD3-9A3A-E011-BA8B-

78E7D1623F9D"), newColumnSet(new string [] { "fullname", "companyname" }));

foreach (var item in slead.Attributes)

Page 22: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

21 | P a g e

{

Console.WriteLine(item.Key + ":" + item.Value);

}

Eğer entity’nin bütün alanlarını geri döndürmek istiyorsak new ColumnSet(true) komutunu

ColumnSet yerine vermemiz gerekmektedir. Yani eğer siz sorgulayacağımız nesnenin GUID

türünden idsini biliyorsanız ve join gibi işlemlerle işiniz yoksa düz mantıkta bir sorgulama

yapmak için bu metodu kullanabilirsiniz.

RetrieveMultiple Metodu ise gerçek anlamda karışık sorguları yapmamıza olanak tanır. Ama

burada tamamen object oriented bir mimari söz konusudur yani temelde bir sorgulama

cümlesi olmadan QueryExpression ya da QueryByAttribute sınıflarının örnekleri üzerinden

sorgulama işlemi yapılmasına da olanak sağlar.

Bizim odak konumuz ise fetchXML olduğu için konuyu fazla dağıtmadan devam edelim.

Bu fetchXML sorgusunu çalıştırmak için ise şu şekilde bir kod yazdım;

string fetchXml = @"<fetch mapping='logical'>

<entity name='contact'>

<attribute name='fullname'/>

<attribute name='createdon'/>

<filter type='and'>

<condition attribute='jobtitle' operator='eq'

value='Purchasing Assistant'/>

</filter>

</entity>

</fetch>";

EntityCollection contactlist =

(EntityCollection)ServiseBaglan().RetrieveMultiple(new FetchExpression(fetchXml));

foreach (var cnt in contactlist.Entities)

{

Console.WriteLine(cnt.Attributes["fullname"].ToString() + ":" +

cnt.Attributes["createdon"].ToString());

}

Console.ReadLine();

Page 23: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

22 | P a g e

Sorgu Sonucu

İşte biraz önce bahsettiğim RetrieveMultiple metoduna fetchXML’i veriyorum. Dönüşte ise

sistem bana EntityCollection içerisinde talep ettğim entity’i vermekte. Bu noktadan sonra

foreach ile bütün kayıtar içinde dolaşabilir ve Attributes ile alanlara ulaşabilirim.

Bu kodu çalıştırınca da aşağıdaki gibi sonucu almaktayım;

İleri Seviye Sorgular

Yukarıda temel bilgileri verdikten sonra ileri seviye bilgilerle buradan devam edebiliriz.

<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>

<entity name='lead'>

<attribute name='fullname' />

<attribute name='createdon' />

<filter type='and'>

<condition attribute='ownerid' operator='eq-userid' />

<condition attribute='statecode' operator='eq' value='0' />

</filter>

</entity>

</fetch>

Page 24: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

23 | P a g e

Bu sorguda ise “lead” türünden nesneleri geri döndürmekteyiz. “fullname” ve “createdon”

alanlarını istemekteyiz sorgu ile ama “ownerid” yani kayıtların sahibi “eq-userid” diyerek

servise kim bağlandıysa onun kayıtları olacak ve durumları da aktif olacak.

Düz mantıktaki tek bir nesne üzerinden sorgular işte bu şekilde yapılmakta ama sistem

bundan daha fazlasına izin verebilmekte yani biz eğer istersek inner ya da outer join yaparak

başka nesneler ile de ilişki içerisindeki kayıtları da geriye döndürebiliriz. Aşağıdaki örnek

üzerinden açıklamaya çalışayım;

<fetch version='1.0' output-format='xml-platform' mapping='logical' distinct='false'>

<entity name='account'>

<attribute name='name' />

<attribute name='address1_city' />

<attribute name='telephone1' />

<order attribute='name' descending='true' />

<filter type='and'>

<condition attribute='name' operator='like' value='{0}%' />

</filter>

<link-entity name='contact' from='contactid' to='primarycontactid' alias='kisi'>

<attribute name='emailaddress1' />

<filter type='and'>

<condition attribute='firstname' operator='like' value='{0}%' />

</filter>

</link-entity>

<link-

entity name='systemuser' from='systemuserid' to='createdby' visible='false' link-

type='outer' alias='kullanici'>

<attribute name='firstname' />

</link-entity>

</entity>

</fetch>

Burada temelde yine bir nesne üzerinde yani “account” nesnesi üzerinden hareket ediyor gibi

gözüksek de “link-entity” düğümleriyle işi genişletiyoruz. Örnekte görebileceğiniz üzere

“contact” ve “systemuser” nesneleri üzerinden de geriye alan döndürdüğümüz gibi bunlar

üzerinden de sorgulama yapabilmekteyiz. “link-entity” içerisinde sisteme hangi nesne ile link

yapacağımızı ve bu nesnelerin hangi alanlar üzerinde birbirleriyle ilişki içerisinde olduklarını

söylemekteyiz. Ayrıca “alias” vererek de kodun ilerleyen kısımlarında buradan gelecek

alanlar için bir tanımlayıcı da oluşturabilmekteyiz.

Page 25: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

24 | P a g e

Burada ben “link-type” olarak “outer” kullandım ama siz isterseniz “inner join” yapmak için

“inner” de kullanabilirsiniz.

Bu arada belirtmeliyim ki “order” komutu ile de belli bir alan üzerinden kayıtların

“ascending” ya da “descending” olarak sıralanmasını da sağlayabilmekteyiz.

Örnekte ben firma adı ve kişi adı için konsoldan parametre almaktayım bu yüzden orada

“{0}” ifadesini görmektesiniz.

Bu sorguyu daha raht anlamanız için SQL cümlesine çevirecek olursam;

select name, address1_city, telephone1, kisi.emailaddress1, kullanici.firstname from a

ccount innerjoin contact kisi on kisi.contactid = account.primarycontactid

inner join systemuser kullanici on kullanici.systemuserid = account.createdby

where account.name like '%%' and kisi.firstname like '%%'

order by account.name desc

Böyle bir sorgu yazmamız gerekirdi. Bu kodu çalıştıracak örnek uygulama ise şu şekilde;

string fetch = @"

<fetch version='1.0' output-format='xml-platform'

mapping='logical' distinct='false'>

<entity name='account'>

<attribute name='name' />

<attribute name='address1_city' />

<attribute name='telephone1' />

<order attribute='name' descending='true' />

<filter type='and'>

<condition attribute='name' operator='like'

value='{0}%' />

</filter>

<link-entity name='contact' from='contactid'

to='primarycontactid' alias='kisi'>

<attribute name='emailaddress1' />

<filter type='and'>

<condition attribute='firstname'

operator='like' value='{0}%' />

</filter>

</link-entity>

<link-entity name='systemuser' from='systemuserid'

to='createdby' visible='false' link-type='outer' alias='kullanici'>

<attribute name='firstname' />

Page 26: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

25 | P a g e

</link-entity>

</entity>

</fetch>";

Console.WriteLine("bir karakter yazın:");

fetch = string.Format(fetch, Console.ReadLine());

EntityCollection groupby1_result =

ServiseBaglan().RetrieveMultiple(newFetchExpression(fetch));

foreach (var c in groupby1_result.Entities)

{

Console.WriteLine("ad:" + c["name"].ToString());

Console.WriteLine("sehir:" + c["address1_city"].ToString());

Console.WriteLine("telefon:" + c["telephone1"].ToString());

Console.WriteLine("kisi eposta:" +

((AliasedValue)c["kisi.emailaddress1"]).Value.ToString());

Console.WriteLine("kullanici:" +

((AliasedValue)c["kullanici.firstname"]).Value.ToString());

Console.WriteLine("\n");

}

Console.ReadLine();

Burada bir noktanın üzerinde durmamız gerekmekte. Kişi ve Kullanıcı üzerindeki alanlardan

veri alabilmek için “kisi” ve “kullanici” isimli alias’ları kullanmıştık. İşte bu alanlardan veri

okuyacağımız zaman şu şekilde bir kullanıma ihtiyacımız bulunmakta;

((AliasedValue)c["kullanici.firstname"]).Value.ToString()

Yani gelen değeri önce “AliasedValue”’e parse etmemiz sonrasında ise “Value” üzerinden

değerini almalıyız.

Çıktımız ise şu şekilde. Yani adı “a” ile başlayan bir firma ve ona adı “a” ile başlayan birinci

ilgili kişi kaydı olarak eklenmiş bir kayıt bulunmakta.

Page 27: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

26 | P a g e

Eğer XSD dosyalarını okumayı biliyorsanız fetchXML üzerinde nereye hangi değerlerin nasıl

gelebileceğini anlayabilirsiniz. Ayrıca bunu dosya haline getirerek Visual Studio’ya

tanıtırsanız fetchXML yazarken denetleme yaparak size hataları da gösterecektir. Ama şu

anda en güzel fetchXML oluşturma yöntemi daha önce de belirttiğim gibi Gelişmiş Ara

aracını kullanmaktır.

<?xml version="1.0" encoding="utf-8" ?>

<xs:schema id="fetch" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/

XMLSchema"

xmlns:mstns="http://tempuri.org/fetch/unique">

<xs:annotation>

<xs:documentation>Schema name: fetch-schema</xs:documentation>

</xs:annotation>

<!--

condition element - used for capturing entity and link-entity

"where" clause criteria

-->

<!-- [XDR-XSD] "value" element -->

<xs:element name="value" type="xs:string"></xs:element>

<!-- [XDR-XSD] "condition" element -->

<xs:element name="condition">

<xs:complexType>

<xs:choice minOccurs="0" maxOccurs="unbounded">

<!-- -->

Page 28: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

27 | P a g e

<!--

The attribute "value" is used for all operators that compare to a single value (for

example, eq).

The element "value" is used for operators that compare to multiple values (for

example, in).

Some operators require neither the attribute "value" or the element "value" (for

example, null).

-->

<xs:element name="value" minOccurs="0" maxOccurs="unbounded">

<xs:complexType>

<xs:simpleContent>

<xs:extension base="xs:string">

<xs:attribute name="uiname" type="xs:string" />

<xs:attribute name="uitype" type="xs:string" />

</xs:extension>

</xs:simpleContent>

</xs:complexType>

</xs:element>

</xs:choice>

<!-- -->

<xs:attribute name="column" type="xs:string" />

<xs:attribute name="attribute" type="xs:string"></xs:attribute>

<xs:attribute name="entityname" type="xs:string"></xs:attribute>

<xs:attribute name="operator" use="required" type="operator"></xs:attribute>

<!--

The attribute "value" is used for all operators that compare to a single value (for

example, eq).

The element "value" is used for operators that compare to multiple values (for

example, in).

Some operators require neither the attribute "value" or the element "value" (for

example, null).

-->

<xs:attribute name="value" type="xs:string"></xs:attribute>

<xs:attribute name="aggregate" type="AggregateType"></xs:attribute>

<xs:attribute name="alias" type="xs:string"></xs:attribute>

<xs:attribute name="uiname" />

<xs:attribute name="uitype" />

Page 29: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

28 | P a g e

<xs:attribute name="uihidden" type="TrueFalse01Type" />

</xs:complexType>

</xs:element>

<!--

filter element - used for constructing complex conditionals

legal on entity and link-entity

-->

<!-- [XDR-XSD] "filter" element -->

<xs:element name="filter">

<xs:complexType>

<xs:choice minOccurs="0" maxOccurs="unbounded">

<!-- -->

<xs:element ref="condition" minOccurs="0" maxOccurs="500" />

<xs:element ref="filter" minOccurs="0" maxOccurs="unbounded" />

</xs:choice>

<!-- -->

<xs:attribute name="type" default="and">

<xs:simpleType>

<xs:restriction base="xs:NMTOKEN">

<xs:enumeration value="and" />

<xs:enumeration value="or" />

</xs:restriction>

</xs:simpleType>

</xs:attribute>

<xs:attribute name="isquickfindfields" type="xs:boolean" />

</xs:complexType>

</xs:element>

<!--

attribute elements - used for selecting attributes from the

surrounding entity / link-entity, these

values are returned as part of the fetch

Page 30: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

29 | P a g e

-->

<!-- [XDR-XSD] "all-attributes" element -->

<xs:element name="all-attributes">

<xs:complexType></xs:complexType>

</xs:element>

<!-- [XDR-XSD] "attribute" element -->

<xs:complexType name="FetchAttributeType">

<xs:attribute name="name" use="required" type="xs:string"></xs:attribute>

<xs:attribute name="build" type="build"></xs:attribute>

<xs:attribute name="addedby" type="xs:string" />

<xs:attribute name="alias" type="xs:string"></xs:attribute>

<xs:attribute name="aggregate" type="AggregateType"></xs:attribute>

<xs:attribute name="groupby" type="FetchBoolType"></xs:attribute>

<xs:attribute name="dategrouping" type="DateGroupingType"></xs:attribute>

<xs:attribute name="usertimezone" type="FetchBoolType"></xs:attribute>

</xs:complexType>

<!--

order element - used to specify a sort order

-->

<!-- [XDR-XSD] "order" element -->

<xs:complexType name="FetchOrderType">

<xs:choice minOccurs="0" maxOccurs="unbounded">

<!-- -->

</xs:choice>

<!-- -->

<xs:attribute name="attribute" type="xs:string"></xs:attribute>

<xs:attribute name="alias" type="xs:string"></xs:attribute>

<xs:attribute name="descending" default="false" type="xs:boolean"></xs:attribute>

</xs:complexType>

<!--

link-entity element - used for joining one entity to its "parent"

Page 31: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

30 | P a g e

-->

<!-- [XDR-XSD] "link-entity" element -->

<xs:complexType name="FetchLinkEntityType">

<xs:choice minOccurs="0" maxOccurs="unbounded">

<!-- -->

<xs:element ref="all-attributes" minOccurs="0" />

<xs:element name="attribute" type="FetchAttributeType" minOccurs="0" maxOccurs="

unbounded" />

<xs:element name="order" type="FetchOrderType" minOccurs="0" maxOccurs="1" />

<xs:element ref="filter" minOccurs="0" />

<xs:element name="link-entity" type="FetchLinkEntityType" />

</xs:choice>

<!-- -->

<xs:attribute name="name" use="required" type="xs:string"></xs:attribute

FetchXML ile Aggregate(Toplama Sorguları) İşlemleri Bir önceki bolumde FetchXML ile neler yapabileceğimize değindik. Eğer istersek FetchXML

ile grouping ve aggregate işlemlerini de yapabilmekteyiz. FetchXML ile aşağıdaki işlemler

desteklenmektedir;

sum

avg

min

max

count(*)

count(attribute name)

Aggregate yapabileceğimiz sorgu örneği standart olarak bildiğimiz fetchXML kurgusundan

farklı değil burada sadece attribute kısmında aggregate ile ilgili keyword yer almakta.

Aggregate=true diyerek bu şekilde bir sorgulama yapacağımızı sisteme söylüyoruz.

Sonrasında ise sırasıyla hangi alan üzerinden işlem yapılacağını, alias yani etiketin ne

olacağını ve aggregate türümüzün ne olacağını sisteme söylüyoruz.

<fetch distinct='false' mapping='logical' aggregate='true'> <entity name='opportunity'> <attribute name='name' alias='opportunity_count' aggregate='count'/> </entity> </fetch>

Bu şekilde oluşturduğumuz bir sorgu ile aslında şunu demek istiyoruz : “select count('name')

as opportunity_count from opportunity” yani standart bir count işleminden fazlası değil

yaptığımız.

Page 32: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

31 | P a g e

Bu fetchXML’i çalıştırmak için ise aşağıdaki gibi bir kod hazırladım; string opportunity_count = @" <fetch distinct='false' mapping='logical' aggregate='true'> <entity name='opportunity'> <attribute name='name' alias='opportunity_count' aggregate='count'/> </entity> </fetch>"; EntityCollection opportunity_count_result = ServiseBaglan().RetrieveMultiple(new FetchExpression(opportunity_count)); foreach (var c in opportunity_count_result.Entities) { Int32 aggregate2 = (Int32)((AliasedValue)c["opportunity_count"]).Value; System.Console.WriteLine("Count of all opportunities: " + aggregate2); }

Burada dikkat edilmesi gereken nokta geriye EntityCollection döndürmesi. Bir önceki

makalemden hatırlarsanız normalde bu tarz sorgulama ile biz geriye account, contact gibi

sitem içerisindeki nesnelerden oluşmuş bir dizi alıyoruz. FetchXML yapısı gereği tek bir

metod kullanıyoruz ve bu metod sonucunda yukarıdaki örnekte olduğu gibi tek bir satır dahi

dönecek olsa bile yine sonucu bir collection içerisinde almaktayız. Bu nedenle mecbur

foreach içerisinde dönüyoruz ya da collection’un 0. üyesini alıyoruz. Ben örneğimde foreach

ile collection içinde döndüm ve gördüğünüz gibi değeri aldım.

Yine bir önceki makalemde ileri düzey sorgular bölümünde anlattığım gibi eğer nesne

üzerinden direkt bir değer döndürmeyeceksek sonuç her zaman AliasedValue olarak

gelmekte. işte bu nedenden dolayı şu şekilde bir convert işlemi yapıyoruz; Int32 aggregate2 = (Int32)((AliasedValue)c["opportunity_count"]).Value

Bu işlem sonucunda bu koddan aşağıdaki gibi çıktımızı alabiliyoruz.

Eğer distinct yapmak istersek de fetchXML içerisine yerleştireceğimiz bir distinct=”true”

ifadesiyle ile sisteme bunu beliretebiliriz.

Aşağıda ise distinct yapılmış bir kod örneği bulunmakta; <fetch distinct='false' mapping='logical' aggregate='true'> <entity name='opportunity'> <attribute name='name' alias='opportunity_distcount' aggregate='countcolumn' distinct='true'/> </entity> </fetch>

Bu FetxhXML’i de aşağıdaki kodla çalıştırabiliriz.

Page 33: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

32 | P a g e

string opportunity_distcount = @" <fetch distinct='false' mapping='logical' aggregate='true'> <entity name='opportunity'> <attribute name='name' alias='opportunity_distcount' aggregate='countcolumn' distinct='true'/> </entity> </fetch>"; EntityCollection opportunity_distcount_result = ServiseBaglan().RetrieveMultiple(new FetchExpression(opportunity_distcount)); foreach (var c in opportunity_distcount_result.Entities) { Int32 aggregate4 = (Int32)((AliasedValue)c["opportunity_distcount"]).Value; System.Console.WriteLine("Distinct name count of all opportunities: " + aggregate4); } Console.ReadLine();

Bu kod sonucunda da aşağıdaki gibi bir cevap alabiliriz sistemden;

Gelin olayı biraz renklendirelim. Bu sefer de bir sorgu içerisinde birden fazla aggregate

seçeneğinin cevabını isteyelim. Böyle bir işlem için standart fetchXML’in içerisinde sırasıyla

hangi özelliklerin bize geri döneceğini belirtiyoruz tabii unutulmaması gereken nokta ise

hepsi için ayrı birer alias olması gerektiğidir. <fetch distinct='false' mapping='logical' aggregate='true'> <entity name='opportunity'> <attribute name='opportunityid' alias='opportunity_count' aggregate='count'/> <attribute name='estimatedvalue' alias='estimatedvalue_sum' aggregate='sum'/> <attribute name='estimatedvalue' alias='estimatedvalue_avg' aggregate='avg'/> </entity> </fetch>

Bu sorgu için ise aşağıdaki kodu hazırladım; string estimatedvalue_avg2 = @" <fetch distinct='false' mapping='logical' aggregate='true'> <entity name='opportunity'> <attribute name='opportunityid' alias='opportunity_count' aggregate='count'/> <attribute name='estimatedvalue' alias='estimatedvalue_sum' aggregate='sum'/> <attribute name='estimatedvalue' alias='estimatedvalue_avg' aggregate='avg'/> </entity>

Page 34: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

33 | P a g e

</fetch>"; EntityCollection estimatedvalue_avg2_result = ServiseBaglan().RetrieveMultiple(new FetchExpression(estimatedvalue_avg2)); foreach (var c in estimatedvalue_avg2_result.Entities) { Int32 aggregate8a = (Int32)((AliasedValue)c["opportunity_count"]).Value; System.Console.WriteLine("Count of all opportunities: " + aggregate8a); decimal aggregate8b = ((Money)((AliasedValue)c["estimatedvalue_sum"]).Value).Value; System.Console.WriteLine("Sum of estimated value of all opportunities: " + aggregate8b); decimal aggregate8c = ((Money)((AliasedValue)c["estimatedvalue_avg"]).Value).Value; System.Console.WriteLine("Average of estimated value of all opportunities: " + aggregate8c); } Console.ReadLine();

İşte bu şekilde aynı anda count, sum ve avg işlemlerini yapabilmekteyim. Sonuç ise aşağıdaki

gibi;

Create/Update/Delete Metodları CRM servis nesnesi bize kayıtlar üzerinde işlem yapma özelliği sağlamaktadır. Servis içinden

yapmak istediğimiz harekete uygun metodu çağırmamız gerekmektedir. Tabii burada

unutulmaması gereken konu servisi çağıran kullanıcının çağrılan metodda işlem yapmaya

yetkili olması gerekmektedir.

Create Metodu CRM 2015 içerisinde bir entity içerisinde yeni bir nesne oluşturmamıza

olanak tanır. Metod parametre olarak entity türünden bir nesne alır ve yeni oluşturulmuş

nesnenin GUID türünden değerini geri döndürür.

Aşağıdaki örnek bu metodun late-bound sınıfla kullanımını göstermektedir.

// Entity nesnesinin yeni bir instance’ini olusturuyoruz Entity account = new Entity("account");

Page 35: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

34 | P a g e

// Gerekli attribute’lara atama yapiyoruz. account["name"] = "Örnek Firma"; // Örnek Firma adında bir firma karti olusturuyoruz. _accountId = ioService.Create(account);

Aşağıdaki örnek bu metodun early-bound sınıfla kullanımını göstermektedir.

Contact contact = new Contact() { FirstName="Deneme", LastName="Kisisi", Address1_City="İstanbul", }; Guid contactGuid =_service.Create(contact);

Update Metodu CRM 2011 içerisinde bir entity içerisinde bir nesneyi güncellememizi sağlar.

Metod parametre olarak entity türünden bir nesne alır. Güncellenecek nesnenin id’si mutlaka

parametre olarak verilmelidir.

Guid gContact = new Guid("7bE545CCD3-9A3A-E011-BA8B-78E7D1623F9D"); Contact contact = new Contact() { ContactId = gContact, FirstName="Test", LastName="Kisisi", Address1_City="Ankara", }; _service.Update(contact);

Delete Metodu CRM 2011 içerisinde Id’sini verdiğiniz bir nesneyi sistemden silmeye yarar.

Metod parametre olarak silinecek nesnenin Id’si yanında bu nesnenin türünü ister.

Guid gContact = "7bE545CCD3-9A3A-E011-BA8B-78E7D1623F9D"; _service.delete("contact", gContact);

Bir programcı olarak çok standart olan bu işlemleri isterseniz bir class mantığı altında

birleştirelim. Bu sayede daha yönetilebilir bir CRUD (Create, Read, Update, Delete) yapısı

oluşturabiliriz. Ben bu sınıf için Process adını kullandım ve Process sınıfı içerisinde şu anda

Oluşturma, Güncelleme ve Silme işlerimi yapmaktayım. İlerleyen makalelerde Okuma

yapılarını incelerken onları da bu sınıfa dâhil ederiz.

Burada öncelikle açıklamalıyım ki bir önceki makalede yer alan Singleton tasarım deseniyle

CRM servisini oluşturma yazımdaki class’tan faydalanarak servisi çağırma işlemini

gerçekleştirdim. O yazıyı okumak isterseniz buraya tıklayınız

Ek olarak hata olaylarını kontrol etmek için Result isimli bir class kullandım bu class’ın

içeriği şu şekilde

public class Result { public string Message { get; set; } public bool isError { get; set; } public Object BusinessObject { get; set; } public Result(string _Message, bool _isError, Object _BusinessObject) {

Page 36: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

35 | P a g e

Message = _Message; isError = _isError; BusinessObject = _BusinessObject; } public Result(string _Message, bool _isError) { Message = _Message; isError = _isError; BusinessObject = null; } }

Görüldüğü üzere çok basit bir class bize sonucun başarılı mı başarısız mı olduğunu

döndürecek o kadar.

Bunun haricinde bir de Base isimli bir class’ım var ki Process sınıfını aslında bu class’dan

türetmekteyim. Şu anda bu class’ı sadece ErrorNumber ve ErrorDetail gibi hata oluştuğunda

bilgi almamızı sağlayacak iki property ile kullanmaktayım ama ileride farklı propertyler de

eklenecek.

public class Base

{

public int ErrorCode { get; set; } public string ErrorDetail { get; set; }

}

Bu iki class’ımı açıkladıktan sonra asıl yapıda kullanacağımız metodlara gelelim. İlk önce

create metodunu inceleyelim. Hatırlayacağınız üzere CRM servisinde Create metdonun

Update metodundan tek farkı id’ye ihtiyaç duymamasıydı. Çünkü bu metod id’yi üretip bize

geri döndürecek. Ben de kurguyu buna göre planladım.

public Result Create(Entity EntityForCreate)

{

try { Service service = Service.GetService(); if (service == null) throw new Exception("Service is null"); if (service != null && service.ErrorCode > 0) throw new Exception(service.ErrorDetail); Guid EntityID = service.OrganizationService.Create(EntityForCreate); DetailedLog.CreateLog("Entity Created! Type: " + EntityForCreate.LogicalName + ", ID : " + EntityID, System.Diagnostics.EventLogEntryType.Information); return new Result("", false, EntityID); } catch (Exception ex) { ErrorCode = 100; ErrorDetail = ExceptionHandler.HandleException(ex); DetailedLog.CreateLog(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name

Page 37: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

36 | P a g e

+ " : " + System.Reflection.MethodBase.GetCurrentMethod().ToString() + " : " + ErrorDetail, System.Diagnostics.EventLogEntryType.Error); return new Result(ErrorDetail, true); } }

Aslında yapı çok basit servis nesnemi çağırıyorum, servis oluşurken hata var mı diye

bakıyorum eğer hata varsa hatayı fırlatıyorum. (bu noktada şunu belirtmeliyim ki catch

bölümünde yer alan DetailLog ve ExceptionHandler benim daha önceden yazmış olduğum

hata yönetimi ile ilgili class’lar catch bölümünü siz de istediğiniz gibi düzenleyebilirsiniz)

Eğer hata yok ise OrganizationService metodumu kullanarak nesnemi oluşturuyorum. Bu

noktada da bir hata yoksa servis bana oluşturduğu nesnenin id’sini döndürüyor yok eğer hata

varsa zaten kod catch bloğuna düşüyor. İşte bu kadar.

Şimdi gelin diğer metodlara bir göz atalım;

public Result Update(Entity EntityForUpdate, Guid EntityID) { try { Service service = Service.GetService(); if (service == null) throw new Exception("Service is null"); if (service != null && service.ErrorCode > 0) throw new Exception(service.ErrorDetail); service.OrganizationService.Update(EntityForUpdate); DetailedLog.CreateLog("Entity Updated! Type: " + EntityForUpdate.LogicalName + ", ID : " + EntityID, System.Diagnostics.EventLogEntryType.Information); return new Result("", false); } catch (Exception ex) { ErrorCode = 100; ErrorDetail = ExceptionHandler.HandleException(ex); DetailedLog.CreateLog(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + " : " + System.Reflection.MethodBase.GetCurrentMethod().ToString() + " : " + ErrorDetail, System.Diagnostics.EventLogEntryType.Error); return new Result(ErrorDetail, true); } }

Update metodu neredeyse Create metodunun aynısı tek fark daha önce de ifade ettiğim gibi

güncellenecek nesnenin id’sini alması. Bunu almalı ki neyi güncellediğini bilebilsin. Aslında

burada şöyle bir mantıksal kargaşa var update metodu ek olarak id’yi almamakta zaten sizin

ona update edilmesi için vereceğiniz entity’nin Id alanına vermelisiniz. Benim burada ek

olarak almamdaki amaç onu loglamak için.

Page 38: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

37 | P a g e

Bir de Delete metoduna göz atalım;

public Result Delete(string EntityName, Guid EntityID) { try { Service service = Service.GetService(); if (service == null) throw new Exception("Service is null"); if (service != null && service.ErrorCode > 0) throw new Exception(service.ErrorDetail); service.OrganizationService.Delete(EntityName, EntityID); DetailedLog.CreateLog("Entity Deleted! Type: " + EntityName + ", ID : " + EntityID, System.Diagnostics.EventLogEntryType.Information); return new Result("", false); } catch (Exception ex) { ErrorCode = 100; ErrorDetail = ExceptionHandler.HandleException(ex); DetailedLog.CreateLog(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + " : " + System.Reflection.MethodBase.GetCurrentMethod().ToString() + " : " + ErrorDetail, System.Diagnostics.EventLogEntryType.Error); return new Result(ErrorDetail, true, null); } }

Delete metodu entity’nin adını ve id’sini almakta. Bu iki veriyi de servise vermekteyiz.

Class’ın tamamına bakacak olursak;

public class Process : Base { public Result Create(Entity EntityForCreate) { try { Service service = Service.GetService(); if (service == null) throw new Exception("Service is null"); if (service != null && service.ErrorCode > 0) throw new Exception(service.ErrorDetail); Guid EntityID = service.OrganizationService.Create(EntityForCreate); DetailedLog.CreateLog("Entity Created! Type: " + EntityForCreate.LogicalName + ", ID : " + EntityID, System.Diagnostics.EventLogEntryType.Information); return new Result("", false, EntityID); } catch (Exception ex)

Page 39: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

38 | P a g e

{ ErrorCode = 100; ErrorDetail = ExceptionHandler.HandleException(ex); DetailedLog.CreateLog(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + " : " + System.Reflection.MethodBase.GetCurrentMethod().ToString() + " : " + ErrorDetail, System.Diagnostics.EventLogEntryType.Error); return new Result(ErrorDetail, true); } } public Result Update(Entity EntityForUpdate, Guid EntityID) { try { Service service = Service.GetService(); if (service == null) throw new Exception("Service is null"); if (service != null && service.ErrorCode > 0) throw new Exception(service.ErrorDetail); service.OrganizationService.Update(EntityForUpdate); DetailedLog.CreateLog("Entity Updated! Type: " + EntityForUpdate.LogicalName + ", ID : " + EntityID, System.Diagnostics.EventLogEntryType.Information); return new Result("", false); } catch (Exception ex) { ErrorCode = 100; ErrorDetail = ExceptionHandler.HandleException(ex); DetailedLog.CreateLog(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + " : " + System.Reflection.MethodBase.GetCurrentMethod().ToString() + " : " + ErrorDetail, System.Diagnostics.EventLogEntryType.Error); return new Result(ErrorDetail, true); } } public Result Delete(string EntityName, Guid EntityID) { try { Service service = Service.GetService(); if (service == null) throw new Exception("Service is null"); if (service != null && service.ErrorCode > 0) throw new Exception(service.ErrorDetail); service.OrganizationService.Delete(EntityName, EntityID);

Page 40: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

39 | P a g e

DetailedLog.CreateLog("Entity Deleted! Type: " + EntityName + ", ID : " + EntityID, System.Diagnostics.EventLogEntryType.Information); return new Result("", false); } catch (Exception ex) { ErrorCode = 100; ErrorDetail = ExceptionHandler.HandleException(ex); DetailedLog.CreateLog(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name + " : " + System.Reflection.MethodBase.GetCurrentMethod().ToString() + " : " + ErrorDetail, System.Diagnostics.EventLogEntryType.Error); return new Result(ErrorDetail, true, null); } } }

Class’ımızı bu şekilde oluşturduktan sonra gelin onu bir konsol uygulaması yardımıyla çağıralım ve iş

başında görelim.

static void Main(string[] args) { try { Entity lead = new Entity("lead"); lead.Attributes["subject"] = "Fuardan Gelenler"; lead.Attributes["firstname"] = "Barış"; lead.Attributes["lastname"] = "KANLICA"; lead.Attributes["companyname"] = "Omerd Business Solutions"; Process process = new Process(); Result result = process.Create(lead); if (result.isError) throw new Exception(result.Message); Console.WriteLine("Lead created : " + result.BusinessObject.ToString()); Console.ReadLine(); } catch (Exception ex) { Console.WriteLine("Error : " + ex.Message); Console.ReadLine(); } }

Gördüğünüz üzere Entity nesnemi çağıyor ve ona lead adını veriyorum. İçerisi istediğim

bilgiler ile dolduruyor ve Process class’ımın içindeki Create metodu vasıtasıyla CRM

içerisinde oluşmasını sağlıyorum. İşte hepsi bu kadar :)

Dynamics CRM 2015 Plug-in Mimarisi 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

Page 41: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

40 | P a g e

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;

Page 42: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

41 | P a g e

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

Page 43: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

42 | P a g e

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

Page 44: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

43 | P a g e

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; } } } }

Plug-in’ler Icerisindeki Hatalari Yakalamak Senkron calisan plug-in’ler sandbox’da olsun ya da olmasin herhangi bir hata ile karsilastiklarinda

geriye kullaniciya uyari gösterecek bir yapiya sahiptirler ve bu durumu Dynamics CRM yönetir. Yani

siz sadece hatayi geriye dondurursunuz.

Asenkron calisan yapilar için CRM içerisinde System Job(AsyncOperation) isimli bir bolum yer

almaktadır. Iste asenkron hatalari da buradan takip edebilirsiniz.

Senkron calisan plug-in’lerde ise hata mesajlarini InvalidPluginException turunden bir hata

göndererek kontrol edebilirsiniz. Message ozelligine herhangi bir değer gönderirseniz sistem onu

gösterir aksi takdirde varsayilan hata mesaji görüntülenir.

Ayrica sunu da belirteyim Sandbox içinde calismayan plug-in’ler için hata mesajlari sistemin calistigi

serverdaki Olay Goruntuleyici içerisinde Uygulama hatalari bolumu içerisine de kaydedilir.

Plug-in içerisinde uygun gordugunuz yerde su sekilde hata fırlatabilirsiniz:

throw new InvalidPluginExecutionException("The account number can only be set by the

system.");

Page 45: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

44 | P a g e

Bir plug-in hata firlattiginda CRM su sekilde bir uyari vermektedir.

Log dosyasini incelediğimizde de detaylari almaktayız. Bizim gönderdiğimiz mesaja dikkat edin lütfen;

Unhandled Exception: System.ServiceModel.FaultException`1[[Microsoft.Xrm.Sdk.OrganizationServiceFault, Microsoft.Xrm.Sdk, Version=7.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]]: The account number can only be set by the system. Detail: <OrganizationServiceFault xmlns="http://schemas.microsoft.com/xrm/2011/Contracts" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <ErrorCode>-2147220970</ErrorCode> <ErrorDetails xmlns:a="http://schemas.datacontract.org/2004/07/System.Collections.Generic"> <KeyValuePairOfstringanyType> <a:key>CallStack</a:key> <a:value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema"> at Microsoft.Crm.Sdk.Samples.AccountNumberPlugin.Execute(IServiceProvider serviceProvider) at PluginProfiler.Library.PluginAppDomainProxy.ExecuteCore(Stopwatch watch, ProfilerExecutionReport report, Object instance, Object executionParameter) at PluginProfiler.Library.AppDomainProxy.Execute(ProfilerExecutionConfiguration configuration, ProfilerExecutionReport report) </a:value> </KeyValuePairOfstringanyType> </ErrorDetails>

<Message>The account number can only be set by the system.</Message> <Timestamp>2015-04-08T15:29:50.7437667Z</Timestamp> <InnerFault i:nil="true" /> <TraceText i:nil="true" /> </OrganizationServiceFault>

Ama siz temel bir hata yönetim sinifina sahip olmak ve yazdiginiz butun kodlarda kullanmak isterseniz

su sekilde bir Exception mimarisini yazdiginiz kodda kullanabilirsiniz. Fakat burada unutmamaniz

gereken nokta siz hata fırlatmaz hatalari kendiniz Handle ederseniz CRM kullaniciya hata mesaji

göndermeyecektir. Bunun için InvalidPluginException’i siz firlatmalisiniz.

Asagidaki kodu Plug-in’ler içerisinde kullanmanizi pek tavsiye etmem cunku sistem gayet detayli bir

geri bildirim yapmakta ama bir hata aliyor ve isin içinden cikamiyorsaniz bu kodu denemenizde fayda

olabilir. Hatayi serverda ya da CRM içinde bir yerlere yazdırıp incelebilrisiniz. Yine uygun gordugunuz

bir yerde kullaniciya hata göstermek istiyorsaniz “InvalidPluginExecutionException” firlatmayi

unutmayin.

catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> ex)

Page 46: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

45 | P a g e

{ Console.WriteLine("The application terminated with an error."); Console.WriteLine("Timestamp: {0}", ex.Detail.Timestamp); Console.WriteLine("Code: {0}", ex.Detail.ErrorCode); Console.WriteLine("Message: {0}", ex.Detail.Message); Console.WriteLine("Inner Fault: {0}", null == ex.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault"); } catch (System.TimeoutException ex) { Console.WriteLine("The application terminated with an error."); Console.WriteLine("Message: {0}", ex.Message); Console.WriteLine("Stack Trace: {0}", ex.StackTrace); Console.WriteLine("Inner Fault: {0}", null == ex.InnerException.Message ? "No Inner Fault" : ex.InnerException.Message); } catch (System.Exception ex) { Console.WriteLine("The application terminated with an error."); Console.WriteLine(ex.Message); // Display the details of the inner exception. if (ex.InnerException != null) { Console.WriteLine(ex.InnerException.Message); FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault> fe = ex.InnerException as FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>; if (fe != null) { Console.WriteLine("Timestamp: {0}", fe.Detail.Timestamp); Console.WriteLine("Code: {0}", fe.Detail.ErrorCode); Console.WriteLine("Message: {0}", fe.Detail.Message); Console.WriteLine("Trace: {0}", fe.Detail.TraceText); Console.WriteLine("Inner Fault: {0}", null == fe.Detail.InnerFault ? "No Inner Fault" : "Has Inner Fault"); } } }

Plug-in Yapici Metodlari

Bir plug-in için Microsoft Dynamics CRM’de opsiyonel olarak kullanabileceğiniz yapici

metod(constructor) türleri mevcuttur. Hic parametre vermeden yapici metod cagirabileceginiz gibi

bir ya da iki parametre vererek de cagirabilirsiniz.

SamplePlugin isimli plug-in için 3 cesit yapici metod ornegi asagidaki gibidir.

public SamplePlugin() public SamplePlugin(string unsecure)

Page 47: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

46 | P a g e

public SamplePlugin(string unsecure, string secure)

Yapici metodun ilk parametresi public yani unsecure bilgi yigini içermelidir. Ikinci parametre ise non-

public (secure) bilgi yigini içermelidir. Buradan da anlayabileceğiniz uzere secure string encrypted

yani sifrelenmis veri unsecure ise unencrypted yani sifrelenmemis değer içermelidir. Office Outlook

client da calisan bir plug-in yazdiysaniz bilmelisiniz ki secure string offline yani cevrimdisi modda

calismayacaktir.

Bu bilgileri bir plug-in’e Plugin Registration Tool vasitasiyla bir step’in kaydi sirasinda sisteme

iletiyoruz. Bu mesajlar için ayrilmis 2 alan bulanmaktadır.

Step içerisinde bu ayarlamalari yaptıktan sonra yazmis olduğumuz degerlere kod içerisinden asagidaki

gibi ulaşabilirsiniz.

private readonly string _unsecureString; private readonly string _secureString; public AdvancedPlugin(string unsecureString, string secureString) { if (String.IsNullOrWhiteSpace(unsecureString) || String.IsNullOrWhiteSpace(secureString)) { throw new InvalidOperationException ("Unsecure and secure strings are required by the Advanced Plug-in, but not provided."); } _unsecureString = unsecureString; _secureString = secureString; }

Page 48: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

47 | P a g e

Hadi Plug-in Yazalim Plug-in’ler hakkında temel bilgileri öğrendiğimize gore artik plug-in yazabiliriz. Asagida vereceğim

orneklerde bir plug-in içerisinde yapabileceğiniz temel işlemleri anlatmaya calisacagim. Bu kodlara

CRM SDK\SampleCode\CS\Plug-ins içerisinden ulaşabilirsiniz.

Veritabanina gitmeden kayitlari değiştirmek Daha once de ifade ettiğim gibi CRM içerisinde bir kayit veritabanina gitmeden Pre-Operation(Pre-

Event) adiminda kaydettiğiniz bir plug-in ile kullanicinin oluşturmak istediği kayda ulaşabilirsiniz.

Asagidaki kod oluşturulan bir account(firma) nesnesinin içerisine eger yok ise bir numara oluşturarak

bunu accountnumber(müşteri numarasi) alanina vermekte böylece kayitta olmayan bir alan

veritabanina bu alan eklenmiş bir sekilde gidecek.

Kodda da görebileceğiniz uzere ilk once Execute metodumuzu oluşturuyoruz. Biliyorsunuz ki bu

metod parametre olarak içine aldigi ServiceProvider ile bize ihtiyacimiz olan butun verileri sunacak.

Ilk once Context’i ServiceProvider’dan türetiyoruz. Daha sonra da Context içerisindeki Target’in bir

Entity mi olup olmadigina bakıyoruz. Tam bu noktada gelin Context nesnesinin içerisine bir bakalim.

Asagidaki ekran goruntusunu bu plug-in’i debug ettiğim anda aldim. Ilerleyen bölümlerde bir plug-

in’in nasil debug edileceğini anlatacagim. Simdilik Context’e odaklanalim.

Gorebileceginiz uzere Context UserId, BusinessUnitId, MessageName, PrimaryEntityName,

CreatedOn gibi o anda isimize yarayacak birçok veri yiginini içermekte. Iste Plug-in içerisinde

ihtiyacimiz olanlari buradan alip kullanacagiz.

Page 49: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

48 | P a g e

Entity ise onu entity sinifindan bir nesne haline getiriyoruz.

Bu sefer bu oluşturduğumuz yeni entity nesnesi account turunden bir nesne midir diye bakıyoruz.

Daha sonra Icinde accountnumber diye bir alan var mi diye bakıyoruz. Yoksa iste tam bu noktada

veritabanina doğru yolculuğa cikmis olan kullanicinin bu kaydına müdahale edip içerisine bizim

urettigimiz numara ile accountnumber nesnesini doldurarak entity mize veriyoruz. Artik içerisinde

accountnumber alani da var.

/// <summary> /// A plug-in that auto generates an account number when an /// account is created. /// </summary> /// <remarks>Register this plug-in on the Create message, account entity, /// and pre-operation stage. /// </remarks> //<snippetAccountNumberPlugin2> public void Execute(IServiceProvider serviceProvider) { // Obtain the execution context from the service provider. Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext) serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));

Page 50: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

49 | P a g e

// The InputParameters collection contains all the data passed in the message request. if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity) { // Obtain the target entity from the input parameters. Entity entity = (Entity)context.InputParameters["Target"]; //</snippetAccountNumberPlugin2> // Verify that the target entity represents an account. // If not, this plug-in was not registered correctly. if (entity.LogicalName == "account") { // An accountnumber attribute should not already exist because // it is system generated. if (entity.Attributes.Contains("accountnumber") == false) { // Create a new accountnumber attribute, set its value, and add // the attribute to the entity's attribute collection. Random rndgen = new Random(); entity.Attributes.Add("accountnumber", rndgen.Next().ToString()); } else { // Throw an error, because account numbers must be system generated. // Throwing an InvalidPluginExecutionException will cause the error message // to be displayed in a dialog of the Web application. throw new InvalidPluginExecutionException("The account number can only be set by the system."); } } } }

Umarim birsey dikkatinizi çekmiştir. Entity içerisine direkt alani Attributes.Add metodu ile ekliyoruz.

Yani bir update işlemi yapmıyoruz zaten kayit daha veritabanina gitmedi doğal olarak CRM Service

nesnesinin bir instance’ini olusturmamiza da gerek kalmadi.

Update aninda update edilmemiş değerlere ulaşmak Baslik biraz karisik gelebilir ama aslinda tam olarak da durum bu update aninda update edilmemiş

alanlara ulaşmak istiyorsaniz birazdan bahsedecegim yöntemi uygulamniz gerekmekte. Peki biz neye

neden ulasamiyoruz diye soracak olursaniz aciklayayim. Dynamics CRM’in Create aninda kayit ile ilgili

elde ettiği butun bilgileri bize Target’tan türettiğimiz entity içerisinde verir. Asagidaki ekran

goruntusunde de bu durumu görebilirsiniz.

Page 51: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

50 | P a g e

Update aninda durum bundan farkli sistem bize sadece (doğal olarak) update edilmiş alanlari

vermektedir. Asagidaki ekran goruntusune bakabilirsiniz.

Ben bu contact üzerinde sadece jobtitle alanini güncelledim. Sistem jobtitle ve yaninda ihtiyaç

duyulacak birkaç bilgiyi daha Target’a vermekte o kadar.

Simdi konu basligina dönecek olursak iste tam bu update aninda ben update edilmemiş bir alanin

değerine ulaşmak istersem ne yaparim? Sistemde bunun için Image yani o kaydin o anki snapshot’ini

almamizi sağlayan bir ozellik var.

Herhangi bir plug-in step’i üzerinde sag tuşa basarak “create new image” seçeneğini seçtiğimizde

asagidaki ekran karsimiza gelecektir.

Page 52: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

51 | P a g e

Bu ekranda Pre ve Post olarak istediğimiz alanlari parametre olarak seçebilir ve bunlara genel bir isim

verebiliriz. Ben Target dedim.

Iste bu ayarlamayi yapdiginizda asagidaki ekran goruntusundeki gibi update aninda değişmeyen ama

sizin erişmek istediğiniz alan/alanlar PreEntityImages içerisinde hazir olacaktır.

Page 53: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

52 | P a g e

Hangi Message’da hangi image’lara ualasabileceginizin listesi asagidaki gibidir.

Mesaj Stage Pre-Image Post-Image

Create PRE Hayir Hayir

Create POST Evet Evet

Update PRE Evet Hayir

Update POST Evet Evet

Delete PRE Evet Hayir

Delete POST Evet Hayir

Peki kod tarafında buna nasil ulasacagiz derseniz o da su sekilde olacak;

Once image nesnesine ulaşıyoruz:

Entity image = (Entity)context.PreEntityImages["Target"];

Sonra image içerisinden istediğimiz alana erişiyoruz:

String descriptionMessage = "Old full name: " + image["fullname"];

Uzerinde calistigim nesnenin id’si nerede? Update edilmis ya da post-operation durumdaki bir nesnenin id’sine ihtiyaç duyarsaniz su sekilde elde edebilirsiniz: Guid id = new Guid(context.OutputParameters["id"].ToString()); Ya da Guid id = context.PrimaryEntityId;

Plug-in’ler arasinda bilgi paylasimi Eger bir plug-in içinde oluşturduğumuz bir veriyi diğer plug-in’lerin de erişmesini istiyorsak “SharedVariables” yapisini kullanmamiz gerekmekte. SharedVarabiles aslinda bir parametre kolleksiyonu ve içerisinde paylaşmak istediğiniz nesneleri saklayabilirsiniz. Asagida 2 tane plug-in yer almakta. Ilk plug-in (PreEventPlugin) context.SharedVariables.Add("PrimaryContact", (Object)contact.ToString());

Page 54: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

53 | P a g e

Kodu ile Contact isimli Guid nesnesini “PrimaryContact” adinda SharedVariables içerisinde saklamakta. Ikinci plug-in ise Post-event aninda calismakta ve SharedVariables’den istediği değeri örnekteki gibi almaktadır. Boylece plug-inler arasi veri transferi ve yapilmis olmakta. Guid contact = new Guid((string)context.SharedVariables["PrimaryContact"]);

public class PreEventPlugin : IPlugin { public void Execute(IServiceProvider serviceProvider) { // Obtain the execution context from the service provider. Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext) serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext)); // Create or retrieve some data that will be needed by the post event // plug-in. You could run a query, create an entity, or perform a calculation. //In this sample, the data to be passed to the post plug-in is // represented by a GUID. Guid contact = new Guid("{74882D5C-381A-4863-A5B9-B8604615C2D0}"); // Pass the data to the post event plug-in in an execution context shared // variable named PrimaryContact. context.SharedVariables.Add("PrimaryContact", (Object)contact.ToString()); } } public class PostEventPlugin : IPlugin { public void Execute(IServiceProvider serviceProvider) { // Obtain the execution context from the service provider. Microsoft.Xrm.Sdk.IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext) serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext)); // Obtain the contact from the execution context shared variables. if (context.SharedVariables.Contains("PrimaryContact")) { Guid contact = new Guid((string)context.SharedVariables["PrimaryContact"]); // Do something with the contact. } } }

Page 55: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

54 | P a g e

Plug-in Registration Tool’u Kullanmak Ilk plug-in’imizi yazdıktan sonra geldi onu CRM içerisine eklemeye. Bu işlem için Plugin Registration Tool dediğimiz CRM SDK içerisinden cikan bir uygulamayi kullanacagiz. Bu uygulama sayesinde hem plug-in hem de custom workflow’lari CRM içerisine ekleyebilmekteyiz. SDK\Tools\PluginRegistration\PluginRegistration.exe yolu ile ulaşabileceğiniz uygulamayi calistirdiginizda sizden bağlanmak istediğiniz server ile ilgili bilgileri isteyecektir. Dynamics CRM Online için Online’i seçebilirsiniz ama unutmayin ki Office 365 hesabi kullaniyorsaniz Office 365’i seçmeniz gerekmekte. Ikisi de Online ama yetki mekanizmaları farkli.

Eger On-Premises yani Microsoft disinda host edilen bir CRM’e erişmek istiyorsaniz o zaman On-Premises seçeneğini seçmeniz gerekmekte. IFD’ler için de bu seçeneği kullanabilirsiniz.

Page 56: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

55 | P a g e

Eger “Always display list of available orgs” seçeneğiniz seçerseniz bağlanmak istediğiniz kullanici ile erişebileceğiniz organizasyonlarin listesini görüntüleyebilirsiniz. Basarili bir sekilde giriş yaptiginizda asagidaki gibi bir ekran karsiniza gelecektir.

1. Plug-in’i sisteme kayit edebilmek için yukarıdaki “Register” düğmesine tikliyoruz ve ardindan “Register New Assembly” ‘ ye tikliyoruz.

Page 57: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

56 | P a g e

2. Step#1 bolumundeki … düğmesine tikliyarak kayit ettirmek istediğimiz .dll’i seçiyoruz. 3. Step#2 bolumunde kaydetmek istediğimiz plug-in class’ini seçiyoruz. 4. Step#3 bolumunde 2 tane seçeneğimiz bulunmakta;

a. Sandbox : Bu seçeneği seçer isek plug-in bir Sandbox içerisinde calisacak yani dis ortamdan izole edilecek. Boylece bu plugin sistem içerisinde calisacak ama sisteme zarar veremeyecek ve izlenebilir olacak. Kisacasi yazdiginiz bir plug-in production ortamina tasimadan once test etmek için bu senecegi kullaniyoruz.

b. None : hiçbir kisitlama olmadan .dll içerisindeki kodlar icra edilir. 5. Step#4 bolumunde ise plug-in nerede duracagini seçmemizi istemekte.

a. Database: tavsiye edilen yöntem budur. Boylece dll işletim sistemi kaynakli sorunlardan izole edilir. Veritabani yedeklendikçe dll de içinde olduğundan yedeklenecektir ve herhangi bir durumda geriye dönmenizi sağlar.

Page 58: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

57 | P a g e

b. Disk: Sistemin varsayilan dll yerleştirme yeri olan CRM Kurulum Yolu\Server\bin\assembly klasörü içerisinden dll’i okur. Her bir server icin dll’lerin belirtilen klasöre konmasi gerekmektedir.

c. GAC: Global Assembly Cache üzerinden dll’leri okur. Bu noktada bir not ileteyim eger server üzerinde calisan kodu debug etmek isterseniz yine server\bin\assembly klasörüne .pdb uzantili debug symbol’lerinizi yerleştirmeniz gerekmekte. Ikinci bir not da eger serverda custom code execution kapaliysa açmak için server üzerinde powershell ile su kodlari calistirmaniz gerekmekte: Add-PSSnapin Microsoft.Crm.PowerShell $setting = get-crmsetting customcodesettings $setting.AllowExternalCode="True" Degerleri kontrol etmek için bu komutlari calistirabilirsiniz : set-crmsetting $setting get-crmsetting customcodesettings Ayarlari tersine çevirmek için “AllowExternalCode”’a “False” değerini vermeniz yeterli. Butun bu adimlari tamamladıktan sonra “Register Selected Plugin” düğmesine tikliyoruz. Plug-in kaydetmediki ilk adimi gerçekleştirmiş olduk sira diğer adimlarda :) Bu noktada plug-in’i hangi event(ler) için yazdiysak onun için adim(lar) eklememiz gerekiyor. Plug-in anlatirken hep bir olay olduğunda yani veritabanina bir kayit eklendiğinde, silindiğinde ya da bir alani güncellendiğinde tetiklenebilir gibi orneklerle anlatıyoruz ama aslinda olay bundan daha derin gelin simdi custom entity’ler için yani bizim oluşturduğunuz varliklar için sistem üzerinde nasil olaylarin tetiklenmelerini yakalayabiliyoruz. Literaturde bu konu message olarak geçmekte yani CRM eventlarina mesaj adi verilmekte.

Message Name Ownership

Type

Message

Availability

Entity

Supported

Deployment

Assign User-owned

entities only

Server Server

Create User-owned

and

organization-

owned entities

Both Server

Delete User-owned

and

organization-

owned entities

Both Server

Page 59: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

58 | P a g e

GrantAccess User-owned

entities only

Server Server

ModifyAccess User-owned

entities only

Server Server

Retrieve User-owned

and

organization-

owned entities

Both Server

RetrieveMultiple User-owned

and

organization-

owned entities

Both Server

RetrievePrincipalAccess User-owned

entities only

Both Server

RetrieveSharedPrincipalsAndAccess User-owned

entities only

Both Server

RevokeAccess User-owned

entities only

Server Server

SetState User-owned

and

organization-

owned entities

Both Server

SetStateDynamicEntity User-owned

and

organization-

owned entities

Both Server

Update User-owned

and

organization-

owned entities

Both Server

Listede de yer aldigi gibi Retrieve, RetrieveMultiple yani veritababindna sorgulama ya da SetState yani bir kaydin durumun değişmesi gibi birçok farkli mesaj için plug-in’i tetikletebilmekteyiz.

Page 60: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

59 | P a g e

Lutfen sunu unutmayin yukarıdaki liste sadece custom entity’ler için campaign, campaignactivity, list gibi entity’ler için farkli mesajlar da mevcut tum listeye SDK içindeki “Message-entity support for plug-ins.xlsx” isimli dosyadan ulaşabilirsiniz. Simdi yeni bir adim ekleyerek bir mesaj için plug-in’imizin tetiklenmesini saglayalim. Bunun için plug-in üzerinde sag tuşa tıklayarak ya da yukarıdaki “Register” düğmesine tıklayarak acilan menüden “Register New Step”’e tikliyoruz. Karsimiza asagidaki gibi bir pencere cikacak:

Message: Yukarida bahsettigim mesajlardan birini buraya yazabilirsiniz. Hangi mesaji yazarsaniz plug-in bu olay icin calisacak. Create/Update gibi mesaj isimleri yazarken otomatik olarak tamamlamaya calistigini göreceksiniz. Her bir mesaj icin ayri step’ler tanimlaniz gerekmektedir. Primary Entity: Bu plug-in hangi entity yani varlik üzerinde calisacak. Buraya account, contact gibi bir varlik adi yazabilirsiniz. Secondary Entity: Bu plug-in’i ikinci bir varlik icin tanıtacaksak buraya yazabiliriz. Event Pipeline Stage of Execution: Bu kisimda plug-in’i pre yani veri veritabanina gitmeden mi calistiracagiz yoksa post yani kaydedildikten sonra mi calistiracagiz bunu seçiyoruz. Execution Mode: (sadece post da ikisinden birini seçebilmekteyiz) kod senkron yani sistemde kullanici ile etkileşimli ayni anda mi hareket etsin yoksa asenkron yani kullanicidan bagimsiz arka tarafta sessizce mi calissin bunu seciyoruz. Deployment: Bu kod server da mı calissin yoksa Outlook client gibi offline modda da calissin seçeneğidir. Bu yukarida acikladigim bolumler standart ayarlar. Yani her plug-in step’i tanimladigimizda mutlaka bakmamiz gereken ayarlar. Ekranda bir de farkli ayarlar var onlara da bakalim. Event Handler: Bu kodun calismaya baslayacagi class’in seçildiği yerdir. Cok değişik bir hareket yapmadiginiz surece zaten plugin registration tool otomatik bir sekilde “Execute” metodunu görecek ve orayi seçecektir. Name: Sistem bu step icin otomatik bir atamakta ama değiştirmek isterseniz buradan yapabilirsiniz.

Page 61: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

60 | P a g e

Run in User’s Context: Belki dokunmaniz gereken noktalardan biri olabilir. Bu kodu hangi kullanici yetkileriyle calistirmak istiyorsaniz onu seçebilirsiniz. Standartta ayari “Calling User” yani hangi kullanici bu işlemi yaparsa seçilidir. ExecutionOrder: eger ayni varlik içinde ve ayni mesaj icin başka bir plug-in daha varsa buraya sira numaralari vererek hangisini once-sonra calisacagini belirleyebilirsiniz. Unsecure ve Secure Configuration’larin ne ise yaradigina zaten “Plug-in Yapici Metodlari” basligi altinda değinmiştim. Butun gerekli ayarlamalari yaptıktan sonra en allta bulunan “Register New Step” düğmesine tıklayarak işlemi tamamlıyoruz. Artik plug-in’i test edebilirsiniz.

Plug-in’i Debug Etmek CRM 2015 icerisinde yazmis olduğumuz bir plug-in’i debug etmenin iki temel yolu bulunmakta. Birinci yol calisan sisteme visual studio ile attach olarak yapilan, ikinci yol ise plug-in profiller kullanmak. Profiller icin Microsoft dokümantasyonlarda plug-in performansini ölçmek icin kullaniliyor dese de aslinda 1. Yöntemden daha saglikli olduğunu söyleyebilirim. Ozellikle Online sistemler icin başka çareniz de yok zaten.

Servis’lere Attach olarak Debug Etme Plug-in’i sisteme kaydettikten sonra visual studio ile nereye attach olacagimizi seçmemiz gerekmekte.

Kayit Ayari Servis

online w3wp.exe

offline Microsoft.Crm.Application.Hoster.exe

asynchronous olarak kaydedilmis plug-

in’ler (ya da custom workflow’lar)

CrmAsyncService.exe

sandbox (isolation mode) Microsoft.Crm.Sandbox.WorkerProcess.exe

Online : CRM Web arabirimini Offline : Outllok Client gibi offline yapidaki yazilimlar Kendimize uygun olan secimi yaptıktan sonra geriye bir tek breakpoint’i seçip attach olmak kaliyor. Visual Studio’yu acip “Attach to Process..” diyoruz.

Page 62: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

61 | P a g e

Sonra asagidaki ekran goruntusu gelecek ve ilgili servisi seçeceğiz.

Asagidaki ekran goruntusunde de goruldugu uzere visual studio ilgili yerde devreye girecek ve bizim kodu debug etmemizi saglayacaktir.

Page 63: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

62 | P a g e

Islem bu kadar basit sadece dikkat etmeniz gereken noktalar bulunmakta;

1. Eger disk’e yaz adimini seçerek plug-in’i sisteme kayit ettiyseniz bu plug-in’in debug modda yeni bir versiyonunu ayni dizine kopyalamak icin plug-in üzerinde calistigi servisi yeniden baslatmaniz gerekir.

2. Plug-in üzerinde değişiklikler yaptiginizda her seferinde registration tool’u ile güncelleme islemini yapin.

3. Eger plug-in’i bu sekilde test edip butun işlemleri bitirdiyseniz onu veritabanina kaydetmenizi tavsiye ederim. Disk olarak birakmaniz pek önerilen bir yöntem değildir.

4. Her ne olursa olsun .pdb uzantili dosyalari assembly klasörü içerisinde birakmayin. 5. Sandbox içindeki bir plug-in’i debug etmek istiyorsaniz asagidaki registery ayarinin 1

(DWORD) değeri tasidigindan emin olun : HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\MSCRM\SandboxDebugPlugins

Plug-in Profiller’i kullanarak Debug etme Bu yöntemi kullanmak birçok bakimdan daha avantajli nedeni ise CRM size kullanicinin yaptigi hareketi simule ediyor ve böylece siz bunun üzerinden debug ediyorsunuz. Ayrica ciktilari baskalarina gönderme opsiyonu da bulunmakta. En değerli ozelligi ise plug-in’i derleyip derleyip CRM’e atmak gibi bir derdiniz yok. Yani bir hata mi yakaladiginiz ya da kodun bir yerini mi değiştirmek istiyorsunuz tek yapmaniz gereken degisikligi yapip uygulamaya yeniden bağlanmak ayni kullanici hareketi tekrar simule edilecek ve siz de yaptiginiz degisikligin etkilerini göreceksiniz. Simdi sirasiyla bu işlemi nasil yapacagimiza bakalim. Oncelikle “Plug-in Registration Tool”’u aciyoruz ve işlem yapmak istediğimiz organizasyonu seçiyoruz. Tool üzerindeki “Install Profiller” düğmesine tikliyoruz. Boylece “Plug-in Profiller”’da listemizde gozukmeye basliyor. Daha sonra test etmek istediğimiz step’i seçiyoruz ve yine toolbar’da yer alan “Start Profilling” düğmesine basıyoruz. Karsimiza asagidaki gibi “Profiler Settings” ekrani cikiyor.

Page 64: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

63 | P a g e

Bu adimda iki secenekten birini seçmeniz lazim.

Exception: Microsoft, Exception yöntemini önermekte gordugunuz gibi. Bunun anlami ise su kullanici ya da siz plug-in’i tetikledeginizde plug-in calisacak ve sistem size bir hata mesaji gösterecek. Bu hata mesaji içerisinde plug-i debug etmemize yarayacak bilgiler yer alacak. Bu bilgileri almak icin cikan hata penceresinde “Download Log File” düğmesine basmaniz gerekmekte.

Persist to Entity: Eger ikinci adimi seçerseniz bu sefer butun bilgiler CRM içerisinde bir Entity içerisine yazılacak.

Iki adimdan birini seçip plug-in’i tetikleyecek işlemi yaptıktan sonra “Plug-in Registration Tool” içerisinde “Debug” düğmesine tiklamaniz gerekmekte.

Page 65: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

64 | P a g e

Karsiniza asagidaki gibi bir ekran gelecek. Bu ekran bir önceki seçtiğiniz adima gore iki işlemden birini yapmaniz gerekmekte; Eger “Exception” adimini seçtiyseniz “…”’ya basarak kaydetmiş olduğunuz hata dosyasinin yerini gösterin. Eger “Persist To Entity” adimini seçtiyseniz asagi doğru duran ok düğmesine basiniz. Karsiniza soyle bir ekran cikacak;

Page 66: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

65 | P a g e

Bu ekrandan kaydettiğiniz profile log’unu seçebilirsiniz. Sonra sirasiyla .dll dosyanizi sisteme gösterin ve debug etmek istediğiniz Plug-in’i secin. Visual Studio’yu acin ve “PluginRegistration.exe” uygulamasina attach olun. Start Execution dugmesina basin ve breakpoint koyduğunuz yerde bekleyin. Bir sure sonra Visual Studio’a beklediğimiz yere gelecek ve bizim debug etmemizi sağlayacak.

Page 67: Dynamics CRM 2015 Kodlama Mimarisi v1.0 · 2020-01-28 · Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA 3 | P a g e Yazar Hakkinda Yaklasik 15 yildir profesyonel olarak

Dynamics CRM 2015 Kodlama Mimarisi v1.0 - Baris KANLICA

66 | P a g e

Eger plug-in’de değişiklik yapmaniz gerekiyorsa değişiklikleri yapin ama CRM’e atmayin ilk once biraz önceki adimlari uygulayarak kodu tekrar test edin. Artik koddan eminseniz CRM içerisine gönderebilirsiniz güncellediğiniz .dll’i. Bu arada belirtmeliyim ki asagida “plug-in traces” bolumunden de debug etmeden kodun nasil calistigini izleyebilirsiniz.

Burada icin TracingService ile yazacaginiz mesajlar görüntülenecektir.