Random Musings

June 21, 2009

Using reflection to iterate over all the properties inside an object

Filed under: Dynamics CRM — haditeo @ 6:04 pm
Tags: ,

Here are the code snippet before it’s refactored using reflection :

        public DynamicEntity Convert(Project newProject)
        {
            try
            {
                DynamicEntity deProject = new DynamicEntity();
                deProject.Name = "new_project";


                if (newProject.IsProjectRefExist())
                    deProject.Properties.Add(newProject.ProjectRef);

                if (newProject.IsClientExist())
                    deProject.Properties.Add(newProject.Client);

                if (newProject.IsPrimaryContactExist())
                    deProject.Properties.Add(newProject.PrimaryContact);

                if (newProject.IsClientCategoryExist())
                    deProject.Properties.Add(newProject.ClientCategory);

                if (newProject.IsProjectTitleExist())
                    deProject.Properties.Add(newProject.ProjectTitle);

                if (newProject.IsProjectTitleInChineseExist())
                    deProject.Properties.Add(newProject.ProjectTitleInChinese);

                if (newProject.IsAccountManagerExist())
                    deProject.Properties.Add(newProject.AccountManager);

                if (newProject.IsKbaExist())
                    deProject.Properties.Add(newProject.Kba);

                if (newProject.IsServiceTypeExist())
                    deProject.Properties.Add(newProject.ServiceType);

                if (newProject.IsDevelopmentTypeExist())
                    deProject.Properties.Add(newProject.DevelopmentType);

                if (newProject.IsRegionExist())
                    deProject.Properties.Add(newProject.Region);

                if (newProject.IsLocationExist())
                    deProject.Properties.Add(newProject.Location);

                if (newProject.IsCountryExist())
                    deProject.Properties.Add(newProject.Country);

                if (newProject.IsDescriptionExist())
                    deProject.Properties.Add(newProject.Description);

                if (newProject.IsSourceExist())
                    deProject.Properties.Add(newProject.Source);

                if (newProject.IsEstimatedProjectCostExist())
                    deProject.Properties.Add(newProject.EstimatedProjectCost);

                if (newProject.IsEstimatedProjectFeesExist())
                    deProject.Properties.Add(newProject.EstimatedProjectFees);

                if (newProject.IsEstimatedFeesPercentageExist())
                    deProject.Properties.Add(newProject.EstimatedFeesPercentage);

                if (newProject.IsEstimatedProjectStartDateExist())
                    deProject.Properties.Add(newProject.EstimatedProjectStartDate);

                if (newProject.IsEstimatedProjectEndDateExist())
                    deProject.Properties.Add(newProject.EstimatedProjectEndDate);

                return deProject;
            }
            catch (System.Web.Services.Protocols.SoapException ex)
            {
                throw ex;
            }
            catch (Exception e)
            {
                throw e;
            }
        }

and here are the code after it’s refactored

        public DynamicEntity Convert(Project newProject)
        {
            try
            {
                DynamicEntity deProject = new DynamicEntity();
                deProject.Name = "new_project";

                foreach (PropertyInfo projectProperty in typeof(Project).GetProperties())
                {
                    // skip if the method is not exist
                    if ((typeof(Project).GetMethod("Is" + projectProperty.Name + "Exist")) == null)
                        continue;

                    bool isPropertyHasValue = (bool)(typeof(Project).GetMethod("Is" + projectProperty.Name + "Exist")).Invoke(newProject, null);

                    //don't add to the Project's dynamic entity with the null value of the current Project property
                    if (!isPropertyHasValue)
                        continue;

                    deProject.Properties.Add((Property)projectProperty.GetValue(newProject, null));
                }

                return deProject;
            }
            catch (System.Web.Services.Protocols.SoapException ex)
            {
                throw ex;
            }
            catch (Exception e)
            {
                throw e;
            }
        }

Reflection is cool. What reflection techniques that i am using it here ?

  • I am using these code snippet to iterate to all the properties inside an object. The advantage of this is i do not need to hard code additional lines when my business object gets added with additional attributes
    foreach(PropertyInfo projectProperty in typeof(Project).GetProperties())
    {}
    
  • I am using the GetMethod() to check whether a particular method name is indeed exist inside the object
    if ((typeof(Project).GetMethod("Is" + projectProperty.Name + "Exist")) == null)
    
  • I am using the Invoke() to invoke the particular method. Fortunately i do not need to pass the parameter
    (bool)(typeof(Project).GetMethod("Is" + projectProperty.Name + "Exist")).Invoke(newProject, null);
    
  • As usual, i always use the GetValue method to obtain the current property value for the particular object

    (Property)projectProperty.GetValue(newProject, null)
    

June 19, 2009

Reflection in C#

Filed under: Dynamics CRM — haditeo @ 10:00 pm
Tags: , ,

