Thursday, June 17, 2010

Formatting datetime in workflows with custom workflow activity in Microsoft Dynamics CRM 4.0

I've found one weird thing in workflows - when you insert datetime value inside text field you can't format it. Result of such inserting:




I decided to develop custom activity which will give possibility to format those output.
This activity has two inputs - datetime value to format (CrmDateTime property) and format (string property) and one output - formatted datetime (string). Code of custom action:

using System;
using System.Text;
using System.Collections.Generic;
using System.Workflow.Activities;
using Microsoft.Crm.Workflow;
using System.Workflow.ComponentModel;
using Microsoft.Crm.Sdk;

namespace DateTimeFormatting
{
[CrmWorkflowActivity("Formats date time with required format", "Formatting Routines")]
public class FormatDateTime : SequenceActivity
{
protected override System.Workflow.ComponentModel.ActivityExecutionStatus Execute(System.Workflow.ComponentModel.ActivityExecutionContext executionContext)
{
string result = string.Empty;

if (!string.IsNullOrEmpty(DateFormat) && datetime != null)
{
result = DateTime.Parse(datetime.Value).ToString(DateFormat);
}

Result = result;

return ActivityExecutionStatus.Closed;
}

public static DependencyProperty DateFormatProperty = DependencyProperty.Register("DateFormat", typeof(string), typeof(FormatDateTime));

[CrmInput("Format of DateTime")]
public string DateFormat
{
get
{
return (string)base.GetValue(DateFormatProperty);
}
set
{
base.SetValue(DateFormatProperty, value);
}
}

public static DependencyProperty datetimeProperty = DependencyProperty.Register("datetime", typeof(CrmDateTime), typeof(FormatDateTime));

[CrmInput("DateTime to format")]
public CrmDateTime datetime
{
get
{
return (CrmDateTime)base.GetValue(datetimeProperty);
}
set
{
base.SetValue(datetimeProperty, value);
}
}

public static DependencyProperty ResultProperty = DependencyProperty.Register("Result", typeof(string), typeof(FormatDateTime));

[CrmOutput("Formatted DateTime")]
public string Result
{
get
{
return (string)base.GetValue(ResultProperty);
}
set
{
base.SetValue(ResultProperty, value);
}
}

}
}


Following screenshots show how to use this action:
1. Insert this action before using the result of formatting:


2. Click "Set Properties" button to insert datetime and format:


3. Fill "Format of DateTime" and "DateTime to Format" fields:


4. Add some workflow step formatted datetime to be used (for example sending email):





Save step and save and publish workflow. Result of work of this workflow:


Sourcecode:

16 comments:

  1. Works Great! Thanks a lot Andriy! You've made my users very happy!

    ReplyDelete
  2. Andriy - can you tell me where your C# code goes or how you have compiled it? The solution is great and I'd like to implement it but not sure about the custom code.

    ReplyDelete
  3. Hello, Brenden. Actually C# is placed on a blog as a sample what and how can be done in CRM. You can just download compiled version of assembly at the end of post and register it on your system using PluginRegistration tool.

    ReplyDelete
  4. Hi,

    I would like to do something similar. I am trying to remove the time from a datetime attribute in an email created by a workflow. Even though the attribute is set to "Date Only", in my email created by the workflow, the time is displayed after the date.

    ReplyDelete
  5. Hello, Deene.

    In this case you should build code proposed in the article and install the library using pluginregistrator. This will give you additional possibility in workflows - to format datetime fields as you want.

    If you have questions you can drop me an email. You can find my address in my profile.

    ReplyDelete
  6. Hi Andriy
    This is just what I needed! Greate work!
    But I'm not sure how to register this with CRM Plugin Registration Tool 2.2. I'm connected to CRM server and trying to follow the tools guide on how to register plugin. But what to fill in??
    Best regards,
    Henrik

    ReplyDelete
  7. PS.
    I forgot to ask: Do you have a guide on how to register this plugin or plugin in general? And by the way, don't seem to find compiled assembly here in blog?

    ReplyDelete
  8. Hello. Here is text description how to register custom workflow activities - http://msdn.microsoft.com/en-us/library/ee704600.aspx

    If you will have other question - don't hesitate to ask.

    ReplyDelete
  9. Hi there,

    I'm getting the following error on registration

    Unhandled Exception: System.IO.FileNotFoundException: Could not load file or assembly 'System.Workflow.Activities, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
    at System.Reflection.Assembly._GetExportedTypes()
    at System.Reflection.Assembly.GetExportedTypes()
    at PluginRegistrationTool.AssemblyReader.RetrievePluginsFromAssembly(String path)
    at PluginRegistrationTool.AssemblyReader.RetrievePluginsFromAssembly(String path)
    at PluginRegistrationTool.RegistrationHelper.RetrievePluginsFromAssembly(String pathToAssembly)
    at PluginRegistrationTool.PluginRegistrationForm.btnLoadAssembly_Click(Object sender, EventArgs e)


    Any idea whats wrong?

    ReplyDelete
  10. Hello Jack,

    I assume that you have problems with .Net framework. What versions do you have installed?

    ReplyDelete
  11. Hi Andriy,

    It was a .net framework issue, i got the plugin registered now. What inputs can the "Format of datetime" condition in the workflow take? dd/mm didnt seem to workf for me!

    ReplyDelete
  12. Hello Jack,
    You can see sample here - http://1.bp.blogspot.com/_73OmG38HHME/TBlT30eujxI/AAAAAAAAAmg/ZCibtud_J-Y/s1600/DateFormat3.JPG

    One quick note - mm - will return minutes. To set months you should use MM instead of mm.

    ReplyDelete
  13. Is there a way to return the french when I use the MMMM (Month name) or ?

    ReplyDelete
  14. Hello Richard,
    I believe it is possible but you will have to redevelop your code and use other DateTime.ToString method which retrieves format and IFormatProvider parameters - http://msdn.microsoft.com/en-us/library/8tfzyc64.aspx In this provider you can set French locale.

    ReplyDelete
  15. I took the liberty to update the code to .net4 for use with CRM 2011.

    Kind regards, Vincent Pannenborg

    using System;
    using System.Activities;
    using System.Collections.Generic;
    using System.Globalization;
    using System.Text;
    using Microsoft.Xrm.Sdk;
    using Microsoft.Xrm.Sdk.Query;
    using Microsoft.Xrm.Sdk.Workflow;

    namespace FormatDateTime2011
    {
    public sealed class DateTimeHandler : CodeActivity
    {
    // Input property
    [RequiredArgument]
    [Input("Format of DateTime")]
    public InArgument InputDateFormat { get; set; }

    // Input property
    [RequiredArgument]
    [Input("DateTime to format")]
    public InArgument InputDateTime { get; set; }

    // Output property
    [Output("Formatted DateTime")]
    public OutArgument OutputResult { get; set; }

    protected override void Execute(CodeActivityContext executionContext)
    {
    string DateFormat = InputDateFormat.Get(executionContext);
    DateTime datetime = InputDateTime.Get(executionContext).ToLocalTime();
    string result = string.Empty;

    CultureInfo provider = CultureInfo.InvariantCulture;

    if (!string.IsNullOrEmpty(DateFormat) && datetime != null)
    {
    result = datetime.ToString(DateFormat, provider);
    }

    OutputResult.Set(executionContext, result);
    }
    }
    }

    ReplyDelete
  16. edit: "using Microsoft.Xrm.Sdk.Query;" can be left out

    ReplyDelete