Category Archives: Development

Development

Handle birthdays in Microsoft CRM 2011/2013

The birthday field in Microsoft Dynamics CRM in the contact entity is nice, but if you want to see the birthdays today or even want to have the birthdays in your calendar you have to spend some effort. Some solutions split the birthday-date in several fields for processing => day, month. Or they use a workflow to set the next birthday.

Here I want to describe a new approach. Why don’t we use the recurring appointment for displaying the birthdates. This is a standard entity and synchronized with outlook.

Basically it is a plugin. Additionally you add a lookupfield to the contact entity to have a reference to the master recurring appointment entity.

Birthday PluginSample

 

In your code replace this name with your custom attributename:

private string appointment_birthday_attribute_name = "soho_birthday";

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Client;
using Microsoft.Xrm.Sdk.Linq;
using Microsoft.Xrm.Sdk.Query;

namespace CRM_2011_Plugins
{
    public class soho_birthday : IPlugin
    {
        public enum RecurrenceRulePatternEndType
        {
            NoEndDate = 1,
            Occurrences = 2,
            PatternEndDate = 3
        };

        public enum RecurrencePatternTypes
        {
            Daily = 0,
            Weekly = 1,
            Monthly = 2,
            Yearly = 3
        };

        public enum DayOfWeek
        {
            Sunday = 0x01,
            Monday = 0x02,
            Tuesday = 0x04,
            Wednesday = 0x08,
            Thursday = 0x10,
            Friday = 0x20,
            Saturday = 0x40
        };

        private string appointment_birthday_attribute_name = "soho_birthday";

        public void Execute(IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            ITracingService tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));

            if (context.InputParameters.Contains("Target") && context.InputParameters["Target"] is Entity)
            {
                Entity entity = (Entity)context.InputParameters["Target"];
                if (entity.LogicalName == "contact" && entity.Attributes.Contains("birthdate"))
                {
                    //  if the entity is created => create the recurring appointment and update your lookupfield with the created master
                    if (context.MessageName == "Create")
                    {
                        Entity newRecurringAppointment = this.createRecurringAppointment(entity, context.UserId);
                        Guid recurringappointmentmasterID = service.Create(newRecurringAppointment);
                        Entity cUpdate = new Entity("contact");
                        cUpdate.Id = entity.Id;
                        cUpdate.Attributes.Add(appointment_birthday_attribute_name, new EntityReference("recurringappointmentmaster", recurringappointmentmasterID));
                        service.Update(cUpdate);
                    }
                    // If the entity is updated get the "old" contact
                    if (context.MessageName == "Update")
                    {
                        if (entity.LogicalName == "contact" && entity.Attributes.Contains("birthdate"))
                        {
                            Entity oldContact = service.Retrieve("contact", entity.Id, new ColumnSet(new string[] { "fullname", "ownerid", appointment_birthday_attribute_name }));
                            // if a birthday is set to null it means the birthday filed was deleted. 
                            //In this case we delete the recurring appointment
                            if (entity.Attributes["birthdate"] != null)
                            {
                                // we need the contacts fullname for the subject. so if we do not update the field we get it from the "old" contact
                                if (!entity.Attributes.Contains("fullname"))
                                    entity.Attributes.Add("fullname", oldContact["fullname"]);

                                Guid? OwnerID = null;
                                if (entity.Attributes.Contains("ownerid"))
                                {
                                    OwnerID = ((EntityReference)entity["ownerid"]).Id;
                                }
                                else
                                {
                                    OwnerID = ((EntityReference)oldContact["ownerid"]).Id;
                                }

                                // Create a new recurringappointment
                                Entity newRecurringAppointment = this.createRecurringAppointment(entity, OwnerID);

                                // If there is a existing recurringappointment pointing to birthday update this entity, else create a new one
                                if (oldContact.Attributes.Contains(appointment_birthday_attribute_name))
                                {
                                    newRecurringAppointment.Id = ((EntityReference)oldContact[appointment_birthday_attribute_name]).Id;
                                    service.Update(newRecurringAppointment);
                                    entity[appointment_birthday_attribute_name] = new EntityReference("recurringappointmentmaster", newRecurringAppointment.Id);
                                }
                                else
                                {
                                    Guid recurringappointmentmasterID = service.Create(newRecurringAppointment);
                                    entity.Attributes.Add(appointment_birthday_attribute_name, new EntityReference("recurringappointmentmaster", recurringappointmentmasterID));
                                }

                            }
                            else
                            {
                                if (oldContact.Attributes.Contains(appointment_birthday_attribute_name))
                                {
                                    service.Delete("recurringappointmentmaster", ((EntityReference)oldContact[appointment_birthday_attribute_name]).Id);
                                    entity[appointment_birthday_attribute_name] = null;
                                }
                            }
                        }
                    }
                }
            }
        }

        // Creates an recurring appointment
        public Entity createRecurringAppointment(Entity entity, Guid? OwnerID)
        {
            // if the contact has an owner use his id to create a required attendee
            Guid? ownerid = null;
            if (entity.Attributes.Contains("ownerid"))
            {
                ownerid = ((EntityReference)entity["ownerid"]).Id;
            }
            else
            {
                if (OwnerID != null)
                {
                    ownerid = OwnerID.Value; ;
                }
            }

            // Create a recurring appointment
            Entity newRecurringAppointment = new Entity("recurringappointmentmaster");
            DateTime birthday = (DateTime)entity["birthdate"];
            // its a allday event
            newRecurringAppointment.Attributes.Add("isalldayevent", true);
            if (entity.Attributes.Contains("fullname"))
            {
                newRecurringAppointment.Attributes.Add("subject", "Geburtstag von " + entity["fullname"].ToString());
            }
            // set the reagrding filed to the contact
            newRecurringAppointment.Attributes.Add("regardingobjectid", new EntityReference(entity.LogicalName, entity.Id));
            // Birthday is recurring once a year
            newRecurringAppointment.Attributes.Add("recurrencepatterntype", new OptionSetValue((int)RecurrencePatternTypes.Yearly));
            // start the pattern today
            newRecurringAppointment.Attributes.Add("patternstartdate", DateTime.Today);
            // Dont stop the recurring appointment at a certain date
            newRecurringAppointment.Attributes.Add("patternendtype", new OptionSetValue((int)RecurrenceRulePatternEndType.NoEndDate));
            // every year => interval = 1
            newRecurringAppointment.Attributes.Add("interval", 1);
            // Set the day (zero-based!)
            newRecurringAppointment.Attributes.Add("dayofmonth", birthday.Day + 1);
            // set the month
            newRecurringAppointment.Attributes.Add("monthofyear", new OptionSetValue(birthday.Month));
            // pretty useless because its a all day event, but if this is not set, the start and end-date were set incorrectly
            newRecurringAppointment.Attributes.Add("starttime", DateTime.Now);
            newRecurringAppointment.Attributes.Add("endtime", DateTime.Now.AddHours(1));

            // set the required attendee
            if (ownerid != null)
            {
                Entity activityparty = new Entity("activityparty");
                activityparty.Attributes.Add("partyid", new EntityReference("systemuser", ownerid.Value));
                newRecurringAppointment.Attributes.Add("requiredattendees", new Entity[] { activityparty });
            }
            return newRecurringAppointment;
        }
    }
}

