Click here to Skip to main content
Click here to Skip to main content
Go to top

Writing Microsoft CRM 3.0 Callouts – Sample Code: Turkish Citizen Number Validator

, 26 May 2007
Rate this:
Please Sign up or sign in to vote.
This article focuses on callout development for MS CRM 3.0. As an example Turkish Citizen Number Validator code is written.
Screenshot - image002.jpg

Introduction

In this artcle i will try to explain the basic concepts to a novice MS CRM developer who wants to customize Microsoft CRM 3.0. This article consists of external referances and code samples those are provided with the permission of the copyright holders' permission. If you will get quotations from this article please provide the original link as the referance info in your material. Outline is as follows:

o What is a callout? Where do them used?

o Which events trigger callouts?

o A simple case example: Validator For Turkish Citizen Number (=TCKN)

Background

Having a strong C# programming knowledge is an asset to benefit from this article. First i will try to explain basic concepts for callout programming for MS CRM 3.0.

What are callouts?

Callouts are simply class libraries those are compiled using .NET Framework (=fw) 1.1.

First question in our minds is: Can we write callouts using fw2.0 or fw3.0 ?
Unfortunately NO! Since MS CRM 3.0 is written using fw 1.1 and callout assemblies are loaded in the same application pool with crm, there is a limitation in executing only one framework in one application pool (=app pool), crm application pool uses fw1.1 and you cannot load an assembly that requires fw2.0 or above in that app pool. So we have to compile our callout code in fw1.1.

How to generate fw1.1 code?

There are two ways to generate fw1.1 code.

First is the conventional way, we use Visual Studio.NET (=VSNET) 2003, we write our code in the IDE and hit F5 to generate the compiled code.

Second is a bit compilcated, you may utilize VSNET 2005 and fw1.1 to generate fw1.1 assemblies. However this technique requires msbee setup and having a proper config file. Then you only need to write an msbuild command in the VSNET command prompt to generate fw1.1 assembly.

Hence this is a bit more complicated i will explain the issue in another article.

Callouts are used to extend MS CRM 3.0 features. Mostly in integration projects callouts are used to provide data integrity, and consistance. For instance you dont want to save two people having the same employee number, however by default ms crm allows having two records with the same employee number. Just at this point you may write a callout and it checks the existance of the employee number, if that number exists aborts the save process, otherwise makes the process continue the usual way.

Importance of CrmCalloutBase Class

This class resides in the microsoft.crm.platform.callout.base.dll file which is located in the system folder of the Microsoft Crm 3.0 installation directory. This is the main starting point for the callout developer, that is:

<formulas /></formulas />Screenshot - image004.gifAll the callouts must be derived from the CrmCalloutBase class, thus you have to reference microsoft.crm.platform.callout.base.dll file all of your callout projects. This dll file may be found at the MS CRM 3.0 installation CD's following path:
Microsoft CRM 3.0 Professional Edition Disk
\Bin\Assembly\Microsoft.Crm.Platform.Callout.Base.dll


Here we see the events that fire callouts. Using these events MS CRM custom checks and additional functionalities are achieved.

PreAssign / PostAssign

Specifies a method called before / after an assign operation.

PreDelete / PostDelete

Specifies a method called before / after a delete operation.

PreUpdate / PostUpdate

Specifies a method called before / after an update operation.

PreCreate / PostCreate

Specifies a method called before /after a create operation.

PreMerge / PostMerge

Specifies a method called before / after a merge operation.

PreSetState / PostSetState

Specifies a method called before / after a set state operation.

PreSend

Specifies a method called before a send e-mail operation.

PostDeliver

Specifies a method called after a deliver e-mail operation.

Reference: http://msdn2.microsoft.com/en-us/library/aa613520.aspx

Table describes the types of operations can be handled using callouts.
We may fully customize Create/Update /Delete/Assign operations by writing pre and post callout methods. Since names describe the usages of the methods some of them need explanation.

Assign event occurs when an entity's owner is changed.

SetState event occurs when an entity's state is changed to active or inactive.
See Apprendix A1 for a sample code about this event.

Merge event occurs when