These are the code before it’s refactored

         private Opportunity ToOpportunity(DynamicEntity de)
         {
             try
             {
                 Opportunity opportunity = new Opportunity();

                 foreach (string attribute in opportunity.AttributesList)
                 {
                     if (!de.Properties.Contains("opportunityid"))
                         throw new PropertiesNotExistException("The Dynamic Entity type Opportunity does not have id property");

                     opportunity.Id = new KeyProperty("opportunityid", ((Key)de["opportunityid"]));

                     switch (attribute)
                     {
                         case "customerid":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetPotentialClient(((Customer)de[attribute]).Value);
                             break;
                         case "new_contactpersonid":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetContactPerson(((Lookup)de[attribute]).Value);
                             break;
                         case "new_clientcategory":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetClientCategory(((Picklist)de[attribute]).Value);
                             break;
                         case "name":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetPotentialProjectTitle(de[attribute].ToString());
                             break;
                         case "new_potentialprojecttitlechinese":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetPotentialProjectTitleInChinese(de[attribute].ToString());
                             break;
                         case "new_accountmanager":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetAccountManager(de[attribute].ToString());
                             break;
                         case "new_kba":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetKba(((Picklist)de[attribute]).Value);
                             break;
                         case "new_servicetype":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetServiceType(((Picklist)de[attribute]).Value);
                             break;
                         case "new_developmenttype":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetProjectDevelopmentType(((Picklist)de[attribute]).Value);
                             break;
                         case "new_regionopportunityid":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetRegion(((Lookup)de[attribute]).Value);
                             break;
                         case "new_location":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetLocation(de[attribute].ToString());
                             break;
                         case "new_countryopportunityid":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetCountry(((Lookup)de[attribute]).Value);
                             break;
                         case "description":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetDescription(de[attribute].ToString());
                             break;
                         case "new_source":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetSource(((Picklist)de[attribute]).Value);
                             break;
                         case "new_estimatedprojectcost":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetEstimatedProjectCost(((CrmMoney)de[attribute]).Value);
                             break;
                         case "estimatedvalue":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetEstimatedProjectFees(((CrmMoney)de[attribute]).Value);
                             break;
                         case "new_estimatedfeespercentage":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetEstimatedFeesPercentage(((CrmDecimal)de[attribute]).Value);
                             break;
                         case "new_estimatedprojectstartdate":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetEstimatedProjectStartDate(((CrmDateTime)de[attribute]).UserTime);
                             break;
                         case "new_estimatedprojectenddate":
                             if (de.Properties.Contains(attribute))
                                 opportunity.SetEstimatedProjectEndDate(((CrmDateTime)de[attribute]).UserTime);
                             break;
                     }
                 }
                 return opportunity;
             }
             catch (SoapException soapExc)
             {
                 throw soapExc;
             }
             catch (Exception exc)
             {
                 throw exc;
             }

         }

and these are the code after it’s refactored

        public Opportunity ToOpportunity(DynamicEntity de)
        {
            try
            {
                Assembly sdkDll = Assembly.LoadFrom("microsoft.crm.sdk.dll");

                Opportunity newOpportunity = new Opportunity();

                foreach(PropertyInfo pi in  typeof(Opportunity).GetProperties())
                {
                    string crmFieldMapping = ((CrmFieldMapping)(pi.GetCustomAttributes(typeof(CrmFieldMapping), false))[0]).GetCrmFieldMapping();
                    string crmTypeProperty = ((CrmTypeProperty)(pi.GetCustomAttributes(typeof(CrmTypeProperty), false))[0]).GetCrmTypeProperty();

                    if (de.Properties.Contains(crmFieldMapping))
                    {
                        Type currentCrmTypeProperty = sdkDll.GetType("Microsoft.Crm.Sdk." + crmTypeProperty);

                        object obj = Activator.CreateInstance(currentCrmTypeProperty, crmFieldMapping, de[crmFieldMapping]);

                        pi.SetValue(newOpportunity, obj, null);
                    }
                }

                return newOpportunity;
            }
            catch (SoapException soapExc)
            {
                throw soapExc;
            }
            catch (Exception exc)
            {
                throw exc;
            }

        }

Currently i’m closely applying Domain Driven Development by creating domain objects first. The previous source code is created without using reflection. Yesterday, i was wondering and got the idea of decorating the domain object with custom attributes as metadata, so that i can easily refer to it when reflecting the object at runtime.

These are the sample of the custom attribute :

    public class Opportunity
    {
        private KeyProperty opportunityId;
        [CrmTypeProperty("KeyProperty")]
        [CrmFieldMapping("opportunityid")]
        public KeyProperty Id
        {
            get { return opportunityId; }
            set { opportunityId = value; }
        }

        private StringProperty _projectTitle;
        [CrmTypeProperty("StringProperty")]
        [CrmFieldMapping("name")]
        public StringProperty PotentialProjectTitle
        {
            get { return _projectTitle; }
            set { _projectTitle = value; }
        }
   }

What are the advantages of using reflection ? Now, let’s say i am adding another property at the domain object, i just need to update the domain object and i don’t need to change the code at the data layer.

Blog at WordPress.com.