Blogging about MS CRM

August 29, 2009

Error TF86001 or TF80042 Opening Microsoft Team Foundation Server Work Items in Microsoft Excel or Microsoft Project

Filed under: TFS — haditeo @ 8:06 am
Tags:

While performing walkthrough for managing work items in Excel and Project here, apparently Excel and Project was not installed. So Excel and Project are installed after Team Foundation Server.

When opening Excel or Project document, this error is reported “TF80042: The document cannot be opened because you do not have Microsoft Excel 200n or one of its components installed.” So to resolve this issue, Excel and Project should be installed. In this case, i install the 2003 version

After Excel and Project 2003 are installed, another error is reported “TF86001: Team Foundation was unable to load the Office Add-In.”. So i googled around and find out this KB Article

The core solution is to repair the Visual Studio 2005/2008 Team Explorer, so that the installation can “link” back the Excel / Project to the Team Explorer

July 24, 2009

Is it possible to register different event handlers in only one assembly to be registered in Dynamics CRM Plugin ?

Filed under: Dynamics CRM — haditeo @ 9:41 am
Tags:

The answer is Yes.

plugin_registration_tool_main_window

The reason why i need this, is because i would like to register only a single DLL for the Plugin DLL, let’s called it XXX.CRM.Plugin

visual_studio_solution

To register multiple event handler, create multiple classes that implements Execute method of the IPlugin interface, then automatically when you register the plugin, you can load those classes

register_assembly

Now, the question is how do i select which class to be loaded against my event message ? When you register a new step, there is a plugin dropdownlist, you can select which class to be executed. Since we are registering two classes, then there will be two plugin options in the drop down list

select_which_plugin_to_be_executed

July 11, 2009

SketchFlow RC is released

Filed under: sketchflow — haditeo @ 5:11 pm
Tags: ,

I have just read the news that Silverlight 3 is released. But the one that got me interested is Sketch Flow Released Candidate

And then i googled around and find out this screencast and immediately i am interested in it.

I am thinking of creating prototype when customizing Dynamics CRM ASP.NET Web Application, by taking the screenshot of the Dynamics CRM UI as the background and create interactions inside it. Let’s say what happen when you click “Convert to Lead” button or what happen when this data is submitted etc . Users can obtain quick feedback regarding the interaction.

July 8, 2009

BluePrint, YAML and 960 GridSystem

Filed under: css — haditeo @ 3:47 pm
Tags:

First of all, you might ask me ? What are those ?

Blueprint is a CSS framework, which aims to cut down on your development time. It gives you a solid foundation to build your project on top of, with an easy-to-use grid, sensible typography, useful plugins, and even a stylesheet for printing.

and

YAML “Yet Another Multicolumn Layout” (YAML) is an (X)HTML/CSS framework for creating modern and flexible floated layouts. The structure is extremely versatile in its programming and absolutely accessible for end users.

and

The960 Grid System is an effort to streamline web development workflow by providing commonly used dimensions, based on a width of 960 pixels. There are two variants: 12 and 16 columns, which can be used separately or in tandem.

3 years ago, i have learned CSS extensively to promote table-less design by using CSS. The painful of manual learning is i need to carefully calculate each of the div boxes, reset the position, calculate the boxes width etc. Not to mention that there is browser quirks means that the layout seen in the IE might be not the same if it’s seen on FireFox.

While i browsed around JQuery most popular plugin list, JQuery UI Layout is on the top of the list.

and then i browsed around my favorite website Stack Overflow, and i found some suggestion that there are some CSS framework. That’s when i found these CSS frameworks. Really fabolous, by looking at the demo or sample page. It’s definitely reduce countless hours of calculating and trying to match the design by using div’s.

This article is definitely a must to read to compare each of the css grid framework.

Since my next task was to layout my .ASPX page according to the Dynamics CRM Forms, i will try Blueprint to design the data entry form layout.

July 6, 2009

Create simple domain generator by reading from CRM Metadata

Filed under: Dynamics CRM, c# — haditeo @ 9:30 pm
Tags: ,

