cub-e.net

just coding...

CRM 2011’de Create/Update/Delete Metodlarına Farklı Bir Bakış

Dynamics CRM'in iş dünyasının parlayan yıldızı olan ve her türlü iş platfomunun temeline yerleştirebilecek bir mimaride olduğunu her fırsatta anlatmaya çalışıyorum. Bu mimari üzerinde bizim kod geliştirmemizi ve sistem ile entegre olmamızı sağlayan web servisleri ve dll'ler vasıtasıyla yazma ve okuma işlemlerimizi gerçekleştirmekteyiz. Bugün sizlere daha önceden eski versiyonlar için de bahsetmiş olduğum oluşturma,  güncelleme ve silme metodlarının yapısını tekrar anlatacağım ama sonunda bunları Process isimli bir class'da birleştirip tek bir yerden yönetilmelerini sağlayacağız.

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 2011 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");
// 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)
        {
            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
                    + " : " + 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.

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 Created! 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)
            {
                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);
 
                DetailedLog.CreateLog("Entity Created! 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 :) 

Bütün bu işlemler sonunda tek bir noktadan yönetilebilir bir CRUD mimarisi yavaş yavaş ortaya çıkmakta. Sıra Okuma işlemlerinin detaylarına inmekte. Onu da artık başka bir makalede inceleyeceğiz.

Dynamics CRM Web Servisinin Çağrılmasında Singleton Tasarım Desenin Kullanılması

Aslında bu makalenin büyük bir kısmını 2009 yılında yazdım ama hatırlayamadığım bir nedenden dolayı o dönemde yarım kaldı ve unutuldu gitti. Şimdi fırsat buldum ve makaleyi tamamladım. (O zamanlar CRM 4.0 vardı şimdi kodları 2011 ve 2011'den sonraki versiyonlar göre uyarladım)

Bu makalemizde, programımızın yaşam döngüsü boyunca sadece bir Dynamics CRM Web Servisi bağlantısının hafızada yer almasını garanti altına almamızı sağlayacak olan Singleton tasarım desenini tanıyacağız ve bu iş için gerekli olan kodu geliştireceğiz.

Bildiğiniz üzere Dynamics CRM 2011 diğer CRM sürümleri gibi bir web uygulaması ve CRM üzerinde kendi yazılımlarımızı geliştirmek istiyorsak onun web servislerini kullanmamız gerekmektedir. Bu durumda IIS'in performansını da düşünmek zorundayız ve uygulamalarımızı buna göre geliştirmeliyiz. Uygulamamızda her işlem sırasında CRM web servisini çağırmak hem uygulamamızın hem de IIS'in gereksiz yere şişmesine neden olmaktadır. Ayrıca CRM servisi IOrganizationService türünden bir nesne ve bizim temel amacımız bu nesnenin hafızanda birden fazla kere oluşturulmasını ve oluşturma zahmetine girilmesini engellemek. Çünkü ben bu örnekte kodların içerisine gömmüş olsam dahi gerçek dünyada projelerde bizler servise bağlanılacak kullanıcı adı ve şifre gibi bilgileri .xml dosyaları gibi dosyalarda tutup buradan okumaktayız. Bir application life cycle içerisinde bu bilgileri okumak için çok sık I/O yaptırmak çok doğru bir işlem değil.

İşte bu durumda uygulamamız çalıştığı sürece açık kalacak ve bizim komutlarımızı icra edecek bir web servisi nesnesine ihtiyacımız olacaktır. Bunu Singleton Tasarım Deseniyle (Singleton Design Pattern) bunu sağlayabiliriz.

Singleton Tasarım Desenine geçmeden önce Tasarım Desenleri'nin ne olduğunu bilmeyenler için açıklayayım. Yazılım Mühendisliğinde içerinde ele alınan Tasarım Deseni (Design Pattern) kavramı, yazılım geliştirilirken sık meydana gelen sorunlara genel ve tekrar kullan��labilir çözümler bütünü olarak tanımlanabilir. Tasarım desenleri size direkt olarak kod üretmez sadece belirli bir problemin çözümüne mimari düzeyde sınıf ve method tasarımlarınızı oluşturmanızı sağlar. Herhangi bir kod parçacığı içermediği için programlama dilinden bağımsızdırlar. Kısaca Design Pattern koda çevrilebilecek tamamlanmış bir tasarım değildir, sorunun nasıl çözüleceğine dair bir modeldir. Tasarım desenleri test edilmiş, onaylanmış modeller sağlayarak yazılım geliştirme sürecini hızlandırabilirler. Tasarım Desenleri 3 kola ayrılırlar.

  • Creational Patterns (Yaratımsal Desenler) : nesnelerin ve sınıfların oluşturulması ile ilgili tasarım desenlerini içerir
  • Behavioral Patterns (Davranışlar Desenler) : sınıfların yapısal özelliklerinin belirlenmesi ile ilgili tasarım desenlerini içerir
  • Structural Patterns (Yapısal Desenler) : nesnelerin davranışsal özelliklerini ve bu davranışlara göre durumlarını yöneten tasarım desenlerini içerir

 

Yazılım geliştiriciler bazen programlarında özel olarak tasarım desenlerini kullanmasalarda aslında onlarda benzer yapılar kurarlar. Zaten tasarım desenlerine baktıkları zaman, "ya zaten ben bunu kullanıyordum.." gibi cümleleri de duymak mümkündür. Eminim benim burada anlatmaya çalışacağım Singleton Tasarım Desenini ve bu desendeki gibi CRM Web Servisine bağlanmayı yapmış arkadaşlar mutlaka vardır.

Şimdi "Creatinal Patterns" grubunda bulunan "Singleton" desenini açıklamaya başlayabiliriz. Singleton deseni bir programın yaşam süresince belirli bir nesneden sadece bir örneğinin olmasını sağlar. Bir uygulamada, tek bir yerden bu nesneye ulaşımın olması isteniyorsa bu desen kullanılabilir. Hatırlayacağınız üzere bir sınıftan yeni bir nesne oluşturmak için varsayılan yapıcı metodu(default constructor) çağırmak gerekir. C# dilinde bu işlemi new sözcüğünü kullarak yapmaktayız.

SınıfAdı olustrulacakNesne = new SınıfAdı();  //Normalde olması gerekn çağırma şekli

Bu şekilde yeni bir nesne oluşturmak için new anahtar sözcüğünün temsil ettiği yapıcı metoduna dışarıdan erişimin olması gerekir. Yani yapıcı metodun public olarak bildirilmiş olması gerekir. Ancak "Singleton" desenine göre belirli bir anda sadece bir nesne olabileceği için new anahtar sözcüğünün ilgili sınıf için yasaklanması gerekir yani yapıcı metodun protected ya da private olarak bildirilmesi gerekir. Eğer bir metodun varsayılan yapıcı metodu(default constructor- parametresiz yapıcı metot) public olarak bildirilmemişse ilgili sınıf türünden herhangi bir nesnenin sınıfın dışında tanımlanması mümkün değildir. Ancak bizim isteğimiz yalnızca bir nesnenin yaratılması olduğuna göre ilgili sınıfın içinde bir yerde nesnenin oluşturulması gerekir. Bunu elbette statik bir özellik(property) ya da statik bir metotla yapacağız. Bu statik metot sınıfın kendi içinde yaratılan nesneyi geri dönüş değeri olarak bize gönderecektir. Peki, bu nesne nerede ve ne zaman yaratılacaktır? Bu nesne statik metodun ya da özelliğin içinde yaratılıp yine sınıfın private olan elemanına atanır. Tekil olarak yaratılan bu nesne her istendiğinde eğer nesne zaten yaratılmışsa bu private olan elemanın referasına geri dönmek ya da nesneyi yaratıp bu private değişkene atamak gerekmektedir.

Ama bizim yapacağımız şu şekilde olacaktır:
SınıfAdı olusturulacakNesne = SınıfAdı.MetodAdı(); //Standart bir static class çağırma şekli

Temel Uml görüntümüz ise şöyle olacaktır:

Ama ben bu yapıya ek birkaç şey daha ekleyerek aşağıdaki şekilde bir sınıf hazırladım.

Temelde ihtiyacım olan property’leri kod bloğunun üst kısmında aşağıda görüldüğü gibi oluşturuyorum.

private static Service _serviceInstance;
private IOrganizationService _organizationService;
private Guid _controlID;
private static object _lockObject = new object();

public IOrganizationService OrganizationService
{
    get { return _organizationService; }
}

public Guid ControlID
{
    get { return _controlID; }
}

Burada Service türünden oluşan _serviceInstance isimli property aslında bütün işi yapan arkadaş. Biz onun dolu ya da boş olduğuna yani null olup olmamasına bakarak hareket edeceğiz. IOrganizationService daha önce de ifade ettiğim gibi Dynamics CRM’in servis nesnesi. Amacımız onun oluşturulma aşamasının tekrar tekrar çağrılmasını engellemek. ControlID sistemde oluşan instance’ların aynı id’ye sahip olup olmadıklarına bakarak onların kaç kere oluşturulduklarını gözlemlediğimiz değişken. lockObject ise tamamen ilerisi için düşünülmüş ve multithread mantıkta sıkıntı yaşamamızı engellemek için konmuş bir değişken.

 

Temel ihtiyaçlar bölümünden sonra asıl işimi yapacak olan kod öbeğini doğru yere yerleştirme işlemi bulunmakta. Aşağıdaki blok benim her zaman için bir kere çalıştırmak isteyeceğim blok işte bu bloğu Singleton tasarım deseni içerisinde private olarak ayarlanmış Constructor metodumun içine yerleştiriyorum.

ClientCredentials clntCredentials = new ClientCredentials();
clntCredentials.Windows.ClientCredential = new System.Net.NetworkCredential("kullanıcı adı", "şifre", "domain");
Uri orgUri = new Uri("http://crm url/Organizasyon Adı/XRMServices/2011/Organization.svc");
OrganizationServiceProxy orgService = new OrganizationServiceProxy(orgUri, null, clntCredentials, null);
_organizationService = (IOrganizationService)orgService;

Daha sonra static olarak çağrılacak ve mevcut servisimin hafıza daha önceden oluşturulup oluşturulmadığını kontrol edecek yapıya geliyor sıra. Onun için de kodun üst kısmında tanımlamış olduğum property’ler vasıtasıyla kontrollerimi yapıyorum.

        public static Service GetService()
        {
            try
            {
                if (_serviceInstance == null)
                {
                    lock (_lockObject)
                    {
                        if (_serviceInstance == null)
                            _serviceInstance = new Service(Guid.NewGuid()); 
                    }
                }

                return _serviceInstance;
            }

 

Burada şunu belirtmeliyim ki lock bölümüne aslında normal şartlar altında ihtiyacım bulunmamakta o bölüm ileride bu sistemi multithread olarak kullanırsam servisinin ayrı instance’lar tarafından tekrar oluşturulmasını engellemek için konan bir kod bloğu.

Ve hepsini bir araya topladığımızda aşağıdaki kod bloğu karşımıza çıkmakta.

    class Service
    {
        private static Service _serviceInstance;
        private IOrganizationService _organizationService;
        private Guid _controlID;
        private static object _lockObject = new object();

        public IOrganizationService OrganizationService
        {
            get { return _organizationService; }
        }

        public Guid ControlID
        {
            get { return _controlID; }
        }
        
        private Service(Guid controlID)
        {
            ClientCredentials clntCredentials = new ClientCredentials();
            clntCredentials.Windows.ClientCredential = new System.Net.NetworkCredential("kullanıcı adı", "şifre", "domain");
            Uri orgUri = new Uri("http://crm url/Organizasyon Adı/XRMServices/2011/Organization.svc");
            OrganizationServiceProxy orgService = new OrganizationServiceProxy(orgUri, null, clntCredentials, null);
            _organizationService = (IOrganizationService)orgService;
            _controlID = controlID;
        }

        public static Service GetService()
        {
            try
            {
                if (_serviceInstance == null)
                {
                    lock (_lockObject)
                    {
                        if (_serviceInstance == null)
                            _serviceInstance = new Service(Guid.NewGuid()); 
                    }
                }

                return _serviceInstance;
            }
            catch (Exception ex)
            {
                string ErrorDetail = ExceptionHandler.HandleException(ex);
                DetailedLog.CreateLog(System.Reflection.Assembly.GetExecutingAssembly().GetName().Name
                    + " : " + System.Reflection.MethodBase.GetCurrentMethod().ToString()
                    + " : " + ErrorDetail, System.Diagnostics.EventLogEntryType.Error);

                return null;
            }
        }
    } 

İşte bu kadar herşey hazırlandı. Şimdi bu kodu çağıracak olan kodu hazırlamaya geldi sıra. Bunun için de bir konsol uygulaması oluşturuyorum ve aşağıdaki kodları ekliyorum.

            Service service1 = Service.GetService();
            Console.WriteLine(service1.ControlID);

            Service service2 = Service.GetService();
            Console.WriteLine(service2.ControlID);

            Entity lead = new Entity("lead");
            lead.Attributes["subject"] = "Fuardan Gelenler";
            lead.Attributes["firstname"] = "Barış";
            lead.Attributes["lastname"] = "KANLICA";
            lead.Attributes["companyname"] = "Omerd Business Solutions";

            service1.OrganizationService.Create(lead);

            Console.WriteLine("Lead created!!");
            Console.ReadLine();

Burada yaptığımız temel işlem Service türünden oluşturduğumuz nesnenin içindeki CRM’in OrganizationService nesnesine ulaşmak. Aşağıdaki ekran çıktısında da göreceğiniz üzere servis sadece bir kere oluşmakta. (Nereden mi biliyorum bakın iki service nesnesi de aynı ControlID değerini Guid olarak döndürmekte)

Eğer isterseniz başka classlar içerisinde de service nesnelerinin çağırabilirsiniz her seferinde tek bir oluşturma işlemi olacak ve sistem kaynaklarını daha verimli kullanmış olacağız.