Thats it. Compile, Register, Enjoy…

 

PS: WHat I forgot to mention.

Register the Create / Contact Step als Postcreate and the Update / Contact Step as PreUpdate :-)

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Create a Rich-Text textarea in Microsoft CRM 2013 forms

ckeditor sample

Sometimes there is a need for creating HTML content within an entity. There are many websites with a how-to description, but be careful: most of them are unsupported! You can easily recognize those solutions. Whenever you find a javascript code which uses something like “document.getElementById()” or uses jquery to get or change attributes on a crm form … hands off. This is unsupported and might be a problem the next time you install an update rollup or upgrade to a new major release.

But it is very simple to build a rich text element. Here is an easy walktrough:

1) Identify the field you want to store the HTML code into. Best practice is to use a memo field, large enough to hold the whole content. You can use for example the description field in the contact entity, or something similar.

2) Download a free WYSIWYG editor. Personally I find the best choice is ckeditor, but you can use almost any other. You can download ckeditor from this site.

3) Create a html-webresource with more or less this content:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script src="../../ckeditor_/ckeditor/ckeditor.js"></script>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>

    <script type="text/javascript">
        CKEDITOR.timestamp = null;
        var Xrm;

        $(document).ready(function () {

            var Xrm = parent.Xrm;
            var voeb_eckdaten = Xrm.Page.getAttribute("description").getValue();
            document.getElementById('editor1').value = voeb_eckdaten;

            CKEDITOR.instances.editor1.on('blur', function () {
                var value = CKEDITOR.instances.editor1.getData();
                Xrm.Page.getAttribute("description").setValue(value);
            });

        });

    </script>
</head>
<body>
    <textarea class="ckeditor" cols="80" id="editor1" name="editor1" rows="10"></textarea>
</body>
</html>

In this example I used the description field for editing. This means of course you must have the field somewhere on the form.
What this code does is:
* wait until the document is in ready state
* get the content of the description field
* initialize ckeditor

It took me some time to recognize that ckeditor uses a parameter to avoid being cached, but if you leave the timestamp property on, crm will throw an error (500 server error). I disabled the timestamp setting the property to null.
ckeditor sample

So if you would like to use this in your crm deployment I added a solution with the complete ckeditor. I suggest to use a managed solution in your production environment, so if you want to get rid of ckeditor all you have to do is to uninstall the solution.

download unmanaged
download managed

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Microsoft Dynamics CRM 2013 – Plugin Messages – RetrieveMultiple– deep dive

Message Name Ownership Type Message Availability Entity Supported Deployment
RetrieveMultiple User-owned and organization-owned entities Both Server

The RetrieveMultiple Message is called when you open a view, and query entities with fetchxml or QueryExpression.

What happens when you retrieve a list of entities (in this case it is a list of open opportunities)  …

12.10.2013 19:53:42.004 :: INFO :: Entity: opportunity => Message: RetrieveMultiple => Stage: 10
12.10.2013 19:53:42.009 :: INFO :: Entity: opportunity => Message: RetrieveMultiple => Stage: 20
12.10.2013 19:53:42.014 :: INFO :: Entity: opportunity => Message: RetrieveMultiple => Stage: 40

The message has an input Parameters called “Query”. This is a fetchXml expression. In the example below I pressed on the button reload in the view “open opportunities”. As you an see the PrimaryEntityName is set to opportunity. On Stage 10 and 20 you still have the chance to change the fetchxml, but on stage 40 (post stage) you will find an outputparameter of tye BusinessEntityCollection which is a list of the returned entities (in our case the opportunities).

If you take a closer look at the inputParameter “Query” you will perhaps recognize that the fetchxml represents the FetchXml of the SavedQueryBase table in the sql database. There are only a few differences.

These three attributes are added for the view. The first parameter (page)  is the paging cookie, the count parameter is the number of records the view wants to retrieve and the returntotalrecordcount tells the query to return the total number of  records. If you go to the next page in the view the page variable is increased and so on …

page=”1″
count=”250″
returntotalrecordcount=”true”

Here is the corresponding context-log.

