Send an appointment in MS CRM as Calendar Item For Attendees

Hi All,

I have got a requirement recently from one of my Client to send appointment to Attendees as outlook calendar item so that attendee can respond to Appointment directly.

This has Done by me through a plugin in MS CRM. Plugin is written on Post Create/Update.

Approach is followed As below :

Step 1:

Reading Appointment from Context and Retrieving Required Attendees and Optional Attendees.

Appointment = (Entity)context.InputParameters[“Target”];

EntityCollection requiredAttendes = Appointment.Attributes.Contains(“requiredattendees”) ? Appointment.GetAttributeValue<EntityCollection>(“requiredattendees”) : null;

EntityCollection optionalAttendes = Appointment.Attributes.Contains(“optionalattendees”) ? Appointment.GetAttributeValue<EntityCollection>(“optionalattendees”) : null;

 

Here Required Attendees and Optional Attendees are of type “Activity Party”

Step 2:

Creating A calendar Item Based on start date and End Date

private StringBuilder CreateCalendarItem()
{

StringBuilder str = new StringBuilder();
str.AppendLine(“BEGIN:VCALENDAR”);
str.AppendLine(“PRODID:-//” + “Email”);
str.AppendLine(“VERSION:2.0”);
str.AppendLine(“METHOD:REQUEST”);
str.AppendLine(“BEGIN:VEVENT”);
str.AppendLine(string.Format(“DTSTART:{0:yyyyMMddTHHmmssZ}”, startTime.ToString(“yyyyMMdd\\THHmmss\\Z”)));
str.AppendLine(string.Format(“DTSTAMP:{0:yyyyMMddTHHmmssZ}”, (endTimestartTime).Minutes.ToString()));
str.AppendLine(string.Format(“DTEND:{0:yyyyMMddTHHmmssZ}”, endTime.ToString(“yyyyMMdd\\THHmmss\\Z”)));
str.AppendLine(“BEGIN:VALARM”);
str.AppendLine(“TRIGGER:-PT15M”);
str.AppendLine(“ACTION:DISPLAY”);
str.AppendLine(“DESCRIPTION:Reminder”);
str.AppendLine(“END:VALARM”);
str.AppendLine(“END:VEVENT”);
str.AppendLine(“END:VCALENDAR”);
return str;
}

Here Start Time and End time is Appointment Start Time and Appointment End Time

Step 3:

Make this Calendar item As Mime Attachment for Email

private Entity CreateAttachment(emailId)
{

Entity attachment = new Entity(“activitymimeattachment”);

attachment[“subject”] = “Appointment”;

string fileName = “Appointment.ics”;

attachment[“filename”] = fileName;

byte[] fileStream = Encoding.ASCII.GetBytes(CreateCalendarItem().ToString()); //Set file stream bytes

attachment[“body”] = Convert.ToBase64String(fileStream);

attachment[“mimetype”] = “text/calendar”;

attachment[“attachmentnumber”] = 1;

attachment[“objectid”] = new EntityReference(“email”, emailId);// Create Email Id

attachment[“objecttypecode”] = “email”;
return attachment;
}

Step 4:

Create and Email and Attach this Mime Attachment to email and Send Email

 

private void CreateEmail(Entity fromParty, List<Entity> toParties, List<Entity> ccParties = null)
{
Entity email = new Entity(“email”);
email[“from”] = new Entity[] { fromParty };
email[“to”] = toParties.ToArray();
if (ccParties != null)
{
if (ccParties.Count > 0)
{
email[“cc”] = ccParties.ToArray();
}
}
email[“subject”] = “Appointment”;
var emailId = service.Create(email);
// SendEmailUsingTemplate(email);
Entity attachement = CreateAttachment( emailId);
service.Create(attachement);
SendEmailRequest emailRequest = new SendEmailRequest
{
EmailId = emailId,
IssueSend = true,
TrackingToken = “CRM”
};
service.Execute(emailRequest);

}

This Sends email with Calendar Item

Issues Faced:

Reading Party Id from Required/Optional Attendees:

Even though Required/Optional Attendees are activity parties we cannot use them directly in email .  Inorder to we use them we need to know their Party Id . It can be done as below

Entity toParty = new Entity(“activityparty”);
toParty[“partyid”] = requiredAttendes.Entities.FirstOrDefault().GetAttributeValue<EntityReference>(“partyid”);

Missing of Encoding of Calendar Item while Creating ah Mime attachment:

Encoding of Calendar Item need to be done to make it as mime Attachment

byte[] fileStream = Encoding.ASCII.GetBytes(CreateCalendarItem().ToString()); //Set file stream bytes

Advertisements

Split List in C# with a batch size N

Hi All,

Sometimes we split List into batches based on our requirement. Use below code to split List into batches of Size N

public IEnumerable<List<T>> SplitList<T>(List<T> locations, int nSize = N)
{
for (int i = 0; i < locations.Count; i += nSize)
{
yield return locations.GetRange(i, Math.Min(nSize, locations.Count – i));
}
}

Here N is of Data Type int and we can assign the batch size

Hope this helps 🙂

Replace Invalid XML characters in Fetch XML in Microsoft Dynamics CRM

Hi All,

Use below method to replace Invalid XML characters in Fetch XML in C#.

private string ReplaceXmlCharacters(string characterToReplace)
{
characterToReplace = characterToReplace.Replace(“<“, “<”);
characterToReplace = characterToReplace.Replace(“>”, “>”);
characterToReplace = characterToReplace.Replace(“&”, “&”);
characterToReplace = characterToReplace.Replace(“‘”, “'”);
characterToReplace = characterToReplace.Replace(“\””, “"”);
return characterToReplace;
}

 

Hope this helps 🙂

Compare Two lists in C#

Hi All,

Below is the code to compare two lists and return the list that has the records that are not available another list

public List<class> compareAndReturn(List<Class> A, List<Class> B)
{
List<Class> result = new List<Class>();
foreach (var item in A)
{
if (!B.Exists(r => r.Id == item.Id))
{
result.Add(item);
}
}
return result;
}

Here list is of type Class in C#

Hope this helps : )

Retrieve accounts from Marketing List of Type “Dynamic” in CRM 2016

Hi All,

It is possible to retrieve accounts from Marketing List of Type “Dynamic” in CRM  in C#.

Below is the code to retrieve accounts.

 

private void getDynamicListMembers(Guid ListId)
{
RetrieveAccounts retrieveDynamicAccount = new RetrieveAccounts();
ColumnSet cols = new ColumnSet(new string[] { “query” });
var entity = service.Retrieve(“list”, ListId, cols);
var dynamicQuery = entity.Attributes[“query”].ToString();
EntityCollection dynamicAccounts = service.RetrieveMultiple(new FetchExpression(dynamicQuery));
}

here

ListId — Marketing List Id of type “Dynamic”

Hope this helps 🙂

 

Retrieve Marketing Lists from Campaigns

Hi ,

Recently i had a client scenario , that all Marketing lists that are associated to Campaign need to be retrieved.

At first i have checked the relationship between Campaign and Marketing List. it is N:N. So i thought to write a query expression as normally as Custom entities.

But in my checking i realized that Marketing lists associated to campaigns cannot be retrieved directly and it should be retrieved by using Intersect entity same as Retrieving accounts from Marketing List.

Intersect Entity : Campaign Item

Query Expression to retrieve all Marketing Lists from Campaign :

QueryExpression qe = new QueryExpression ();

qe.EntityName =”list”

ColumnSet col = new ColumnSet(True);

LinkEntity le = new LinkEntity();
le.LinkFromEntityName = “list”
le.LinkFromAttributeName = “listid”;
le.LinkToEntityName = “campaignitem”;
le.LinkToAttributeName = “entityid”;

LinkEntity le2 = new LinkEntity();
le2.LinkFromEntityName = “campaignitem”
le2.LinkFromAttributeName = “campaignid”;
le2.LinkToEntityName = “campaign”;
le2.LinkToAttributeName = “campaignid”;

le2.LinkCriteria.Add(“campaignid”,ConditionOperator.Equal,CampaignGuid);

le.LinkEntities.Add(le2);

qe.LinkEntities.Add(le);

EntityCollection MarketingLists = service.RetriveMultiple(qe);

Hope this helps 🙂

 

 

Bulk Edit and Restriction of bulk edit in Microsoft Dynamics CRM

Hi all,

This post may be very old on bulk edit feautre in Microsoft Dynamics CRM but hope this gives some more information on bulk edit.

Bulk Edit in Microsoft Dynamics CRM:

Editing record is very easy in Microsoft Dynamics CRM.But what if we need to edit a field of all records with same value. So here, Instead of opening records one by one and editing it, we can also use Bulk edit feature which edits that field in one go for all records.

Limitations:

Not so good for large numbers of customer records where results ‘go onto the next page’ of the results grid – you can only select one page of results at a time so you would need to repeat the bulk edit steps.

By default the scripts are disabled for bulk edit forms.But we can enable on load and on change event scripts for bulk edit.

On save scripts will not be triggered while performing Bulk Edit

Restriction of Bulk Edit for particular records:

Because of its limitations thought of Exploring a bit more on bulk edit with a requirement  restricting bulk edit of different owner records.

Steps:

  1. Created a custom entity .Bulk edit previllege will not be available for users unless miscelleaneous previllege Bulk Edit is enabled.Capture
  2. Inorder to restrict bulk edit for particular records , create a enable rule(custom javascript rule) for this button and add a parameter “CRM Parameter” for this enable rule and the name of this parameter “selectedcontrolselecteditemreferences“.
  3. This will retrieve all the selected records by the user for bulk edit

Javascript code:

function run(selectedItems)
{
    
    var selectedItem = selectedItems[0];
    alert(“Id=” + selectedItem.Id + “\nName=” + selectedItem.Name + “\nTypeCode=” + selectedItem.TypeCode.toString() + “\nTypeName=” + selectedItem.TypeName);
}
Here
selectedItem.Id — Selected record Guid
selectedItem.Name — Selected record Name
selectedItem.TypeCode — Entity Type code 
selectedItem.TypeName — Entity schema Name
By using record details we can perform our required actions on bulk edit . We can hide/show edit button based on our requirement .
Javascript for hiding a ribbon button :
function hideRibbonButton()
{
if(selectedItem!=null)
{
return true; // Shows button
}
else
{
return false; // Hides button
}
}
Enabling javascripts on Bulk Edit:

By default the scripts are disabled for bulk edit forms.

To enable the script for Bulk edit forms check the below syntax

<event
active=[“0” “1” “true” “false”]application=[“0” “1” “true” “false”]attribute=”String”
BehaviorInBulkEditForm=”String”
eventType=[“DataEvent” “ControlEvent”]name=”String”></event

Export the entity as solution from CRM system by adding the required entity where bulk edit need to be enabled along with javascript. By default server side events gets enabled for bulk edit. But inorder to enable client side events, open the file  called Customizations.xml from downloaded solution and find  <formlibraries>.

Capture

Note: Microsoft Dynamics CRM provides multi forms and you can enable for single form or multiple forms.

Save and Import the solution, publish it. Now javascript gets enabled on the solution

Performing Bulk Create,Update,Delete by using C# ExecuteMultipleRequest:

Bulk Create:

 

/// <summary>
   /// Call this method for bulk Create
   /// </summary>
   /// <param name="service">Org Service</param>
   /// <param name="entities">Collection of entities to Create</param>
   public static void BulkCreate(IOrganizationService service, DataCollection<Entity> entities)
   {
       // Create an ExecuteMultipleRequest object.
       var multipleRequest = new ExecuteMultipleRequest()
       {
           // Assign settings that define execution behavior: continue on error, return responses.
           Settings = new ExecuteMultipleSettings()
           {
               ContinueOnError = false,
               ReturnResponses = true
           },
           // Create an empty organization request collection.
           Requests = new OrganizationRequestCollection()
       };
 
       // Add a CreateRequest for each entity to the request collection.
       foreach (var entity in entities)
       {
           CreateRequest createRequest = new CreateRequest { Target = entity };
           multipleRequest.Requests.Add(createRequest);
       }
 
       // Execute all the requests in the request collection using a single web method call.
       ExecuteMultipleResponse multipleResponse = (ExecuteMultipleResponse)service.Execute(multipleRequest);
 
   }

 

Bulk Update:

/// <summary>
   /// Call this method for bulk update
   /// </summary>
   /// <param name="service">Org Service</param>
   /// <param name="entities">Collection of entities to Update</param>
   public static void BulkUpdate(IOrganizationService service, DataCollection<Entity> entities)
   {
       // Create an ExecuteMultipleRequest object.
       var multipleRequest = new ExecuteMultipleRequest()
       {
           // Assign settings that define execution behavior: continue on error, return responses.
           Settings = new ExecuteMultipleSettings()
           {
               ContinueOnError = false,
               ReturnResponses = true
           },
           // Create an empty organization request collection.
           Requests = new OrganizationRequestCollection()
       };
 
       // Add a UpdateRequest for each entity to the request collection.
       foreach (var entity in entities)
       {
           UpdateRequest updateRequest = new UpdateRequest { Target = entity };
           multipleRequest.Requests.Add(updateRequest);
       }
 
       // Execute all the requests in the request collection using a single web method call.
       ExecuteMultipleResponse multipleResponse = (ExecuteMultipleResponse)service.Execute(multipleRequest);
 
   }

 

Bulk Delete:

/// <summary>
   /// Call this method for bulk delete
   /// </summary>
   /// <param name="service">Org Service</param>
   /// <param name="entityReferences">Collection of EntityReferences to Delete</param>
   public static void BulkDelete(IOrganizationService service, DataCollection<EntityReference> entityReferences)
   {
       // Create an ExecuteMultipleRequest object.
       var multipleRequest = new ExecuteMultipleRequest()
       {
           // Assign settings that define execution behavior: continue on error, return responses.
           Settings = new ExecuteMultipleSettings()
           {
               ContinueOnError = false,
               ReturnResponses = true
           },
           // Create an empty organization request collection.
           Requests = new OrganizationRequestCollection()
       };
 
       // Add a DeleteRequest for each entity to the request collection.
       foreach (var entityRef in entityReferences)
       {
           DeleteRequest deleteRequest = new DeleteRequest { Target = entityRef };
           multipleRequest.Requests.Add(deleteRequest);
       }
 
       // Execute all the requests in the request collection using a single web method call.
       ExecuteMultipleResponse multipleResponse = (ExecuteMultipleResponse)service.Execute(multipleRequest);
   }

Hope this helps 🙂