Xrm.Sdk.Messages.ExecuteMultipleRequest
Merhaba,
Bu yazıda Dynamics 365 CE (CRM) SDK ‘da Microsoft.Xrm.Sdk.Messages
namespace altında yer alan ExecuteMultipleRequest
mesajını detaylı olarak inceleyeceğiz.
ExecuteMultipleRequest
, Dynamics 365 CE üzerinde tek bir seferde birden fazla işlem (bulk operation) yapmamıza imkan sağlayan bir yapıdır.
Genel olarak, Dynamics 365 sistemine data aktarımı (migration / integration) gibi performans gerektiren işlemlerde kullanmaktayız, fakat bulk işlem yapmak istediğiniz herhangi bir aşamada kullanabiliriz. Toplu işlemlerde (bulk operation) client – server arasında network akışını (round trip) en aza indirmek amacıyla Dynamics 365 CE (CRM) SDK ‘a eklenmiştir.
Internette kolayca bulabildiğiniz örneklerin aksine sadece Create, Update, Delete gibi operasyonlar ile değil, aynı zamanda RetrieveMultipleRequest
gibi data okuma amaçlı işlemler için de kullanılmaktadır. Requests
parametresi OrganizationRequest
‘den türetilmiş bütün Dynamics 365 SDK mesajlarını kabul etmektedir, fakat bu konuda ufak bir istisna bulunmaktadır, detayları limitasyonlar başlığında detaylı olarak anlatacağım.
ExecuteMultipleRequest Nasıl Çalışır?
.NET tarafında kod örneklerine geçmeden önce ExecuteMultipleRequest
‘in çalışma mantığından bahsetmekte fayda var. Yukarıda bahsettiğim gibi OrganizationRequest
‘den türetilmiş bütün Dynamics 365 SDK mesajlarını kabul eden ve collection (list) olarak data alan Requests
parametresi bulunmaktadır. Bu sayede limitasyonlar dahilinde istediğimiz kadar request bilgisini bu listeye ekleyebiliriz.
Settings
parametresi ise ExecuteMultipleSettings
tipinde bir değer almaktadır. Bu parametre sayesinde ilgili işlemin çalışma zamanında (run-time) nasıl tepki vereceğini istediğimiz gibi belirleyebiliyoruz.
ExecuteMultipleRequest
‘in dönüş tipi ExecuteMultipleResponse
‘dir. Mevcut işlem için detayları içeren IsFaulted
ve Results
isimli 2 parametresi mevcuttur.
ExecuteMultipleRequest, paket içinde bulunan herhangi bir işlemde hata meydana geldiğinde exception oluşturmaz, bunun yerine IsFaulted değeri TRUE olarak döner ve Results içinde hatalı kaydın bilgisi yer alır.
İşlem sonrasında oluşan cevaplar ise Results
parametresi içinde yer almaktadır. Settings
parametresinde vermiş olduğumuz ayarlara göre bu parametrenin dönüş değerlerini içerip içermemesi değişkenlik göstermektedir.
Unutmamamız gereken önemli bir nokta, IsFaulted değeri TRUE olduğunda, Settings parametresinde vermiş olduğumuz değerlerden bağımsız olarak Responses parametresi mutlaka hatalı kayıtları içerir.
ExecuteMultipleRequest
‘i çalıştırabilmek için IOrganizationService
interface ‘in Execute
metodunu kullanmaktayız.
ExecuteMultipleRequest
, OrganizationService
oluşturduğumuz (ya da Impersonate yaptığımız) kullanıcının context bilgisi ile işlem yapar, dolayısıyla Requests
parametresi içinde yer alan tüm işlemler bu kullanıcının yetkisine göre çalıştırılacaktır. CreatedBy
, ModifiedBy
gibi alanlar bu kullanıcı bilgisini içerecektir. Eğer herhangi bir işlem için yetkisi yoksa ilgili işlem için hata oluşacaktır.
ExecuteMultipleSettings
ContinueOnError
ve ReturnResponses
isimli boolean (True / False) değer alan 2 parametreye sahip olan bu yapı ile ExecuteMultipleRequest
‘in çalışma zamanında nasıl davranacağını belirlemekteyiz.
ReturnResponses
parametresi, paket içinde yer alan request (OrganizationRequest
) ‘ler için response bilgilerinin (OrganizationResponse
) dönmesini sağlar. Eğer Requests
içinde CreateRequest
işlemleri varsa ve oluşan kayıtların Id bilgilerini alıp başka bir sisteme kaydetmek ya da log olarak yazmak istiyorsak bu parametreye TRUE değer vermeliyiz.
Bazı kaynaklarda ReturnResponses
bilgisinin TRUE olarak atanması performans kaybı oluşturduğu yönünde yorumlar bulunmakta, açıkcası ben böyle bir test yapmadım. Elbette işlem sonuçlarına ihtiyacımız yoksa ya da operasyonel anlamda herhangi bir bilgi içermeyen (UpdateRequest
– UpdateResponse
gibi) isteklerimiz varsa bu bilgiyi TRUE olarak ayarlamak zaten gereksiz bir durum. Bu nedenle ihtiyacınıza en uygun şekilde değer atamanız mantıklı olacaktır.
ContinueOnError
parametresi, herhangi bir hata anında işlemin devam edip etmeyeceği bilgisini düzenlemektedir. TRUE gönderdiğimizde paket içinde yer alan işlemlerde herhangi bir hata meydana geldiğinde sıradaki işlem ile devam etmesini sağlarız. Bu sayede tüm paket bitinceye kadar işlemler devam eder. Eğer FALSE olarak değer atarsak paketin içinde oluşan ilk hata sonrasında işlem kesilir ve o ana kadar yapılmış tüm işlemler için cevap döner, hatalı kaydın sonrasında listede yer alan işlemler devam etmez.
ExecuteMultipleRequest ‘te yer alan her bir işlem kendi transaction yapısında işlenir. Herhangi bir hata olması durumunda sadece ilgili kayıt bazında rollback işlemi gerçekleşir. Hatalı kayıt öncesinde yapılan işlemlerde herhangi bir değişiklik, rollback işlemi söz konusu değildir.
Run-time Limitleri
ExecuteMultipleRequest
hem kendini ve hem de platformu korumak için belirli kısıtlamalar içermekte. Bu limitleri bilmek ve dikkate almak yazdığımız uygulamanın sorunsuz ve performanslı olarak çalışmasını sağlayacaktır.
Paket Kısıtlaması (MaxBatchSize)
İlk kısıtlama Requests
parametresine ekleyeceğimiz istek sayısı ile ilgili. ExecuteMultipleRequest
ile tek seferde en fazla 1000 istek içeren bir paket gönderebiliriz.
Eğer paketimiz 1000+ istek içeriyorsa, IOrganizationService.Execute
metodunu çalıştırdığımızda -2147220715 (Not Supported) hata kodu ile “ExecuteMultiple Request batch size exceeds the maximum batch size allowed!” hatası oluşacaktır. Oluşan hatanın paket sayısından kaynaklı olduğunu tespit etmek için dönen hata mesajını kontrol edebilir ya da hata detayında MaxBatchSize
anahtar kelimesini arayabiliriz. Bu hatayı detaylı olarak Hata Yönetimi başlığında inceleyeceğiz.
Elbette bu hatayı çok kolay bir yöntemle engelleyebiliriz. Elimizde bulunan istekleri 1000 ‘lik ya da daha düşük request bilgisi içerecek şekilde paketler halinde bölüp işlem yapabiliriz. Bunun için aşağıdaki gibi bir kod yapısı kullanabilirsiniz.
Kodda yer alan itemPerPackage
, ExecuteMultipleRequest
paketimizde her döngü için gönderilecek Request sayısını belirlemektedir. Örnek kodda 150 request olarak belirledim.
Recursion Kısıtlaması
Yazıya başlarken ExecuteMultipleRequest
‘in OrganizationRequest
‘ten türetilmiş tüm istekleri çalıştırabildiğinden bahsetmiştim. Bu konuda bir istisna bulunmakta.
Bir ExecuteMultipleRequest
isteği içinde başka bir ExecuteMultipleRequest
kullanamayız. Böyle bir işlem yaptığımızda yine exception oluşacaktır. Fakat bu durumda hatayı yakalamak ve tespit etmek için try-catch(FaultException<OrganizationServiceFault> fault){ }
bloğu yerine ExecuteMultipleResponse
‘in IsFaulted
parametresi TRUE olacaktır ve hata ilgili request için dönecektir.
Platform ve API Kısıtlamaları
Direkt olarak ExecuteMultipleRequest
ile ilgili olmasa bile bizim işlerimizi etkileyebilecek diğer hatalar için platform API limitlerinin detaylı olarak yer aldığı dokümantasyona bakmanızı öneririm. Bu hatalardan biri oluştuğunda uygulama direkt olarak hata oluşturur, eğer uygulamamızda try-catch varsa catch(FaultException<OrganizationServiceFault> fault){ }
bloğu ile oluşan hatanın detayını yakalayabiliriz.
Plug-in ya da Workflow Assembly ‘lerde ExecuteMultipleRequest Kullanımı
Microsoft, custom plug-in ya da workflow assembly ‘ler içinde işlem yaparken ExecuteMultipleRequest
kullanmamızı öneriyor. Bunun yerine bu tarz işlemlerde bir döngü içinde işlem yapmamız daha sağlıklı olacaktır.
Detaylar için https://docs.microsoft.com/en-us/powerapps/developer/data-platform/best-practices/business-logic/avoid-batch-requests-plugin adresine bakabilirsiniz.
ExecuteMultipleRequest Hata Yönetimi
Uygulamamızda herhangi bir kural ihlali yoksa ya da akışımız ile ilgili olarak farklı bir hata mevcut değilse ExecuteMultipleRequest
kullanımında herhangi bir exception fırlatılmaz, diğer bir değişle try-catch ‘e normal şartlar altında ihtiyaç duyulmaz. Hata yönetimi ExecuteMultipleResponse
‘in IsFaulted
parametresi kontrol edilerek yapılmaktadır. Bu parametre TRUE dönüyorsa işlemlerin birinde ya da birkaçında hata meydana gelmiştir. FALSE ise tüm işlemler başarılı bir şekilde tamamlanmış demektir.
Limitasyonlar başlığı altında yer alan kısıtlamaların ihlal edilmesi ihtimaline karşı kodumuzun içinde try-catch (FaultException<OrganizationServiceFault> fault)
bloğu kullanmakta fayda var.
Aşağıdaki örnek kod yapısını kullanarak ExecuteMultipleRequest
yapısında hataları yakalayabilir ve hatalı kayıtları kolayca tespit edebilirsiniz. Bu kod genel olarak bir exception oluşmadığı zaman kullanabileceğimiz yapıdır.
Limitasyonlar ya da farklı bir hata nedeniyle oluşan hataları yakalamak için aşağıdaki gibi bir try-catch yapısı kullanabilirsiniz. Örnek kodda MaxBatchSize hatasını tespit edebilmek için Microsoft ‘un önerdiği şekilde hata detayı içinde MaxBatchSize anahtar kelimesini arayarak hem hata tespiti yapıyoruz hem de ilgili Instance (Organization) için geçerli olan MaxBatchSize değerini elde ediyoruz.
.NET Projesi – Örnek Kod
Öncelikli olarak projemize Microsoft.CrmSdk.CoreAssemblies
kütüphanelerini eklememiz gerekiyor. Eğer bu konu hakkında bilginiz yoksa daha önce hazırlamış olduğum detaylı yazıya göz atmanızda fayda var.
PL-400 Microsoft Power Platform Developer Sorusu (Bonus ;))
Geçtiğimiz günlerde PL-400 Microsoft Power Platform Developer (eski adı MB-400 Power Apps + Dynamics 365 Developer) sertifikası için sınava girdim. Sınavda aşağıdaki gibi bir soru ile karşılaştım, ayrıca bir çok arkadaşımdan benzer konu ile ilgili soru aldığım için örnek soruyu bu yazıya dahil etmek istedim.
Bu soru için dikkat etmemiz gereken en önemli nokta Settings
(ExecuteMultipleSettings
) parametreleri.
ContinueOnError
parametresiTRUE
, yani liste içinde herhangi bir hata olsa bir bir sonraki işlem ile devam edecekReturnResponses
parametresiFALSE
, bu durumdaExecuteMultipleRequest
içinde yer alan işlemler için (CreateRequest
,UpdateRequest
vb) herhangi bir sonuç dönmeyecek.
Bu bilgiler doğrultusunda cevaplar aşağıdaki gibi olacaktır;
The developer is able to get to the newly created accounts IDs
Developer, yeni oluşturulan kayıtların ID bilgilerini alabilir
Cevap HAYIR. ReturnResponses = false
olduğu için işlem bilgileri dönmeyecektir. Bu durumda yeni kayıtların ID bilgilerini elde edemeyiz.
If an error occurs, the developer can get access to the request that caused the fault
Eğer hata olursa Developer hatalı kayda erişebilir
Cevap EVET. ReturnResponses
parametresine bakılmadan, hatalı kayıtlar her durumda response içinde yer alır.
If there are errors in the request, the request will raise an exception at the first error and stop processing
Eğer hata meydana gelirse, ilk hatada exception fırlatılır ve işlem durdurulur
Cevap HAYIR. ContinueOnError = true
olduğu için işlemlerde hata oluşsa bile bir sonraki işlem ile devam eder
If there are ten errors in the 1000 CreateRequest requests, ten responses will be returned from the platform
Eğer 1000’lik pakette 10 hatalı işlem varsa, platformdan 10 cevap döner
Cevap EVET. İkinci soru ile benzer şekilde, hatalı kayıtlar her durumda response içinde yer alır. Bu durumda eğer 1000 istek içinde 10 adet hatalı kayıt mevcutsa response içinde bu hatalı kayıtları görürüz.
Kişisel Deneyimlerim ve Önemli Noktalar
Uzun bir yazının sonuna gelirken ExecuteMultipleRequest
yapısı ile ilgili bugüne kadar deneyimlediğim bazı önemli bilgileri de sizinle paylaşmak istiyorum.
1. İsteklerin (OrganizationRequest) Requests parametresine eklenme sırası
ExecuteMultipleSettings
ReturnResponses
parametresini TRUE olarak atamışsak, ExecuteMultipleRequest
işlemi tamamlandığında, Requests
parametresi içinde yer alan her bir item için ExecuteMultipleResponse
aynı sırada (Index
) bir response (OrganizationResponse
) ya da hata (Fault) datası içerir. Bu sayede başarılı ya da hatalı işlemler için bir akış planlayabiliriz.
Eğer yüksek data hacimleriyle çalışıyorsak ve uygulamamızda performans kazanmak için Requests
içine eklenecek işlemleri Parallel.Foreach
ya da Parallel.For
ile eklemişsek ve eklediğimiz sırayı takip etmediysek, maalesef response datasını okumamız ve hangi item için hangi response döndü tespit etmemiz zorlaşacaktır.
Bu nedenle ek bir kontrol mekanizması vb. oluşturmak yerine isteklerimizi normal şekilde for / foreach döngüsünde eklersek response ‘lar üzerinde çalışmamız daha kolay olacaktır.
2. Tek bir istekte gönderilecek olan request sayısı
Normal şartlar altında tek bir istek ile 1000 request ‘lik bir paket gönderip işlem yapabiliyoruz. Fakat bu sayı güçlü sunucular ve arka planda senkron plug-in ya da workflow olmayan durumlar için geçerli diyebiliriz.
Eğer herhangi bir işlem için arka planda farklı akışlarınız mevcutsa işlemler zaman alacağı için paket sayınızı düşürmenizde fayda var. Ben genelde 250 – 500 arasında bir değer seçiyorum, bu sayede hem Dynamics 365 tarafında oluşacak yükü azaltmış oluyorum hem de işlem yapmak istediğim data boyutunu kabul edilebilir bir zamanda bitiriyorum.
Elbette bu sayıyı çalıştığınız sistemin ve projenin gereksinimlerine göre bir kaç test yaparak çok rahatlıkla belirleyebilirsiniz.
3. Hata Senaryolarının Tespit Edilmesi ve Gerekli Akışların Oluşturulması
Belki de projelerde yaptığımız en sık hatalardan birisi ExecuteMultipleRequest
‘in hata senaryolarının düşünmemek ve bunlar için bir geliştirme yapmamak.
Daha önce belirttiğim gibi ExecuteMultipleRequest
içinde yer alan her bir request kendi transaction yapısına sahiptir ve diğer işlemleri etkilemez, bu nedenle tüm işlemler için geçerli bir rollback mekanizması yoktur. Eğer kritik süreçlerinizde ExecuteMultipleRequest
yapısını kullanıyorsanız hata ihtimallerini göz önüne alarak buna uygun akışlar oluşturmanızı öneririm.
Muhtemelen ExecuteMultipleRequest
için oluşturulmuş en kapsamlı yazı oldu 🙂 umarım faydalı olmuştur.
Dynamics 365 CE (CRM) SDK mesajları hakkında tüm yazılara tek nokta üzerinden ulaşmak isterseniz https://www.emregulcan.com/microsoft-xrm-sdk-messages adresine bakabilirsiniz.
Dynamics 365 CE (CRM) SDK konusunda ilgili tüm yazılara tek nokta üzerinden ulaşmak isterseniz http://www.emregulcan.com/dynamics365-sdk adresine bakabilirsiniz.