12.10.2013 19:53:41.931 :: INFO :: Start XrmLoggerPlugin ======================================================================== >>>
12.10.2013 19:53:41.931 :: INFO :: MessageName: RetrieveMultiple
12.10.2013 19:53:41.931 :: INFO :: PrimaryEntityName: opportunity
12.10.2013 19:53:41.931 :: INFO :: PrimaryEntityId: 00000000-0000-0000-0000-000000000000
12.10.2013 19:53:41.931 :: INFO :: Stage: 10
12.10.2013 19:53:41.931 :: INFO :: BusinessUnitId: 7647d68b-471d-e311-b013-000c2926dde4
12.10.2013 19:53:41.931 :: INFO :: CorrelationId: 55308b0f-0896-45a8-b653-605bb499f6eb
12.10.2013 19:53:41.931 :: INFO :: Depth: 1
12.10.2013 19:53:41.931 :: INFO :: InitiatingUserId: 0cd683a0-541d-e311-b013-000c2926dde4
12.10.2013 19:53:41.931 :: INFO :: InputParameters:
12.10.2013 19:53:42.004 :: INFO ::  >  Key: Query / Value: Microsoft.Xrm.Sdk.Query.QueryExpression  >> Queryexpression:
<fetch distinct="false" no-lock="true" mapping="logical" page="1" count="250" returntotalrecordcount="true"><entity name="opportunity"><attribute name="name" /><attribute name="estimatedvalue" /><attribute name="estimatedclosedate" /><attribute name="customerid" /><attribute name="opportunityratingcode" /><attribute name="closeprobability" /><attribute name="opportunityid" /><attribute name="name" /><attribute name="customerid" /><attribute name="estimatedclosedate" /><attribute name="estimatedvalue" /><attribute name="closeprobability" /><attribute name="opportunityratingcode" /><filter type="and"><condition attribute="statecode" operator="eq" value="0" /></filter><order attribute="estimatedclosedate" descending="false" /><link-entity name="contact" to="customerid" from="contactid" link-type="outer" alias="opportunitycustomeridcontactcontactid"><attribute name="emailaddress1" /></link-entity></entity></fetch>
12.10.2013 19:53:42.004 :: INFO :: IsExecutingOffline: False
12.10.2013 19:53:42.004 :: INFO :: IsInTransaction: False
12.10.2013 19:53:42.004 :: INFO :: IsOfflinePlayback: False
12.10.2013 19:53:42.004 :: INFO :: IsolationMode: 1
12.10.2013 19:53:42.004 :: INFO :: Mode: 0
12.10.2013 19:53:42.004 :: INFO :: OperationCreatedOn: 10/12/2013 5:53:41 PM
12.10.2013 19:53:42.004 :: INFO :: OperationId: 00000000-0000-0000-0000-000000000000
12.10.2013 19:53:42.004 :: INFO :: OrganizationId: eba3ca00-3338-49dd-b206-8ed1aacb1c3e
12.10.2013 19:53:42.004 :: INFO :: OrganizationName: crmdemo
12.10.2013 19:53:42.004 :: INFO :: OutputParameters:
12.10.2013 19:53:42.004 :: INFO :: 
12.10.2013 19:53:42.004 :: INFO :: OwningExtension: Microsoft.Xrm.Sdk.EntityReference
12.10.2013 19:53:42.004 :: INFO :: ParentContext: 
12.10.2013 19:53:42.004 :: INFO :: PostEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
12.10.2013 19:53:42.004 :: INFO :: PreEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
12.10.2013 19:53:42.004 :: INFO :: RequestId: 
12.10.2013 19:53:42.004 :: INFO :: SecondaryEntityName: none
12.10.2013 19:53:42.004 :: INFO :: SharedVariables: Microsoft.Xrm.Sdk.ParameterCollection
12.10.2013 19:53:42.004 :: INFO :: UserId: 0cd683a0-541d-e311-b013-000c2926dde4
12.10.2013 19:53:42.004 :: INFO :: Ende XrmLoggerPlugin ======================================================================== >>>

12.10.2013 19:53:42.006 :: INFO :: Start XrmLoggerPlugin ======================================================================== >>>
12.10.2013 19:53:42.006 :: INFO :: MessageName: RetrieveMultiple
12.10.2013 19:53:42.006 :: INFO :: PrimaryEntityName: opportunity
12.10.2013 19:53:42.006 :: INFO :: PrimaryEntityId: 00000000-0000-0000-0000-000000000000
12.10.2013 19:53:42.006 :: INFO :: Stage: 20
12.10.2013 19:53:42.006 :: INFO :: BusinessUnitId: 7647d68b-471d-e311-b013-000c2926dde4
12.10.2013 19:53:42.006 :: INFO :: CorrelationId: 55308b0f-0896-45a8-b653-605bb499f6eb
12.10.2013 19:53:42.006 :: INFO :: Depth: 1
12.10.2013 19:53:42.006 :: INFO :: InitiatingUserId: 0cd683a0-541d-e311-b013-000c2926dde4
12.10.2013 19:53:42.006 :: INFO :: InputParameters:
12.10.2013 19:53:42.006 :: INFO ::  >  Key: Query / Value: Microsoft.Xrm.Sdk.Query.QueryExpression  >> Queryexpression:
<fetch distinct="false" no-lock="true" mapping="logical" page="1" count="250" returntotalrecordcount="true"><entity name="opportunity"><attribute name="name" /><attribute name="estimatedvalue" /><attribute name="estimatedclosedate" /><attribute name="customerid" /><attribute name="opportunityratingcode" /><attribute name="closeprobability" /><attribute name="opportunityid" /><attribute name="name" /><attribute name="customerid" /><attribute name="estimatedclosedate" /><attribute name="estimatedvalue" /><attribute name="closeprobability" /><attribute name="opportunityratingcode" /><filter type="and"><condition attribute="statecode" operator="eq" value="0" /></filter><order attribute="estimatedclosedate" descending="false" /><link-entity name="contact" to="customerid" from="contactid" link-type="outer" alias="opportunitycustomeridcontactcontactid"><attribute name="emailaddress1" /></link-entity></entity></fetch>
12.10.2013 19:53:42.006 :: INFO :: IsExecutingOffline: False
12.10.2013 19:53:42.006 :: INFO :: IsInTransaction: False
12.10.2013 19:53:42.006 :: INFO :: IsOfflinePlayback: False
12.10.2013 19:53:42.006 :: INFO :: IsolationMode: 1
12.10.2013 19:53:42.006 :: INFO :: Mode: 0
12.10.2013 19:53:42.006 :: INFO :: OperationCreatedOn: 10/12/2013 5:53:42 PM
12.10.2013 19:53:42.006 :: INFO :: OperationId: 00000000-0000-0000-0000-000000000000
12.10.2013 19:53:42.006 :: INFO :: OrganizationId: eba3ca00-3338-49dd-b206-8ed1aacb1c3e
12.10.2013 19:53:42.006 :: INFO :: OrganizationName: crmdemo
12.10.2013 19:53:42.006 :: INFO :: OutputParameters:
12.10.2013 19:53:42.006 :: INFO :: 
12.10.2013 19:53:42.006 :: INFO :: OwningExtension: Microsoft.Xrm.Sdk.EntityReference
12.10.2013 19:53:42.006 :: INFO :: ParentContext: 
12.10.2013 19:53:42.006 :: INFO :: PostEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
12.10.2013 19:53:42.006 :: INFO :: PreEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
12.10.2013 19:53:42.006 :: INFO :: RequestId: 
12.10.2013 19:53:42.006 :: INFO :: SecondaryEntityName: none
12.10.2013 19:53:42.006 :: INFO :: SharedVariables: Microsoft.Xrm.Sdk.ParameterCollection
12.10.2013 19:53:42.006 :: INFO :: UserId: 0cd683a0-541d-e311-b013-000c2926dde4
12.10.2013 19:53:42.006 :: INFO :: Ende XrmLoggerPlugin ======================================================================== >>>