By deriving from CrmCalloutBase class and limplementing one of the above methods we write our callout code, then we compile it to a DLL file. Now it's time to deploy the resultant assembly to the MS CRM server.

.NET assembly (the class library) is put in the MS CRM server's installation directory's sub folder bin\assembly. i.e: If you installed the server to C:\Program Files\Microsoft CRM then the callout assembly must be put to C:\Program Files\Microsoft CRM\Server\bin\assembly.

Screenshot - image004.gifAssuming the CRM installation directory is C:\Program Files\Microsoft CRM\
All the callouts must reside at
C:\Program Files\Microsoft CRM\Server\bin\assembly\

After putting the callout DLL to the assembly directory callout declaration must be made to the CRM server, otherwise server cannot know when to call the callout assembly. Notifying the server about callouts is done using the callout.config.xml file that is found in the assembly directory of the CRM.

<?xml version="1.0" encoding="utf-8" ?>
<callout.config version="2.0">
<callout entity="contact" event="PreCreate">
<subscription assembly="DontPermitDuplicates.dll" class="DontPermitDuplicates.NoDblNames" />
</callout>
</callout.config>


Above we see a callout assembly notification to CRM. Callout class library's namespace is called DontPermitDuplicates. Just before a Lead entity is created in the CRM this callout is called.

CRM instantiates an object of DontPermitDuplicates.NoDblNames class. Then executes the PreCreate method in that class. That method may check things or do the required custom business operations then object may either abort the creation operation by raising an error message, or makes the operation continue so the entity is created in the CRM.

Step by Step Simple Callout Example

1. Create a Class Library project in VSNET 2003.

2. Add referance to microsoft.crm.platform.callout.base.dll file

3. Derive a class from CrmCalloutBase.

4. Write PreCreate and then CTRL+SPACE to see the method signature find PreCreate method and press enter.

Use the following sample code to achieve your first callout code.

<p style="LINE-HEIGHT: normal">public override PreCalloutReturnValue PreCreate(

</p>

<p style="LINE-HEIGHT: normal">      CalloutUserContext userContext, CalloutEntityContext entityContext, 
      ref string entityXml, ref string errorMessage

</p>

<p style="LINE-HEIGHT: normal">) {
      PreCalloutReturnValue calloutRetVal = PreCalloutReturnValue.Continue;

</p>

<p style="LINE-HEIGHT: normal">      // error message is not set at the begining
      errorMessage = string.Empty;

</p>

<p style="LINE-HEIGHT: normal">      XmlDocument xd = new XmlDocument();
      xd.LoadXml(entityXml);

</p>

<p style="LINE-HEIGHT: normal">/* all the elements in the XML file is iterated, and only desired ones are added 
    to the nvPostedInfo collection */
      NameValueCollection nvPostedInfo = new NameValueCollection();

</p>

<p style="LINE-HEIGHT: normal">      
</p>

<p style="LINE-HEIGHT: normal">      foreach (XmlElement element in xd.GetElementsByTagName("Property"))
      {

</p>

<p style="LINE-HEIGHT: normal">            string strAttributeName = element.Attributes.GetNamedItem("Name").Value;

</p>

<p style="LINE-HEIGHT: normal">            switch (strAttributeName) {
                  case "tbs_tckn":
                  nvPostedInfo.Add("tbs_tckn", element.InnerText);
                  break;
            }
      }

</p>

<p style="LINE-HEIGHT: normal">      if ( ! IsTcknValid( nvPostedInfo["tbs_tckn"] ) ) {
            errorMessage = "The TCKN value is not valid!";
            calloutRetVal = PreCalloutReturnValue.Abort;// abort operation
      } 
      return calloutRetVal; 
}
</p>

Above code contains a method called IsTcknValid this method returns a boolean value, weather the parameter of the method is a valid TCKN (=Republic of Turkey Citizen Number) value.

