Wednesday, August 5, 2009

MS CRM : Creating bulk deletion job

Microsoft Dynamics CRM 4.0 allow users to bulk delete records using its interface, but is limited to a maximum of 250 records at a time. This is not a feasible solution if you have thousands of records to be deleted as a part of the campaign process.

CRM 4.0 supports bulk delete operation, but this functionality is not available out of box. You have to create an application which could perform this job using Dot Net.

The below code explains how you could perform a bulk delete operation on the leads entity.

You have to specify the Entity where the record need to be deleted and the Array of Lead Id's which needs to be deleted.

static void CreateBulkDeleteProcess()
{
try
{

// Create a query expression that retrieves all records for the entity.
QueryExpression qry = new QueryExpression();
qry.EntityName = EntityName.lead.ToString();
qry.ColumnSet = new AllColumns();

// Retrieve the accounts where the last name is not Cannon.
ConditionExpression condition = new ConditionExpression();
condition.AttributeName = "leadid";
condition.Operator = ConditionOperator.Equal;
condition.Values = new string[] { leadArray.ToString() };

// Build the filter based on the condition.
FilterExpression filter = new FilterExpression();
filter.FilterOperator = LogicalOperator.And;
filter.Conditions.Add(condition);
qry.Criteria = filter;

// Create a request.
BulkDeleteRequest request = new BulkDeleteRequest();
request.JobName = "Delete (" + iLoop +") + " lead records";
request.QuerySet = new QueryBase[] { qry };
request.SendEmailNotification = false;
request.ToRecipients = new Guid[0];
request.CCRecipients = new Guid[0];
request.RecurrencePattern = string.Empty;
request.StartDateTime = new CrmDateTime();
TimeSpan ts = new TimeSpan(0, 5, 0);
request.StartDateTime.Value = DateTime.Now.Add(ts).ToString("s");

// Execute the request.
BulkDeleteResponse response = (BulkDeleteResponse)oService.Execute(request);
Guid jobId = response.JobId;
Console.WriteLine("Job Id: " + jobId.ToString());
}
catch (Exception ex)
{
string sMsg = "Error creating deletion job for " + sEntityName + ": " + ex.Message;
throw new Exception(sMsg, ex);
}
}

We can schedule the start time for the bulk delete operation and leave it run during the off peak hours. Also an email notification to the user who needs to be intimated regarding this task could be allocated. If this process needs to be recurrent, a recurrent pattern could be defined.

This is really a cool way of deleting the records rather than going through the hurdles which CRM gives for bulk delete process.

How to read a excel/csv file using c#

Dot net provides different mechanism to read files. The problem occurs when you have large files to be read and processed. I had was wondering what difference a String and StringBuilder could make in the performance of manipulating a string record.

The real difference is too high while using String instead of StringBuilder and the system even reboots if the processing file size is too high.

public static string ReadCsvFile(string filePath)
{
StreamReader reader = null;
StringBuilder data = new StringBuilder();
string value = null;
using (reader = new StreamReader(filePath))
{
value = reader.ReadLine();
while (value!= null)
{
data.AppendLine(value);
}
}
return data. ToString ();
}


The Method above uses StreamReader, which is a light weight .net class which could read the CSV or Excel file line by line without giving the system too much hurdle.

The StringBuilder uses less memory by allocating the same memory for the new text appended to it without creating more memory space like the string.

This set of code runs very fast and without any memory leakage.

Send plain email messages using BizTalk SMTP Adapter

The new SMTP adapter provides the facility to send text/plain messages without using external classes or having more hazel.

Create a Message to be send which is of type System.String. Set the message SMTP values as follows in a Message Assignment shape.

EmailMessage = System.String.Empty;
EmailMessage(SMTP.Subject) = "Hello World!";
EmailMessage(SMTP.EmailBodyText) = "My Test Message"; // Text message body.
EmailMessage(SMTP.EmailBodyTextCharset) = "UTF-8";
EmailMessage(Microsoft.XLANGs.BaseTypes.ContentType) = "text/plain";
SMTPSendPrt(Microsoft.XLANGs.BaseTypes.Address) = "mailto:bts@test.com";

In the above case I am using a dynamic send port, so I need to set the send port address before I send the message.

Microsoft.XLANGs.BaseTypes.Address , is used to set the address location of the message. You have to use "mailto:", as specified above in the address location.

If you have to send messages to more than one person, you can either set the "SMTP.CC" property, or you can use a ';' to delimit the email addresses.

SMTP.EmailBodyTextCharset is by default set as 'None', so has to be set explicitly to 'UTF-8'. Otherwise, BizTalk will throw strange run time errors.

Post any comments if you have. Enjoy!

Saturday, August 1, 2009

MS CRM : Update hotlist using plugin

Microsoft Dynamics CRM 4.0 offers a lot of functionality in terms of Customer relations management and sales process. It could be highly customised and flexible enough to satisfy the user requirement.

Microsoft Dynamics CRM 4.0, Plug ins are very powerful and are highly extensible within Dynamics CRM for overriding the limitations of Microsoft Dynamics CRM 4.0. The hotlist are one of the major component of Dynamics CRM, and it has some limitations in querying the information's required. Plug ins can be used to define the criteria and the use FetchXML query to get the information required.

Plug ins and IPluginExecutionContext

CRM SDK provides the list of Messages and entities which could be used for registering a plug in.

"Execute" is one of the Message type which could be used to register a plug in to trigger when an execute event is fired within CRM for a hotlist. The Execute message doesn't allow you to specify the primary or secondary entity, and will run within the logged in users context. There is Pre Stage and Post Stage stages for the pipeline execution and this could be used for both the Asynchronous and Synchronous execution modes.

The code below could be used to override the hotlist using the FetchXML and replacing it with the criteria required to return the exact result set. The
"context.InputParameters.Properties["FetchXml"]" gives you the currently executed query from CRM and this could be used if you just need to update the criteria only.


public class PeopleHotListViewsPlugin : IPlugin
{
public void Execute(IPluginExecutionContext context)
{
ICrmService vService = context.CreateCrmService(true);

if (context.InputParameters != null)
{
if (context.InputParameters.Properties.Contains("FetchXml"))
{

string fetch1 = @"
<fetch mapping='logical'>
<entity name='account'>
<attribute name='accountid'/>
<attribute name='name'/>
<link-entity name='systemuser' to='owninguser'>
<filter type='and'>
<condition attribute='lastname' operator='ne' value='Cannon' />
</filter>
</link-entity></entity></fetch>";

context.InputParameters.Properties["FetchXml"] = fetch1
}
}
}
}



The plug in should be registered using the Execute message as shown below.



The plug in will be executed each time a hotlist is called, but could be limited to the specific hotlist by matching the FetchXMl Entity node and adding a specific criteria to identify the hotlist.

Thanks
Abish Asharaf