12.10.2013 19:53:42.011 :: INFO :: Start XrmLoggerPlugin ======================================================================== >>>
12.10.2013 19:53:42.011 :: INFO :: MessageName: RetrieveMultiple
12.10.2013 19:53:42.011 :: INFO :: PrimaryEntityName: opportunity
12.10.2013 19:53:42.011 :: INFO :: PrimaryEntityId: 00000000-0000-0000-0000-000000000000
12.10.2013 19:53:42.011 :: INFO :: Stage: 40
12.10.2013 19:53:42.011 :: INFO :: BusinessUnitId: 7647d68b-471d-e311-b013-000c2926dde4
12.10.2013 19:53:42.011 :: INFO :: CorrelationId: 55308b0f-0896-45a8-b653-605bb499f6eb
12.10.2013 19:53:42.011 :: INFO :: Depth: 1
12.10.2013 19:53:42.011 :: INFO :: InitiatingUserId: 0cd683a0-541d-e311-b013-000c2926dde4
12.10.2013 19:53:42.011 :: INFO :: InputParameters:
12.10.2013 19:53:42.014 :: INFO ::  >  Key: Query / Value: Microsoft.Xrm.Sdk.Query.QueryExpression  >> Queryexpression:
<fetch distinct="false" no-lock="true" mapping="logical" page="1" count="250" returntotalrecordcount="true"><entity name="opportunity"><attribute name="name" /><attribute name="estimatedvalue" /><attribute name="estimatedclosedate" /><attribute name="customerid" /><attribute name="opportunityratingcode" /><attribute name="closeprobability" /><attribute name="opportunityid" /><attribute name="name" /><attribute name="customerid" /><attribute name="estimatedclosedate" /><attribute name="estimatedvalue" /><attribute name="closeprobability" /><attribute name="opportunityratingcode" /><filter type="and"><condition attribute="statecode" operator="eq" value="0" /></filter><order attribute="estimatedclosedate" descending="false" /><link-entity name="contact" to="customerid" from="contactid" link-type="outer" alias="opportunitycustomeridcontactcontactid"><attribute name="emailaddress1" /></link-entity></entity></fetch>
12.10.2013 19:53:42.014 :: INFO :: IsExecutingOffline: False
12.10.2013 19:53:42.014 :: INFO :: IsInTransaction: False
12.10.2013 19:53:42.014 :: INFO :: IsOfflinePlayback: False
12.10.2013 19:53:42.014 :: INFO :: IsolationMode: 1
12.10.2013 19:53:42.014 :: INFO :: Mode: 0
12.10.2013 19:53:42.014 :: INFO :: OperationCreatedOn: 10/12/2013 5:53:42 PM
12.10.2013 19:53:42.014 :: INFO :: OperationId: 00000000-0000-0000-0000-000000000000
12.10.2013 19:53:42.014 :: INFO :: OrganizationId: eba3ca00-3338-49dd-b206-8ed1aacb1c3e
12.10.2013 19:53:42.014 :: INFO :: OrganizationName: crmdemo
12.10.2013 19:53:42.014 :: INFO :: OutputParameters:
12.10.2013 19:53:42.014 :: INFO ::  >  Key: BusinessEntityCollection / Value: Microsoft.Xrm.Sdk.EntityCollection  >> EntityCollection:
opportunity/ (8/8)
12.10.2013 19:53:42.014 :: INFO :: OwningExtension: Microsoft.Xrm.Sdk.EntityReference
12.10.2013 19:53:42.014 :: INFO :: ParentContext: 
12.10.2013 19:53:42.014 :: INFO :: PostEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
12.10.2013 19:53:42.014 :: INFO :: PreEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
12.10.2013 19:53:42.014 :: INFO :: RequestId: 
12.10.2013 19:53:42.014 :: INFO :: SecondaryEntityName: none
12.10.2013 19:53:42.014 :: INFO :: SharedVariables: Microsoft.Xrm.Sdk.ParameterCollection
12.10.2013 19:53:42.014 :: INFO :: UserId: 0cd683a0-541d-e311-b013-000c2926dde4
12.10.2013 19:53:42.014 :: INFO :: Ende XrmLoggerPlugin ======================================================================== >>>

 

 

 

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Microsoft Dynamics CRM: Simple File Logging for Plugins (and Workflows)

Well, there are many logging tools out there, but most of them depend on external assemblies. It is (not impossible but) more or less difficult to implement them in plugins.

So I decided to write a very simple file logger for myself. And this is also the tool I use to demonstrate what happens within the execution of plugins in my “Plugin messages – deep dive”. I tested it with Dynamics CRM 2013, but it should work the same way with every other version!

The Logger

The XrmLogger class is very easy to understand. There is a XrmLoggerConfig class where you specify where to write the files and the name you like your logs to have. The filename is a combination of a string and the date. In our Example the name would be “2013-10-09-XrmLoggerDemo.log”. Every day a new file is created. But you can change this very easily.

XrmLoggerConfig config = new XrmLoggerConfig()
            {
                LogDirectoryName = @"C:\LOG",
                LogFileGroup = "XrmLoggerDemo",
                logLevel = LogLevel.VERBOSE
            };

Next step is to get the execution context and do whatever your plugin is supposed to do. In my example I write the entity name, the message and the stage the plugin is running at.

xLog.ialert(String.Format("Entity: {0} => Message: {1} => Stage: {2}", context.PrimaryEntityName, context.MessageName, context.Stage));

So thats it more or less. Compile the code and register the assembly. Next choose the entity and the messages you want to listen at. And here is the result:

09.10.2013 14:27:28.400 :: INFO :: Entity: account => Message: RetrieveMultiple => Stage: 10
09.10.2013 14:27:28.405 :: INFO :: Entity: account => Message: RetrieveMultiple => Stage: 20
09.10.2013 14:27:28.458 :: INFO :: Entity: account => Message: RetrieveMultiple => Stage: 40

