This documentation is archived and is not being maintained.

Custom Workflow Activity: Get the Next Birthday

banner art

[Applies to: Microsoft Dynamics CRM 4.0]

Find the latest SDK documentation: CRM 2015 SDK

The following sample workflow activity returns the next birthday. Use this in a workflow that sends a birthday greeting to a customer. Note that this uses dynamic entity rather than strong types as is recommended for workflows and plug-ins.

This sample code can be found in the following files in the SDK download:



using System;
using System.Collections;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.Reflection;
using Microsoft.Crm.Workflow;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.Sdk.Query;

namespace SampleWorkflows
    /// <summary>
    /// Activity will return the next upcoming birthday that has just passed
    /// If this year's birthday has not yet occurred, it will return this year's birthday.
    /// Otherwise, it will return the birthday for next year.
    /// A workflow can time-out when on this date.
    /// </summary>
    [CrmWorkflowActivity("Get the Next Birthday", "Release Scenarios")]
    public partial class UpdateNextBirthday : SequenceActivity
        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
            IContextService contextService = (IContextService)executionContext.GetService(typeof(IContextService));
            IWorkflowContext context = contextService.Context;

            //Create a CRM Service.
            ICrmService crmService = context.CreateCrmService();

            //Retrieve the contact ID.
            Guid contactId = ((Lookup)base.GetValue(ContactProperty)).Value;

            //Retrieve the entity to determine what the birth date is.
            //Retrieve the Contact Entity
            DynamicEntity contactEntity;
                //Create the target.
                TargetRetrieveDynamic retrieveTarget = new TargetRetrieveDynamic();
                retrieveTarget.EntityId = contactId;
                retrieveTarget.EntityName =;

                //Create a request.
                RetrieveRequest retrieveRequest = new RetrieveRequest();
                retrieveRequest.ColumnSet = new ColumnSet(new string[] {"birthdate" });
                retrieveRequest.ReturnDynamicEntities = true;
                retrieveRequest.Target = retrieveTarget;

                //Execute the request.
                RetrieveResponse retrieveResponse = (RetrieveResponse)crmService.Execute(retrieveRequest);

                //Retrieve the Loan Application Entity.
                contactEntity = retrieveResponse.BusinessEntity as DynamicEntity;

            //Check to see if the current birthday is set. We don't want the activity to fail if the birth date is not set.
            CrmDateTime contactBirthDate = (CrmDateTime)contactEntity["birthdate"];
            if (contactBirthDate == null || (contactBirthDate.UniversalTime == null))
                //Complete the execution of the activity.
                return base.Execute(executionContext);

            //Calculate the next birth date. Encapsulate it in a method so that the method can be used in the test case for verification purposes.
            DateTime nextBirthdate = CalculateNextBirthday(contactBirthDate.UniversalTime);

            //Update the next birthday field on the entity.
            DynamicEntity updateEntity = new DynamicEntity(;
            updateEntity["contactid"] = new Key(contactId);
            updateEntity["new_nextbirthday"] = CrmDateTime.FromUniversal(nextBirthdate);


            CompositeActivity parentActivity = this.Parent;
            while (parentActivity.Parent != null)
                parentActivity = parentActivity.Parent;

            context.PopulateEntitiesFrom((CrmWorkflow)parentActivity, "primaryEntity");

            //Allow the base class to continue the execution.
            return ActivityExecutionStatus.Closed;

        //Define the variables.
        public static DependencyProperty ContactProperty = DependencyProperty.Register("Contact", typeof(Lookup), typeof(UpdateNextBirthday));

        //Define the properties.
        [CrmInput("Update Next Birthdate for")]
        public Lookup Contact
                return (Lookup)base.GetValue(ContactProperty);
                //Validate the argument.
                if (value == null || (value.IsNullSpecified && value.IsNull))
                    throw new InvalidPluginExecutionException("Contact Lookup cannot be null or have IsNullSpecified = true");
                else if (value.type != null && value.type != "contact")
                    throw new InvalidPluginExecutionException("Contact Lookup must be a contact entity");
                else if (value.Value == Guid.Empty)
                    throw new InvalidPluginExecutionException("Contact Lookup must contain a valid Guid");

                base.SetValue(ContactProperty, value);

        private DateTime CalculateNextBirthday(DateTime birthdate)
            DateTime nextBirthday = new DateTime(birthdate.Year, birthdate.Month, birthdate.Day);

            //Check to see if this birthday occurred in a leap year.
            bool leapYearAdjust = false;
            if (nextBirthday.Month == 2 && nextBirthday.Day == 29)
                //Verify that this year was a leap year.
                if (DateTime.IsLeapYear(nextBirthday.Year))
                    //Check to see if the current year is a leap year.
                    if (!DateTime.IsLeapYear(DateTime.Now.Year))
                        //Push the date to March 1st so that the date arithmetic will function correctly.
                        nextBirthday = nextBirthday.AddDays(1);
                        leapYearAdjust = true;
                    throw new InvalidPluginExecutionException("Invalid Birthdate specified", new ArgumentException("Birthdate"));

            //Calculate the year difference.
            nextBirthday = nextBirthday.AddYears(DateTime.Now.Year - nextBirthday.Year);

            //Check to see if the date was adjusted.
            if (leapYearAdjust && DateTime.IsLeapYear(nextBirthday.Year))
                nextBirthday = nextBirthday.AddDays(-1);

            return nextBirthday;

See Also


© 2010 Microsoft Corporation. All rights reserved.