cub-e.net

just coding...

Plug-in’ler Icerisindeki Hatalari Yakalamak

Bu makalede plug-in hata yakalama mekanizmasina deginecegim. 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.");

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)

                    {

                        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");

                            }

                        }

                    }

 

E-Mail Router and Microsoft Exchange MAPI

Dynamics CRM 4.0 veya Exchange Server üzerine E-mail Router kurmak istediğinizde aşağıdaki hata ile karşılaşabilirsiniz.
When you installing the E-mail Router on CRM server or Exchange Server you might get this error
The Microsoft Exchange MAPI subsystem is not installed on this machine.



Eğer aşağıdaki linkten Microsoft Exchange Server MAPI Client and Collaboration Data Objects 1.2.1'i kurulumdan önce yüklerseniz bu sorun ortadan kalkar. Dosyayı buradan indirebilirsiniz.
If you install the Microsoft Exchange Server MAPI Client and Collaboration Data Objects 1.2.1 before continue the installation. This file can be downloaded here.



Tekrar E-Mail Router kurulumunu çalıştırdığınızda hata uyarısı almazsınız.
When you re-run the E-Mail Router installation you didn't get the error.

Microsoft Dynamics CRM Hatalarını Yakalamak

CRM web servisi bir web servisinin doğası gereği soap ile iletişim kurmakta ve işlenen hataları da soap içinde xml ile döndürmektedir.


Microsoft Dynamics CRM Web Servisi'nde Request parametresi kullanılarak bir çağrı yaptığınızda hata olarak System.Web.Services.Protocols.SoapException sınıfından ortak bir hata mesaj yapısı döner.

SoapException'ın Message property'si her zaman için "Server was unable to process request." hatasını döndürür.

SoapException içerisinde Detail property'si oluşmuş olan hata hakkında daha fazla bilgi verecektir. Detail property bir XmlNode türündendir ve InnerXml property aşağıdaki formatta hatayı sunmaktadır.

<error>
<description>Error description goes here.</description>
<code>0xABCD1234</code>
<type>Platform</type>
</error>
 

ErrorCode yani xml içerisindeki Number hexadecimal türündedir. Örnek verecek olursak; eğer veritabanında olmayan bir fax'ı çağırmaya kalkalsanır hata aşağıdaki şekilde olacaktır:

<error>
<code>0x80041103</code>
<description>'Lead' entity doesn't contain attribute with Name = 'name'.</description>
<type>Platform</type>
</error>

Standart bir kodlama mantığında catch bloğunda bu hatayı aşağıdaki şekilde yakalabiliriz.

catch (System.Web.Services.Protocols.SoapException ex)
{
   
Message = ex.Message;
   
Detail = ex.Detail.InnerText;
}

Bu şekilde hatayı öğrenebiliriz ama detaylı ve güzel bir hata mesajı olmaz son kullanıcı için. Tabii burada bu hataları loglayacak bir yapı oluşturabiliriz bu tercihinize kalmış ama her durumda detaya ihtiyacımız var.

CRM'in detaylı hata kod listesine buraya tıklayarak ulaşabilirsiniz.

Hata yapısı ve içeriği hakkında bu bilgileri verdikten sonra bu hataları yakalayacak kodu vermek güzel olacak sanırım :) Aşağıda kodu ve açıklamasını bulabilirsiniz.

 

/// <summary>
///
Hatalari yakaliyoruz.
/// </summary>
/// <param name="ex">System Exception</param>
/// <returns>hatanin detayli aciklamasi</returns>
private string HandleException(Exception ex)
{
   
string Error = "Uygulama bir hata ile karsilasti." + System.Environment.NewLine;
    Error +=
"Message : " + ex.Message + System.Environment.NewLine;
   
if (ex.InnerException != null)
        Error += ex.InnerException.Message + System.
Environment.NewLine;
   

    SoapException
se = ex as SoapException;
   
if (se != null)
    {
        Error +=
"Code : " + GetError(se.Detail, "//code") + System.Environment.NewLine;
        Error +=
"Desription : " + GetError(se.Detail, "//description") + System.Environment.NewLine;
        Error +=
"Type : " + GetError(se.Detail, "//type") + System.Environment.NewLine;
    }
   
return Error;
}

/// <summary>
/// SoapException.Detail icerisindeki hatayi dondurur
/// </summary>
/// <param name="errorInfo">hatayi iceren XmlNode'u.</param>
/// <param name="item">geri dondurulecek hata.</param>
/// <returns>hata detayi ya da bos icerik.</returns>
private string GetError(XmlNode errorInfo,string item)
{
   
XmlNode code = errorInfo.SelectSingleNode(item);
   
if (code != null)
   
    return code.InnerText;
   
else
        return
"";
}
  1. Burada dikkat edilmesi gereken şey hatanın SoapException sınıfı türünden olup olmadığını kontrol ettiğimiz kısım;

        SoapException se = ex as SoapException;

    eğer içerik SoapException türünden ise detayını öğrenmek isityoruz. ( "as" ifadesi hakkında daha fazla bilgi almak için buraya tıklayınız.)
  2. Yukarıda hata durumunda dönecek Xml içeriğini verdim. Bu bir Xml olduğu için XmlNode'larına erişerek istediğimiz bilgiyi alalım. İşte GetError bu işe yarıyor. Soap Exception'ın Detail'ını ve istediğimiz node'u söylüyoruz bize geri dönüyor.

        GetError(se.Detail, "//code")

Bu kod sonucunda elde ettiğimiz hata mesajı;

 

Uygulama bir hata ile karsilasti.
Message : Server was unable to process request.
Code : 0x80041103
Desription : 'Lead' entity doesn't contain attribute with Name = 'name'.
Type : Platform

 

Bir makalemizin daha sonuna geldik umarım faydalı olmuştur.


Barış KANLICA

Yazılım Uzmanı – Software Specialist
brsk@e-kolay.net
www.cub-e.net
forum.cub-e.net