Below we may see the TCKN checker code block. This is very useful to preserve the data validity. (The code presented is a port of the SQL function that is located at following URL:
http://www.verivizyon.com/detail.asp?catid=17&cid=317 )

<p style="LINE-HEIGHT: normal">private bool IsTcknValid(string TcknToValidate)

</p>

<p style="LINE-HEIGHT: normal">{

</p>

<p style="LINE-HEIGHT: normal">      bool isValid = false;

</p>

<p style="LINE-HEIGHT: normal">      TcknToValidate = TcknToValidate.Trim();

</p>

<p style="LINE-HEIGHT: normal">      if (TcknToValidate.Length != 11) return isValid;

</p>

<p style="LINE-HEIGHT: normal">      short C1, C2, C3, C4, C5, C6, C7, C8, C9;

</p>

<p style="LINE-HEIGHT: normal">      int Q1, Q2;

</p>

<p style="LINE-HEIGHT: normal">      Int64 TCNO = Convert.ToInt64(TcknToValidate);

</p>

<p style="LINE-HEIGHT: normal">      Int64 ATCNO = TCNO / 100;

</p>

<p style="LINE-HEIGHT: normal">      Int64 BTCNO = TCNO / 100;

</p>

<p style="LINE-HEIGHT: normal">      C1 = Convert.ToInt16( ATCNO % 10 ); ATCNO /= 10;

</p>

<p style="LINE-HEIGHT: normal">      C2 = Convert.ToInt16( ATCNO % 10 ); ATCNO /= 10;

</p>

<p style="LINE-HEIGHT: normal">      C3 = Convert.ToInt16( ATCNO % 10 ); ATCNO /= 10;

</p>

<p style="LINE-HEIGHT: normal">      C4 = Convert.ToInt16( ATCNO % 10 ); ATCNO /= 10;

</p>

<p style="LINE-HEIGHT: normal">      C5 = Convert.ToInt16( ATCNO % 10 ); ATCNO /= 10;

</p>

<p style="LINE-HEIGHT: normal">      C6 = Convert.ToInt16( ATCNO % 10 ); ATCNO /= 10;

</p>

<p style="LINE-HEIGHT: normal">      C7 = Convert.ToInt16( ATCNO % 10 ); ATCNO /= 10;

</p>

<p style="LINE-HEIGHT: normal">      C8 = Convert.ToInt16( ATCNO % 10 ); ATCNO /= 10;

</p>

<p style="LINE-HEIGHT: normal">      C9 = Convert.ToInt16( ATCNO % 10 ); ATCNO /= 10;

</p>

<p style="LINE-HEIGHT: normal">      Q1 = ((10 - ((((C1 + C3 + C5 + C7 + C9) * 3) + (C2 + C4 + C6 + C8)) % 10)) % 10);

</p>

<p style="LINE-HEIGHT: normal">      Q2 = ((10 - (((((C2 + C4 + C6 + C8) + Q1) * 3) + (C1 + C3 + C5 + C7 + C9)) % 10)) % 10);

</p>

<p style="LINE-HEIGHT: normal">      if ( TCNO == ((BTCNO * 100) + (Q1 * 10) + Q2) ) {

</p>

<p style="LINE-HEIGHT: normal">            isValid = true;

</p>

<p style="LINE-HEIGHT: normal">      }

</p>

<p style="LINE-HEIGHT: normal">      return isValid;
}
</p>

After writing above code to a Class Library project we have to compile it and then the resultant DLL file msut be copied to the MS CRM's Callout directory that is:
"C:\Program Files\Microsoft CRM 3.0\Server\bin\assembly" This directory has a callout.config file which contains the executed callout DLLs for every Entity those are needed to be checked.

We will add the following line of codes in the callout.config.xml file in order to test our callout.

<?xml version="1.0" encoding="utf-8" ?>
<callout.config version="2.0">
<callout entity="contact" event="PreCreate">
<subscription assembly="DontPermitDuplicates.dll" class="DontPermitDuplicates.NoDblNames" />
</callout>
</callout.config>

ATTENTION! Don't forget to put the XML extension to the callout.canfig file, i.e: callout.config.xml


Now we have to test it using a valid and an invalid TCKN value

Testing the Code

First we have to create an attribute that will hold the citizen number, the attribute will be called "new_tckn". After creation, field will be placed on the contact's form.

1) Create the attribute for the contact entity

2) Place the field on the contact form, then publish the changes.

3) Edit the following file, if it does not exists then create it using notepad.

"C:\Program Files\Microsoft CRM\Server\bin\assembly\callout.config.xml"