Below you find a listing of the complete code and the files do download.

xrlmLogger.cs

using System;
using System.Text;
using System.IO;

namespace xrmLog
{
    public enum LogLevel
    {
        VERBOSE = 0,
        INFO = 10,
        WARNING = 20,
        ERROR = 30,
    }

    public class XrmLoggerConfig
    {
        private string _LogDirectoryName = @"C:\LOG\";
        private string _LogFileName = "{0}-{1}.log";
        private string _LogFileGroup = "XrmAppLog";
        private LogLevel _logLevel = LogLevel.VERBOSE;

        public string LogDirectoryName
        {
            set
            {
                this._LogDirectoryName = value;
            }
            get
            {
                return this._LogDirectoryName;
            }
        }

        public string LogFileName
        {
            set
            {
                this._LogFileName = value;
            }
            get
            {
                return this._LogFileName;
            }
        }

        public string LogFileGroup
        {
            set
            {
                this._LogFileGroup = value;
            }
            get
            {
                return this._LogFileGroup;
            }
        }

        public LogLevel logLevel
        {
            set
            {
                this._logLevel = value;
            }
            get
            {
                return this._logLevel;
            }
        }

    }

    public class XrmLogger
    {

        private Boolean _dologging = true;
        private XrmLoggerConfig _config = new XrmLoggerConfig();

        private FileStream _fileStream;

        public XrmLogger()
        {
            this.init(_config);
        }

        public XrmLogger(string logFileName)
        {
            _config.LogFileName = logFileName;
            init(_config);
        }

        public XrmLogger(XrmLoggerConfig config)
        {
            this._config = config;
            init(config);
        }

        public Boolean doLogging
        {
            set
            {
                this._dologging = value;
            }
            get
            {
                return this._dologging;
            }
        }

        private string getDateTimeString()
        {
            return DateTime.Now.ToString("dd.MM.yyyy HH:mm:ss.fff");
        }

        private string getDateString()
        {
            return DateTime.Now.ToString("yyyy-MM-dd");
        }

        private string getFileName()
        {
            return String.Format(_config.LogFileName, this.getDateString(), _config.LogFileGroup);

        }

        private void init(XrmLoggerConfig config)
        {
            string _LogDirectoryName = config.LogDirectoryName.EndsWith(@"\") ? config.LogDirectoryName : config.LogDirectoryName + @"\";

            string path = String.Format("{0}{1}", _LogDirectoryName, this.getFileName());
            _fileStream = new FileStream(path, FileMode.Append, FileAccess.Write, FileShare.ReadWrite);
        }

        public void close()
        {
            _fileStream.Close();
        }

        private void writeFile(string message)
        {
            string line = this.getDateTimeString() + message + Environment.NewLine;
            byte[] info = new UTF8Encoding(true).GetBytes(line);
            this._fileStream.Write(info, 0, info.Length);
            this._fileStream.Flush();
        }

        public void valert(string msg)
        {
            if (this._dologging && _config.logLevel <= LogLevel.VERBOSE)
            {
                writeFile(" :: VERBOSE :: " + msg);
            }
        }

        public void ialert(string msg)
        {
            if (this._dologging && _config.logLevel <= LogLevel.INFO)
            {
                writeFile(" :: INFO :: " + msg);
            }
        }

        public void walert(string msg)
        {
            if (this._dologging && _config.logLevel <= LogLevel.WARNING)
            {
                writeFile(" :: WARNINIG :: " + msg);
            }
        }

        public void ealert(string msg)
        {
            if (this._dologging && _config.logLevel <= LogLevel.ERROR)
            {
                writeFile(" :: ERROR :: " + msg);
            }
        }
    }

}

The Sample Plugin

If you want to write a informational message use ialert, if you want to indicate a warning walert and on errors use the ealert function.

XrmLoggerDemo.cs

using System;
using Microsoft.Xrm.Sdk;

// 
// This is  demo of the XrmLogger class.
// How to use it:
// Create a C:\LOG on the Server and give your CRM Users RW rights
// Compile this class (don't forget to sign it with a strong key!)
// Use the pluginregistrationtool from the CRM.SDK to register the assembly (don't specify sandbox isolation mode! 
// => this plugin works only in onpremise or hosting environments
// deploy it for any message and entity you like
// 

namespace xrmLog
{
    public class XrmLoggerDemo : IPlugin
    {

        public void Execute(System.IServiceProvider serviceProvider)
        {
            IPluginExecutionContext context = (Microsoft.Xrm.Sdk.IPluginExecutionContext)serviceProvider.GetService(typeof(Microsoft.Xrm.Sdk.IPluginExecutionContext));

            XrmLoggerConfig config = new XrmLoggerConfig()
            {
                LogDirectoryName = @"C:\LOG",
                LogFileGroup = "XrmLoggerDemo",
                logLevel = LogLevel.VERBOSE
            };

            XrmLogger xLog = new XrmLogger(config);

            xLog.ialert(String.Format("Entity: {0} => Message: {1} => Stage: {2}", context.PrimaryEntityName, context.MessageName, context.Stage));
        }
    }
}

Download Visual Studio 2012 Project:
XrmLoggerDemo

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Microsoft Dynamics CRM 2013 – Plugin Messages – AddMember – deep dive

SdkMessage.Name SdkMessageRequest.Name SdkMessage.CategoryName
AddMember AddMemberList None

The AddMember Message is called when you add a entity to a marketing list.

What happens when you add an entity to a marketing list …

08.10.2013 11:36:13.236 :: INFO :: Entity: list => Message: AddMember => Stage: 10
08.10.2013 11:36:13.237 :: INFO :: Entity: list => Message: AddMember => Stage: 20
08.10.2013 11:36:13.257 :: INFO :: Entity: list => Message: AddMember => Stage: 40

For each entity you selected to add to the marketing list the AddMember message is triggered (Stage 10-20-40 => pre Validation, pre Operation and post Operation).

Here is the corresponding context. If you look at the properties you will find that the listid (= Guid of marketinglist) and the enitityid (= Guid of account, contact or lead) are members of the InputParameters. The entity-type is not part of the parameterbag, because the system knows which entitytype is allowed for the marketinglist you are trying to add the item.

In the post-stage the outputparameter Id is the guid of the created  listmember (in the sql database this is an entry in the ListMemberbase-table.

08.10.2013 11:36:13.234 :: INFO :: Start XrmLoggerPlugin ======================================================================== >>>
08.10.2013 11:36:13.234 :: INFO :: MessageName: AddMember
08.10.2013 11:36:13.234 :: INFO :: PrimaryEntityName: list
08.10.2013 11:36:13.235 :: INFO :: PrimaryEntityId: 00000000-0000-0000-0000-000000000000
08.10.2013 11:36:13.235 :: INFO :: Stage: 10
08.10.2013 11:36:13.235 :: INFO :: BusinessUnitId: 7647d68b-471d-e311-b013-000c2926dde4
08.10.2013 11:36:13.235 :: INFO :: CorrelationId: 8cf9ec1d-1259-4b6c-8a72-9296c52c6b2d
08.10.2013 11:36:13.235 :: INFO :: Depth: 1
08.10.2013 11:36:13.235 :: INFO :: InitiatingUserId: 0cd683a0-541d-e311-b013-000c2926dde4
08.10.2013 11:36:13.235 :: INFO :: InputParameters:
08.10.2013 11:36:13.235 :: INFO ::  >  Key: ListId / Value: 6a82f56a-9c2d-e311-b696-000c2926dde4
08.10.2013 11:36:13.235 :: INFO ::  >  Key: EntityId / Value: fc708f4b-2e2c-e311-8137-000c2926dde4
08.10.2013 11:36:13.235 :: INFO :: IsExecutingOffline: False
08.10.2013 11:36:13.235 :: INFO :: IsInTransaction: False
08.10.2013 11:36:13.235 :: INFO :: IsOfflinePlayback: False
08.10.2013 11:36:13.235 :: INFO :: IsolationMode: 1
08.10.2013 11:36:13.235 :: INFO :: Mode: 0
08.10.2013 11:36:13.235 :: INFO :: OperationCreatedOn: 10/8/2013 9:36:13 AM
08.10.2013 11:36:13.235 :: INFO :: OperationId: 00000000-0000-0000-0000-000000000000
08.10.2013 11:36:13.235 :: INFO :: OrganizationId: eba3ca00-3338-49dd-b206-8ed1aacb1c3e
08.10.2013 11:36:13.235 :: INFO :: OrganizationName: crmdemo
08.10.2013 11:36:13.235 :: INFO :: OutputParameters:
08.10.2013 11:36:13.235 :: INFO :: OwningExtension: Microsoft.Xrm.Sdk.EntityReference
08.10.2013 11:36:13.235 :: INFO :: ParentContext: 
08.10.2013 11:36:13.235 :: INFO :: PostEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
08.10.2013 11:36:13.235 :: INFO :: PreEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
08.10.2013 11:36:13.235 :: INFO :: RequestId: 
08.10.2013 11:36:13.235 :: INFO :: SecondaryEntityName: none
08.10.2013 11:36:13.235 :: INFO :: SharedVariables: Microsoft.Xrm.Sdk.ParameterCollection
08.10.2013 11:36:13.235 :: INFO :: UserId: 0cd683a0-541d-e311-b013-000c2926dde4
08.10.2013 11:36:13.235 :: INFO :: Ende XrmLoggerPlugin ======================================================================== >>>

08.10.2013 11:36:13.236 :: INFO :: Start XrmLoggerPlugin ======================================================================== >>>
08.10.2013 11:36:13.236 :: INFO :: MessageName: AddMember
08.10.2013 11:36:13.236 :: INFO :: PrimaryEntityName: list
08.10.2013 11:36:13.236 :: INFO :: PrimaryEntityId: 00000000-0000-0000-0000-000000000000
08.10.2013 11:36:13.236 :: INFO :: Stage: 20
08.10.2013 11:36:13.236 :: INFO :: BusinessUnitId: 7647d68b-471d-e311-b013-000c2926dde4
08.10.2013 11:36:13.236 :: INFO :: CorrelationId: 8cf9ec1d-1259-4b6c-8a72-9296c52c6b2d
08.10.2013 11:36:13.236 :: INFO :: Depth: 1
08.10.2013 11:36:13.236 :: INFO :: InitiatingUserId: 0cd683a0-541d-e311-b013-000c2926dde4
08.10.2013 11:36:13.236 :: INFO :: InputParameters:
08.10.2013 11:36:13.236 :: INFO ::  >  Key: ListId / Value: 6a82f56a-9c2d-e311-b696-000c2926dde4
08.10.2013 11:36:13.236 :: INFO ::  >  Key: EntityId / Value: fc708f4b-2e2c-e311-8137-000c2926dde4
08.10.2013 11:36:13.236 :: INFO :: IsExecutingOffline: False
08.10.2013 11:36:13.236 :: INFO :: IsInTransaction: True
08.10.2013 11:36:13.236 :: INFO :: IsOfflinePlayback: False
08.10.2013 11:36:13.236 :: INFO :: IsolationMode: 1
08.10.2013 11:36:13.236 :: INFO :: Mode: 0
08.10.2013 11:36:13.236 :: INFO :: OperationCreatedOn: 10/8/2013 9:36:13 AM
08.10.2013 11:36:13.236 :: INFO :: OperationId: 00000000-0000-0000-0000-000000000000
08.10.2013 11:36:13.236 :: INFO :: OrganizationId: eba3ca00-3338-49dd-b206-8ed1aacb1c3e
08.10.2013 11:36:13.236 :: INFO :: OrganizationName: crmdemo
08.10.2013 11:36:13.236 :: INFO :: OutputParameters:
08.10.2013 11:36:13.236 :: INFO :: OwningExtension: Microsoft.Xrm.Sdk.EntityReference
08.10.2013 11:36:13.236 :: INFO :: ParentContext: 
08.10.2013 11:36:13.236 :: INFO :: PostEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
08.10.2013 11:36:13.236 :: INFO :: PreEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
08.10.2013 11:36:13.236 :: INFO :: RequestId: 
08.10.2013 11:36:13.236 :: INFO :: SecondaryEntityName: none
08.10.2013 11:36:13.236 :: INFO :: SharedVariables: Microsoft.Xrm.Sdk.ParameterCollection
08.10.2013 11:36:13.236 :: INFO :: UserId: 0cd683a0-541d-e311-b013-000c2926dde4
08.10.2013 11:36:13.236 :: INFO :: Ende XrmLoggerPlugin ======================================================================== >>>

08.10.2013 11:36:13.256 :: INFO :: Start XrmLoggerPlugin ======================================================================== >>>
08.10.2013 11:36:13.256 :: INFO :: MessageName: AddMember
08.10.2013 11:36:13.256 :: INFO :: PrimaryEntityName: list
08.10.2013 11:36:13.256 :: INFO :: PrimaryEntityId: 00000000-0000-0000-0000-000000000000
08.10.2013 11:36:13.256 :: INFO :: Stage: 40
08.10.2013 11:36:13.257 :: INFO :: BusinessUnitId: 7647d68b-471d-e311-b013-000c2926dde4
08.10.2013 11:36:13.257 :: INFO :: CorrelationId: 8cf9ec1d-1259-4b6c-8a72-9296c52c6b2d
08.10.2013 11:36:13.257 :: INFO :: Depth: 1
08.10.2013 11:36:13.257 :: INFO :: InitiatingUserId: 0cd683a0-541d-e311-b013-000c2926dde4
08.10.2013 11:36:13.257 :: INFO :: InputParameters:
08.10.2013 11:36:13.257 :: INFO ::  >  Key: ListId / Value: 6a82f56a-9c2d-e311-b696-000c2926dde4
08.10.2013 11:36:13.257 :: INFO ::  >  Key: EntityId / Value: fc708f4b-2e2c-e311-8137-000c2926dde4
08.10.2013 11:36:13.257 :: INFO :: IsExecutingOffline: False
08.10.2013 11:36:13.257 :: INFO :: IsInTransaction: True
08.10.2013 11:36:13.257 :: INFO :: IsOfflinePlayback: False
08.10.2013 11:36:13.257 :: INFO :: IsolationMode: 1
08.10.2013 11:36:13.257 :: INFO :: Mode: 0
08.10.2013 11:36:13.257 :: INFO :: OperationCreatedOn: 10/8/2013 9:36:13 AM
08.10.2013 11:36:13.257 :: INFO :: OperationId: 00000000-0000-0000-0000-000000000000
08.10.2013 11:36:13.257 :: INFO :: OrganizationId: eba3ca00-3338-49dd-b206-8ed1aacb1c3e
08.10.2013 11:36:13.257 :: INFO :: OrganizationName: crmdemo
08.10.2013 11:36:13.257 :: INFO :: OutputParameters:
08.10.2013 11:36:13.257 :: INFO ::  >  Key: Id / Value: d054d780-9c2d-e311-b696-000c2926dde4
08.10.2013 11:36:13.257 :: INFO :: OwningExtension: Microsoft.Xrm.Sdk.EntityReference
08.10.2013 11:36:13.257 :: INFO :: ParentContext: 
08.10.2013 11:36:13.257 :: INFO :: PostEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
08.10.2013 11:36:13.257 :: INFO :: PreEntityImages: Microsoft.Xrm.Sdk.EntityImageCollection
08.10.2013 11:36:13.257 :: INFO :: RequestId: 
08.10.2013 11:36:13.257 :: INFO :: SecondaryEntityName: none
08.10.2013 11:36:13.257 :: INFO :: SharedVariables: Microsoft.Xrm.Sdk.ParameterCollection
08.10.2013 11:36:13.257 :: INFO :: UserId: 0cd683a0-541d-e311-b013-000c2926dde4
08.10.2013 11:36:13.257 :: INFO :: Ende XrmLoggerPlugin ======================================================================== >>>

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Microsoft Dynamics CRM 2013 – Plugin Messages – AddItem – deep dive

SdkMessage.Name SdkMessageRequest.Name SdkMessage.CategoryName
AddItem AddItemCampaignActivity None

The AddItem Message is called when you add a marketinglist to a marketing campaign.

What happens when you add a marketinglist to a campaign…

05.10.2013 11:18:47.992 :: INFO :: Entity: list => Message: Retrieve => Stage: 10
05.10.2013 11:18:47.993 :: INFO :: Entity: list => Message: Retrieve => Stage: 20
05.10.2013 11:18:47.996 :: INFO :: Entity: list => Message: Retrieve => Stage: 40
05.10.2013 11:18:47.998 :: INFO :: Entity: campaign => Message: AddItem => Stage: 10
05.10.2013 11:18:47.999 :: INFO :: Entity: campaign => Message: AddItem => Stage: 20
05.10.2013 11:18:48.010 :: INFO :: Entity: list => Message: Update => Stage: 20
05.10.2013 11:18:48.015 :: INFO :: Entity: list => Message: Update => Stage: 40
05.10.2013 11:18:48.017 :: INFO :: Entity: campaign => Message: AddItem => Stage: 40

05.10.2013 11:18:48.040 :: INFO :: Entity: list => Message: Retrieve => Stage: 10
05.10.2013 11:18:48.041 :: INFO :: Entity: list => Message: Retrieve => Stage: 20
05.10.2013 11:18:48.044 :: INFO :: Entity: list => Message: Retrieve => Stage: 40
05.10.2013 11:18:48.046 :: INFO :: Entity: campaign => Message: AddItem => Stage: 10
05.10.2013 11:18:48.048 :: INFO :: Entity: campaign => Message: AddItem => Stage: 20
05.10.2013 11:18:48.057 :: INFO :: Entity: list => Message: Update => Stage: 20
05.10.2013 11:18:48.062 :: INFO :: Entity: list => Message: Update => Stage: 40
05.10.2013 11:18:48.065 :: INFO :: Entity: campaign => Message: AddItem => Stage: 40

05.10.2013 11:18:48.119 :: INFO :: Entity: list => Message: RetrieveMultiple => Stage: 10
05.10.2013 11:18:48.123 :: INFO :: Entity: list => Message: RetrieveMultiple => Stage: 20
05.10.2013 11:18:48.128 :: INFO :: Entity: list => Message: RetrieveMultiple => Stage: 40

05.10.2013 11:18:48.143 :: INFO :: Entity: list => Message: RetrieveMultiple => Stage: 10
05.10.2013 11:18:48.147 :: INFO :: Entity: list => Message: RetrieveMultiple => Stage: 20
05.10.2013 11:18:48.152 :: INFO :: Entity: list => Message: RetrieveMultiple => Stage: 40

First the marketing list is retrieved (Stage 10-20-40 => pre Validation, pre Operation and post Operation).

Then the AddItem message is triggered and the marketing list is added to the campaign (Stage 10-20).
Within this process the marketing list is updated (Stage 20-40 => there is no pre validation stage ?!) and the “last used on” date value is set.

The next retrievemultiple messages are used to display the related marketing lists. The question is – why two times ?

Debugging shows the content of the first and second fetchxml:

<fetch distinct="false" no-lock="true" mapping="logical" page="1" count="4" returntotalrecordcount="true">
<entity name="list">
<attribute name="membercount" />
<attribute name="listname" />
<attribute name="listid" />
<attribute name="listname" />
<attribute name="membercount" />
<order attribute="listname" descending="false" />
<link-entity name="campaignitem" to="listid" from="entityid" link-type="inner">
<link-entity name="campaign" to="campaignid" from="campaignid" link-type="inner">
<filter type="and">
<condition attribute="campaignid" operator="eq" value="{CCD0CE13-9C2D-E311-B696-000C2926DDE4}" />
</filter>
</link-entity>
</link-entity>
</entity>
</fetch>
<fetch distinct="false" no-lock="true" mapping="logical" page="1" count="250" returntotalrecordcount="true">
<entity name="list">
<attribute name="listname" />
<attribute name="createdfromcode" />
<attribute name="type" />
<attribute name="lastusedon" />
<attribute name="purpose" />
<attribute name="listid" />
<attribute name="listname" />
<attribute name="type" />
<attribute name="createdfromcode" />
<attribute name="lastusedon" />
<attribute name="purpose" />
<order attribute="listname" descending="true" />
<link-entity name="campaignitem" to="listid" from="entityid" link-type="inner">
<link-entity name="campaign" to="campaignid" from="campaignid" link-type="inner">
<filter type="and">
<condition attribute="campaignid" operator="eq" value="{CCD0CE13-9C2D-E311-B696-000C2926DDE4}" />
</filter>
</link-entity>
</link-entity>
</entity>
</fetch>

Of course the AddItem message is also triggered if you add a campaign activity to a campaign which already has related marketing lists.

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Microsoft Dynamics CRM 2013 Xrm.Page.ui.formSelector

formSelector

The Xrm.Page.ui.formSelector contains an items collection that provides capabilities to query the forms available for the current user.

formSelector.getCurrentItem

Method to return a reference to the form currently being shown.

When only one form is available this method will return null.

formSelector.items

A collection of all the form items accessible to the current user.

Only those forms that share an association with one of the user’s security roles are available in this collection.

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Microsoft Dynamics CRM Xrm.Page object model

XrmPageModel

 

Object Description
context Provides methods to retrieve information specific to an organization, a user, or parameters that were passed to the form in a query string.
data Provides access to the entity data and methods to manage the data in the form.
ui Contains methods to retrieve information about the user interface, in addition to collections for several sub components of the form.

 

 

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Microsoft Dynamics CRM 2013 Client-side context

getContext

context = eContext.getContext();

getClient

Returns a value to indicate which client the script is executing in.

context.client.getClient();
Client Value
Browser Web
Outlook Outlook
Mobile Mobile

getClientState

Returns a value to indicate the state of the client.

Use this instead of the deprecated isOutlookOnline method.

context.client.getClientState();
Client Valid Clients
Online Web, Outlook, Mobile
Offline Outlook, Mobile

getClientUrl

Returns the base URL that was used to access the application.

Use this instead of the deprecated getServerUrl method.

context.getClientUrl();
Client Value
Microsoft Dynamics CRM (on-premises) http(s)://server/org
Microsoft Dynamics CRM Online https://org.crm.dynamics.com
Microsoft Dynamics CRM for Outlook with Offline Access when offline http://localhost:2525

getCurrentTheme

Returns a string representing the current Microsoft Office Outlook theme chosen by the user.

context.getCurrentTheme();
Value Theme
default Microsoft Dynamics CRM web application
Office12Blue Microsoft Dynamics CRM for Outlook 2007 or 2010 Blue Theme
Office14Silver Microsoft Dynamics CRM for Outlook 2007 or 2010 Silver or Black Theme

getOrgLcid

Returns the LCID value that represents the base language for the organization

context.getOrgLcid();

Vaild locale ID values can be found at Locale ID Chart.

The most needed:

English … 1033
French … 1036
German … 1031

getOrgUniqueName

Returns the unique text value of the organization’s name.

context.getOrgUniqueName();

getQueryStringParameters

Returns a dictionary object of key value pairs that represent the query string arguments that were passed to the page.

context.getQueryStringParameters();

getUserId

Returns the GUID of the SystemUser.Id value for the current user.

context.getUserId();

getUserLcid

Returns the LCID value that represents the Microsoft Dynamics CRM Language Pack that is the user selected as their preferred language.

context.getUserLcid();

Vaild locale ID values can be found at Locale ID Chart.

getUserName

Returns the name of the current user.

context.getUserName();

This method is only available for Updated Entities.

getUserRoles

Returns an array of strings that represent the GUID values of each of the security roles that the user is associated with or any teams that the user is associated with.

context.getUserRoles();

prependOrgName

Prepends the organization name to the specified path.

context.prependOrgName(sPath);

The value returned follows this pattern: “/”+ OrgName + sPath

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Microsoft Dynamics CRM 2013 Prevent a record from being saved

function My_PreventSaveFunction(eContext) {
 eContext.getEventArgs().preventDefault();
}

This method is essential if you want to enable auto-save for most forms in an organization but disable it for specific forms. The following code registered for the onSave event with the execution context passed to it will prevent any saves that initiate from an auto-save but allow all others.

With auto-save enabled, navigating away is equivalent to Save and Close. This code will prevent any saves that are initiated by the 30 second timer or when people navigate away from a form with unsaved data.

function preventAutoSave(econtext) {
    var eventArgs = econtext.getEventArgs();
    if (eventArgs.getSaveMode() == 70 || eventArgs.getSaveMode() == 2) {
        eventArgs.preventDefault();
    }
}

You can even check if  the save event has been canceled because the preventDefault method was used in this event hander or a previous event handler:

econtext.getEventArgs().isDefaultPrevented()

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>