Objective
I would like to create my own domain (class) from the custom CRM entity. The advantage of this is to simplify domain persistence and retrieval between application layer and database layer (CRM Web Service)

How to achieve this ?

  • First of all we utilize RetrieveEntityRequest message to retrieve all attributes of the specific entity.
                    RetrieveEntityRequest request = new RetrieveEntityRequest();
                    request.LogicalName = entityName;
                    request.EntityItems = EntityItems.IncludeAttributes;
    
                    RetrieveEntityResponse response = (RetrieveEntityResponse)metadataService.Execute(request);
    
                    EntityMetadata entityMetadata = response.EntityMetadata;
    
                    foreach (AttributeMetadata attributeMetadata in entityMetadata.Attributes)
                    {
                        //loop through all attributes here.
                    }
    
  • There are some interesting attributes of the AttributeMetadata. Such as LogicalName attribute, DisplayName attribute and AttributeType attribute
  • By looping through each of the attributes, i read the relevant template file consisting of the code templates and replace the necessary placeholder with the actual values

    private LookupProperty _#internalVariableName#;
    [CrmAttributeMapping("#crmAttributeMapping#")]
    public LookupProperty #publicPropertyName#
    {
        get { return _#internalVariableName#; }
        set { _#internalVariableName# = value; }
    }
    
    public void Set#publicPropertyName#(Guid value)
    {
        _#internalVariableName# = new LookupProperty("#crmAttributeMapping#", new Lookup("#lookupAttributeMapping#", value));
    }
    
    public bool Is#publicPropertyName#Null()
    {
        if (_#internalVariableName# == null)
            return true;
    
        if (_#internalVariableName#.Value == null)
            return true;
    
        if (_#internalVariableName#.Value.Value == Guid.Empty)
            return true;
    
        return false;
    }
    

    Here are the result of the placeholder value replacement

    private LookupProperty _owninguser;
    [CrmAttributeMapping("owninguser")]
    public LookupProperty owninguser
    {
        get { return _owninguser; }
        set { _owninguser = value; }
    }
    
    public void Setowninguser(Guid value)
    {
        _owninguser = new LookupProperty("owninguser", new Lookup("#lookupAttributeMapping#", value));
    }
    
    public bool IsowninguserNull()
    {
        if (_owninguser == null)
            return true;
    
        if (_owninguser.Value == null)
            return true;
    
        if (_owninguser.Value.Value == Guid.Empty)
            return true;
    
        return false;
    }
    
  • Some clean up needs to be performed to tidy up the public Property name, but this code generator has helped me tremendeously to eliminate boring and repititive tasks of creating custom domain objects by hand.

July 4, 2009

Json.NET and json.js

Filed under: c# — haditeo @ 11:45 am
Tags: ,

Let’s say i have an “Argument” class and “Customer” class below :

    public class Argument
    {
        private string _filterComboType;

        public string FilterComboType
        {
            get { return _filterComboType; }
            set { _filterComboType = value; }
        }

        private string _selectedNameClientId;

        public string SelectedNameClientId
        {
            get {return _selectedNameClientId;}
            set {_selectedNameClientId = value;}
        }

        private List<Customer> customerList;

        public List<Customer> Customer
        {
            get { return customerList; }
            set { customerList = value; }
        }

        public Argument()
        {

        }
    }
    public class Customer
    {
        private string _customerType;
        private string _customerText;
        private string _customerValue;

        public string ObjectType
        {
            get { return _customerType; }
            set { _customerType = value; }
        }

        public string CustomerText
        {
            get { return _customerText; }
            set { _customerText = value; }
        }

        public string CustomerValue
        {
            get { return _customerValue; }
            set { _customerValue = value; }
        }

        public Customer(string strCustomerType, string strCustomerText, string strCustomerValue)
        {
            _customerType = strCustomerType;
            _customerText = strCustomerText;
            _customerValue = strCustomerValue;
        }

        public Customer()
        {

        }
    }

The purpose of these objects is to be passed along from the “main” page to the “lookup” page to be processed further.

Refer to the sample result of these objects on the JSON string format for one Customer

{"FilterComboType":"NameOfClient","SelectedNameClientId":null,"Customer":[{"ObjectType":"account","CustomerText":"Account E","CustomerValue":"c0b377cf-1766-de11-8f5c-0003ffb4d763"}]}

and here is the sample JSON string result for multiple Customers

{"FilterComboType":"ContactList","SelectedNameClientId":null,"Customer":[{"ObjectType":"contact","CustomerText":"Lim","CustomerValue":"e0203ac0-2a3d-de11-8641-0003ffc4d675"},{"ObjectType":"contact","CustomerText":"Contact B","CustomerValue":"a0ff10e6-1766-de11-8f5c-0003ffb4d763"},{"ObjectType":"contact","CustomerText":"Contact C","CustomerValue":"9088e0ec-1766-de11-8f5c-0003ffb4d763"}]}

What are the advantages of creating JSON string format ?

you can access those objects at the client side easily, in example :

function AccessArgument(arg)
{
  var jsonStringArgument = arg;
  var argument = eval(jsonStringArgument);

  var filterComboTypeValue = argument.FilterComboType;

  for(var i=0; i<argument.Customer.length; i++)
  {
    var customerValue = argument.Customer[i].CustomerValue;
  }
}

Notice how easily i’m accessing a list of the argument’s Customer in array object at the client side

How do you convert from JSON string to the actual object itself ?

var objectArgument = eval('a Json String');

How do you convert from actual object back to the JSON string ? You need json2.js which can be downloaded here . The javascript file needs to be included in the html head.

var jsonText = JSON.stringify(objectArgument);

I like to use Newtonsoft JSON.NET to serialize my C# object to the JSON string format as well as deserialize my C# object back to the JSON string format

Here are the code sample how to serialize the Argument object into JSON string

txtAccountListJson.Text = Newtonsoft.Json.JavaScriptConvert.SerializeObject(newArg);

And here are the code sample in how to serialize the JSON string back to the actual object

Argument arg = (Argument)Newtonsoft.Json.JavaScriptConvert.DeserializeObject(txtContactListJson.Text, typeof(Argument));

June 27, 2009

what is the difference between RetrieveRequest and RetrieveMultipleRequest

Filed under: Dynamics CRM — haditeo @ 10:43 am
Tags: ,

RetrieveRequest is used to retrieve one and only one record based on the unique EntityId while RetrieveMultipleRequest can be used to retrieve one or many records based on the selection criteria.

You can use RetrieveMultipleRequest to retrieve a particular record based on EntityId, usually i create a helper method by using RetrieveMultipleRequest to retrieve particular records based on selection criteria

Here is the example of using RetrieveRequest. Our scenario is retrieving a particular account based on accountid attribute

public DynamicEntity RetrieveByUsingRetrieveRequest(CrmService service, Guid accountId)
{
    TargetRetrieveAccount target = new TargetRetrieveAccount();
    target.EntityId = accountId;

    RetrieveRequest request = new RetrieveRequest();
    request.Target = target;

    // retrieve all attributes of the particular account
    request.ColumnSet = new AllColumns();

    // tell the CRM SDK to return the result as DynamicEntity type of object
    request.ReturnDynamicEntities = true;
    RetrieveResponse response = (RetrieveResponse) service.Execute(request);

    DynamicEntity de = (DynamicEntity)response.BusinessEntity;

    return de;
}

and here is the example of using RetrieveMultipleRequest

public DynamicEntity RetrieveByUsingRetrieveMultipleRequest(CrmService service, Guid accountId)
{
    QueryExpression query = new QueryExpression();
    query.EntityName = "account";

    ConditionExpression ceAccount = new ConditionExpression();
    ceAccount.AttributeName = "accountid";
    ceAccount.Operator = ConditionOperator.Equal;
    ceAccount.Values = new object[] {accountId};

    FilterExpression feAccount = new FilterExpression();
    feAccount.AddCondition(ceAccount);
    feAccount.FilterOperator = LogicalOperator.And;

    query.Criteria.AddFilter(feAccount);

    // retrieve all attributes of the particular account
    query.ColumnSet = new AllColumns();

    RetrieveMultipleRequest request = new RetrieveMultipleRequest();
    request.Query = query;

    // tell the CRM SDK to return the result as DynamicEntity type of object
    request.ReturnDynamicEntities = true;

    RetrieveMultipleResponse response = (RetrieveMultipleResponse) service.Execute(request);

    DynamicEntity de = (DynamicEntity)response.BusinessEntityCollection.BusinessEntities[0];

    return de;
}

Note :

  • ReturnDynamicEntities property can be used to configure the CRM SDK either to return the result as Dynamic Entity or Proxy Class
  • The disadvantage of using RetrieveRequest is the query can only be implemented by querying the entity-id. Usually our goal is to obtain the particular entity-id by querying certain criteria.

    Let me elaborate further. Suppose you like to know which accounts residing in Singapore, you can query like this SELECT * FROM account where city=’Singapore’ and it will return the list of accounts complete with the account id

    It’s not useful to use RetrieveRequest, if we know ahead all accounts, means SELECT * FROM account where accountid = ‘3F2504E0-4F89-11D3-9A0C-0305E82C3301′

    Usually our targets are the Unique Identifiers.

June 25, 2009

How to: Add the CrmService Web Reference

Filed under: Dynamics CRM — haditeo @ 9:29 pm
Tags: ,

I seldom use CRM Service proxy Web Reference and i almost forgot that there is a difference in invoking the web service between CRM 3.0 and CRM 4.0

Here is the CRM 3.0 way:

http://<your server name>/mscrmservices/2006/crmservice.asmx

and here is the CRM 4.0 way:

http://<servername[:port]>/mscrmservices/2007/crmservice.asmx?WSDL&uniquename=organizationName

No wonder when i invoke using below code, i still can obtain the CrmService, but i cannot find any proxy entities there

http://<your server name>/mscrmservices/2007/crmservice.asmx

After i using the correct way, i can refer to the CRM entities through intellisense as usual
class_account

intellisense

I forgot that in the CRM 4.0, there is a multitenancy concept, so we can create multiple organization within one Dynamics CRM deployment, so to refer to the particular organization CRM entities, we can customize the organization name below

http://<servername[:port]>/mscrmservices/2007/crmservice.asmx?WSDL&uniquename=organizationName

Type.GetType() return null value

Filed under: Dynamics CRM — haditeo @ 9:06 pm

Here are my code snippet that returning null value when invoking Type.GetType()

        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;
            }

        }

The above codes are working well when i have tested by testing the dll using NUnit. But when i deployed it as a custom workflow activity, these code snippet returned null value. There is an IOException complained by the system. In the details of the Exception, it’s mentioned that it cannot find the microsoft.crm.sdk.dll at the ‘c:\windows\system32′. I have tried to copy the code manually to \windows\system32 but it still cannot find the correct dll, maybe i should register it through the GAC.

Type currentCrmTypeProperty = sdkDll.GetType("Microsoft.Crm.Sdk." + crmTypeProperty);

Anyway, i have another alternative by directly using Type.GetType as shown below. I was reluctant to use the Full Assembly Qualified Name, but somehow when referring to microsoft.crm.sdk.KeyProperty, it still cannot find, unless i specified Full Qualified Name

 Type currentCrmTypeProperty = Type.GetType("Microsoft.Crm.Sdk." + crmTypeProperty + ", Microsoft.Crm.Sdk, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35");

And here are the modified code

        public Opportunity ToOpportunity(DynamicEntity de)
        {
            try
            {
                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 = Type.GetType("Microsoft.Crm.Sdk." + crmTypeProperty + ", Microsoft.Crm.Sdk, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"); 

                        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;
            }

        }

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)
    
Next Page »

Blog at WordPress.com.