4) Make iis start again by doing Start > Run > "iisreset"

Now try to enter 12345678901 value for the tckn field of a new contact recrod. This operation will be aborted by the callout since the value is not a valid TCKN number.

Screenshot - image005.gif

Conclusion

In this article the basics of callout programming are shown. As an example of a simple callout Turkish Citizen Number validator callout is developed and tested. Since callout assembies are loaded and run by the MS CRM application using reflection, we have to generate .NET Framework 1.1 assemblies for our callouts. That is beacause MS CRM 3.0 is implemented using .NET 1.1 Framework. As a restriction .NET 1.1 processes cannot execute any higher version of the framework assemblies in their application domain.

In our example there were no connection strings in assembly. Since we don't want to keep our connection string hard coded we need to store them in a config file, thus the config file must be the web.Config of the MS CRM application.

For the curious reader it is beneficial to mention that callouts' DataAccessLayer may be implemented using Enterprise Library's Data Application Block. Until next article keep coding! Smile | :)

Apprendix – Additional Remarks

A.1. When your callouts does not not work, check out here!

Well written two trobleshooting articles may be found at the following locations:

"Is your Microsoft CRM callout not working?", http://blog.sonomapartners.com/2007/03/is_your_microso.html

"The functionality that you expect from a callout .dll file does not work as expected in Microsoft Dynamics CRM 3.0"http://support.microsoft.com/kb/933842

A.2 Other Callout resources

Microsoft's sample callout from CRM SDK's 3.0.7 versionhttp://msdn2.microsoft.com/en-us/library/aa680675.aspx

A.3. Enterprise Library for .NET Framework 1.1

Source: http://msdn2.microsoft.com/en-us/library/ms954827.aspx

This page provides an overview of the Enterprise Library Data Access Application Block. This is reusable and extensible source code-based guidance that simplifies development of common data access functionality in .NET-based applications.

Downloads Latest Release (for .NET Framework 1.1): Enterprise Library, June 2005
See also: Enterprise Library for .NET Framework 2.0, January 2006
License End User Licensing Agreement (EULA)
Hands-On Labs Enterprise Library - Hands on Labs
Webcast Enterprise Library Data Access Application Block (Level 300)
Community Enterprise Library Community

System Requirements for Enterprise Library for .NET Framework 1.1
*
Supported OS: Windows 2000; Windows Server 2003; Windows XP Professional Edition
* Microsoft .NET Framework version 1.1
* Microsoft Visual Studio .NET 2003 development system (Enterprise Architect, Enterprise Developer, or Professional edition)
* Some blocks and samples require the use of Microsoft SQL Server or other database products.
* NUnit 2.1.4 is required if you want to execute unit tests

A.4 Sample List of files in Callout Assembly Directory

Screenshot - image007.gif

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

Share

About the Author

Ziver Alen MALHASOGLU is e-commerce consultant. He has been working in IT industry since 2003. He has worked on Microsoft Commerce Server, Microsoft CRM, and Microsoft Sharepoint Server.
 
He is interested in Artificial Intelligence (AI) and Robotics. However doing some research and reading about them are just hobbies, and is not part of his professional life.
 
As an application of AI in E-Commerce and CRM area he is interested in Business Intelligence concepts such as data mining, and practical implementations of artificial neural networks. He likes to read articles about latest C# development and design patterns.
 
His spare time activities are cycling, dancing salsa, tango and other kinds of latin dances.
Follow on   Twitter

Comments and Discussions

 
General...Interesting article Pinmembermatply22-Apr-10 8:27 
Generalfields content not preserved Pinmemberlemravec28-Apr-08 23:13 
GeneralMy Callout is not working??? :&lt;&lt;/codeProject$$&gt; Pinmemberqumer10131-Dec-07 3:27 
Generalgreat article PinmemberYogiMySon18-Oct-07 15:41 
QuestionPostSetState not working. PinmemberKuntal Ghoshal6-Jun-07 2:59 
AnswerRe: PostSetState not working. PinmemberZiver Alen MALHASOGLU20-Oct-07 3:53 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web03 | 2.8.140916.1 | Last Updated 26 May 2007
Article Copyright 2007 by Ziver Alen MALHASOGLU
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid