What’s slowing down your CRM development?

I was reading an excellent article called Produce more by removing more, it instantly struck me this thought process would be useful for development tasks.  The article Which is based on a the book below (which is on my to read list)

Essentialism: The Disciplined Pursuit of Less

The standard process of speeding up projects is usually to throw more resources at the project, I’m sure you have worked on a project where extra CRM Developers have been added to shorten the delivery time of the CRM project.

Another popular method of delivering a project sooner is by rushing a project, this is achieved by cutting corners, removing developments steps (unit tests, reduce testing, no documentation, removing code reviews).  The outcome of rushing a project is often a build of technical debt and a CRM project of reduced quality.   You can read my article on Why rushed projects/code doesn’t save time and reduces quality.

Rushed projects often gain short term benefits (reduced development time) but incur the cost of reduced quality.  Creating a high quality CRM solution is taking a long term view because the code will be easier to debug, understand, extend and change.  Unit tests will be able to rerun and code reviews help junior members of the team learn more about CRM development.

This article will consider a different way to increase the speed of delivery for a project.

What is the goal of a CRM project

This quote highlights the frame of mind needed to streamline the process of creating a CRM solution

We can’t know what obstacles to remove until we are clear on the desired outcome. When we don’t know what we’re really trying to achieve, all change is arbitrary. So ask yourself, “How will we know when we are done?

The first task is to analyse your CRM project and understand what are the key tasks of a CRM project.

The key tasks are the priority tasks team members should be focusing on, the other tasks we can analyse to see which tasks it’s possible to remove.

CRM development,  development tasks in general can seem illogical or unquantifiable, a lot of unknowns and tasks which are estimated but which contain elements of risk.

Why are tasks hard to estimate

Tasks involve human interaction

  • Collecting requirements
  • Company politics
  • Dealing with different and difficult individuals

Project

  • Integrating with 3rd party software
  • Company policy

Code

  • Design of code
  • Unit Tests
  • Documentation
  • Build and deploying
  • Peer Reviews

Customers can sometimes forget estimates are best guesses, they should be quite accurate because they are created by developers with plenty of experience of similar customizations but each CRM project and piece of CRM development is different and unforeseen circumstances can interfere with the estimates.

Code needs to work and be all structured
A design of a solution can sometimes be found incorrect late in the day when a developer is developing a certain part in more detail, e.g testing the design theory with a practical exam

Learning and development of people

  • CRM Developers might need to research some skills (e.g. search the internet or the Hosk CRM Blog :-))
  • Peer reviews rewrite

What is the end goal of code and customizations

Whilst I have talked about the various different tasks in a CRM project it’s worth reminding ourselves of the goal of a CRM project.

The end goal of CRM development is to create quality CRM code and customizations

  • Deliver functionality
  • Few bugs
  • Easily maintainable
  • Easy to understand
  • Easy to debug
  • Manage complexity and create a CRM solution as simple as possible by creating lots of small simple pieces of development which work together as a whole

Do tasks take time or save time?

 

I have considered some of the tasks of CRM development, the goal of a CRM project is to create a quality project to deliver the required functionality to the customer on time and bug free.

With this knowledge of CRM projects, CRM development is not straight forward, consider the facts below

  • Quick projects cost you more time
  • Spending more time designing code can save you time later
  • Simple code can be reused
  • Unit tests can save time and find more bugs
  • Peer reviews can help learning, find bugs and keep code quality high but seem to take more time

The tasks above initially seem to make a project take longer but they create better code which has fewer bugs, easy to debug/extend/understand, which will save time later (long term benefits)

What is slowing down your CRM development and CRM projects

So far in this article we have seen a lot of tasks in CRM projects are difficult to estimate because they involve tasks which can only be estimated but which can take longer when the tasks are being done.
Tasks which involve human interaction always have the potential to take longer with misunderstandings, personal and political issues coming into play.

Things which can slow you down

When you think about your CRM project, concentrate on

What are all the obstacles standing between me and getting this done

or

What is the obstacle that, if removed, would make the majority of other obstacles disappear?

Here is a list of of items which could be slowing down your CRM project

  • Knowledge – Lack of
  • Poor code
  • Inefficient processes
  • A customer who keeps making change requests
  • Poor development environment
  • Hardware
  • Missing requirements
  • Inexperienced team members
  • No Experienced CRM Developer
  • Flawed design
  • Bugs
  • Layers of people
  • Slow IT support

In the book Essentialism: The Disciplined Pursuit of Less it uses the excellent phrase of finding your slowest hiker.

Knowledge – Lack of

A lack of knowledge in your team can slow down the project.  The reason is CRM developer make mistakes when learning new customizations or code/customizations they do not have any experience of.

This should be expected and factored into the project, I view this as an investment in time by the employer.  The employer will be rewarded with a CRM developer who is more experienced.

The real danger can happen when a CRM developer cannot get the customization to work or their design has a fundamental flaw hidden inside, which only becomes apparent later on in the project.   The lack of knowledge can be more of a problem when integrating 3rd party software or WCF services which can be more complicated than more standard CRM development.

The best to method to combat a lack of experience is to have senior developers working on the project.  Senior developers can

  • keep more junior developers on track
  • Help junior developers not to get stuck
  • On hand for quick help
  • Help with the design of solutions

A senior developer acts like a safety net for junior developers, can provide quick answers or advise on the process a junior developer should tackle an unknown problem.  The biggest plus is senior developers can help junior developers from wasting time on problems which senior developers can point them away from before they make them.

Poor code

Poor quality code can be written quickly but afterwards any interaction with the poor code will be difficult, will take longer and is harder to understand.

Poor code usually is created by inexperienced developers who create complex code The problems with complex code and complex CRM Customizations.  Complex code makes any interaction with the code difficult and will take longer.  The code is usually created like this due to inexperienced developers or because the code has been rushed (Rushed Code projects do not save time)

Inefficient processes

Projects can have inefficient processes, one of the main culprits is build processes.  Moving the complex CRM solutions can take a lot of time spent

  • creating and deploying solutions
  • Documenting changes
  • manual steps with deployments
  • testing

A customer who keeps making change requests

The ideal CRM project is a collaboration between CRM supplier and the customer.   When this works it’s a beautiful thing, the CRM supplier brings the CRM expertise,  the customer brings their detailed business knowledge.

Unfortunately many times it doesn’t happen this way.  Sometimes customers can decide to make technical design decisions or demand customizations which are not recommended by the CRM supplier.

A common mistake for the CRM supplier is making incorrect assumptions about business logic or creating code with design flaws or bugs.

A common problem in CRM projects is when a customer constantly changes requirements.  Below are the common reasons for constant requirement change

  • Poorly defined requirements
  • lack of customer time invested in the project
  • changing members of the customer team who have different opinions
  • wrong people creating requirements, which don’t match work practices of users

Poor development environment

Messy and poorly set-up development environments can make development difficult.  Development on CRM projects can often involve multiple developers working from different locations.

Development environments don’t usually make development any easier but a poor development environment can slow things down.

Hardware

Slow developer computers

Slow development environment

It doesn’t make sense to pay CRM developers lots of money to do their job and to slow them down with poor hardware.  Slow hardware has a cumulative effect of slowing development by small amounts many times  a day, 5 days a week, 52 weeks a year.  It all adds up to many productive hours being lost whilst the CRM Developer waits for his computer or the environment to do it’s thing.

Missing requirements

Missing requirements can cause problems

Inexperienced team members

A project with a lot of inexperienced team members can slow down development

  • Making mistakes whilst doing new development they have no experience
  • creating more complex code (which is harder to maintain, extend, debug)
  • working through mistakes people learn to avoid through experience

In my article Should you hire a rockstar developer for your CRM project, it mentions these points about inexperienced CRM Developers

  • Take longer to do customizations
  • Poor design can lead to problems later in the project
  • Make more mistakes whilst learning and gaining experience
  • Does not always choose the correct type of customization
  • Create complex code and customizations, which are difficult to maintain, debug and extend
  • Can have problems integrating with 3rd party software and tools
  • Increased likelihood of late delivery of the project (due to problems with code and incorrect estimates)

No Experienced CRM Developer

Experience and CRM Development (and possible development in general) can be summed up by this quote

Inexperienced developers make complex solutions to simple problems

Experienced developers make simple solutions to complex problems.

I have previously talked about experienced developers in this articles

Should you hire a rockstar developer for your CRM project

What do Senior/Rockstar Developers bring to a company

  • Avoiding costly development mistakes
  • Create best practice documents
  • Experienced developers are often very good at assessing third-party software
  • Helping other developers
  • Calming influence
  • Create a good team
  • Senior developers mentor
  • Senior developers are a safety net

Experienced developers keep the project on track, help inexperienced members and act as a safety net to stop major problems with a project.  Experienced Developers are particular important for the design stage of projects or if a large problems suddenly appears.

Flawed design

Flawed designs are not usually obvious and the flaw often comes to light when development on a section of the solution is investigating at a deeper level.  A flawed design is usually due to unforeseen limitations of 3rd party software or some missing/misunderstood requirement

Bugs

complex code and a lack of unit testing/peer reviews can mean many bugs make it into the production environment

Layers of people – bureaucracy

Sometimes projects have too many people to discuss and inform about project decisions.  Like trying to agree a party date with a big family (someone always can’t make one day) you can end up discussing availability and other topics instead of the project.

Needless Meetings

The amount of time wasted in meetings is staggering.  Think about all the pointless meetings and the many times people attended meetings they didn’t need to be in.

In some projects telephone meetings can become a habit.

I’m not against all meetings, an effective meeting can save lots of interactions (email, phone) but I recommend analysing who attends meetings and ensuring you can justify everyone’s attendance.

Slow IT support/procedures

In large organisations IT requests can take weeks, in some situations this can be a bottleneck for CRM projects.

If this is constantly slowing the CRM Project down it needs to be raised with the customer and faster path needs to be arranged

People

Sometimes certain people can slow down entire projects.  It could be a customer wants to do all the tasks and their workload is too large.

It could be only one person on the team has knowledge about a particular process or 3rd party software.

What steps should you take

I have gone through some of the common problems in CRM projects, the next step is to identify and remove those problems.

Identify your slowest hiker(s)

I will admit I love the saying Identify your slowest hiker but I also like the idea.  Most projects speed up development process by adding more resources, this is usually effective (although you can get in a situation where you have too many developers who are constantly getting in each others way).

Identifying the slowest hiker is looking at your development environment, the team and the processes to see where your bottle necks.

It could be things like

  • Too many releases
  • No senior developer
  • under trained users asking simple questions
  • manual processes
  • poor quality – too many bugs
  • layers of people
  • slow IT change requests
  • slow debugging techniques
  • no unit tests/no code reviews – more bugs

Remove Obstacles

Once you have audited your Development team, processes and environments the next step is to improve them.

Each CRM Project and CRM environment is different but many lessons and improvements found can be made into best practices for other CRM projects.

Like the design of a solution the design of the CRM Project team is an important step before the project begins.

Changing team members and resources after a project has begun will mean the incoming project team members will have to quickly understand the business rules/logic.  The new team members will be considerably less efficient than the current team members (who have a wealth of business logic) who are in the project flow.

It’s better to make project team changes earlier rather than later to give the new team members as much time to learn about the business logic/rules and more time to make a positive impact on the project.

Removing obstacles in CRM projects can sometimes be quick but sometimes can involve changing project processes on a company level

  • making unit testing mandatory
  • peer reviews
  • build processes
  • Automated testing
  • Creating/using software to automate steps

Changes to factors controlled by the customer are best tackled by discussing the issues and both  the CRM solution provider and customer working together to find practical solutions.   Ultimately it will be in the customers benefit to improve the speed of the project but change is never easy.

Changes on the customer side are the customers prerogative but if you don’t raise the issues with the customer then no improvements will be made, if you raise the issues you have a small chance of improvements 🙂

Summary

I hoped you enjoyed the article and this was an interesting way to look at the speed/efficency of your CRM Projects.

Some of the solutions focus on improving the quality of your CRM project, the idea being better quality code is easier to work with and results in fewer bugs getting out of the development environment and into the production environment.

Team members of a CRM Project ideally you want to get right at the start of the project due to the time it takes to new members to acclimatise to the new project and learn the business rules/business logic of a project.

Improving the delivery speed of your projects might not always involve adding more people, an interesting thought.

Advertisements

WCF with no service xml or endpoints? What is this magic?

I had to write a WCF service for a project and I hadn’t created a WCF service for a while.

I was trying to write mine to fit in with the rest of the projects but I was totally confused because I was looking at the other WCF services in the project and looking to copy the shell and modify (like all good developers do:-))

I could see there was a SVC file, I could see the code but in the web.config there was no service xml section for the WCF service.

I trying to look at the url for the SVC to see if I could see the wsdl but when I did I got the message no endpoint found.

no endpoint found

 

WHAT WAS GOING ON.

Sometimes as a developer, when you haven’t worked on an area for a while, you have a horrible feeling they have changed the way it worked to some completely new method and framework a bit like the way web services were replaced with WCF.   but this wasn’t the case, it was CRM 2011 project (not that makes any difference calling a WCF service).

The most puzzling aspect was the WCF code was being called (I called it myself to make sure it worked) from a Javascript form.

I asked a developer and he said it must be a factory service, I must have had a completely blank look on my face because he then offered to show me.  A good tip is if you don’t understand something ask someone to point you in the right direction because you can save yourself days of puzzling.

He said right click on the SVC file in Visual Studio and choose View Markup
 
You will see this
mine was like this
<%@ ServiceHost Language=”C#” Debug =”true” Service=”Hosk.HoskRibbonService” CodeBehind=”HoskRibbonService.svc.cs %>
he said change it to this
<%@ ServiceHost Language=”C#” Debug =”true” Service=”Hosk.HoskRibbonService”  Factory=”System.ServiceModel.Activation.WebServiceHostFactory” %>

I removed the service xml section in the web.config and then as if by magic it worked and I was able to call the wcf service using jsonp call (cross domain) in javascript.

Not only had I never heard of using WebServiceHostFactory to create a WCF but I had never come across it in any of the code I have worked with.

I was interested to learn a bit more about it,  It’s a way to dynamically create services and it automatically creates the endpoints for the service and was added in .NET 3.5

 

Here is MSDN class

http://msdn.microsoft.com/en-us/library/system.servicemodel.activation.webservicehostfactory(v=vs.110).aspx

 

this flashcard gives a good quick explanation

http://www.brainthud.com/cards/5218/25206/what-is-the-purpose-of-the-webservicehostfactory-class-and-how-is-it-used

Question

What is the purpose of the WebServiceHostFactory class and how is it used?
Answer

When hosting a web service in IIS, the WebServiceHostFactory class can be used to automatically configure the endpoints for the service. Endpoints will be configured to use WebHttpBinding and WebHttpBehavior. The WebServiceHostFactory class will automatically create a WebServiceHost class when the web service is activated. The following example demonstrates how to reference the WebServiceHostFactory in a .svc file:

<%@ ServiceHost 
    Service="OrderService" 
    Factory="System.ServiceModel.Activation.WebServiceHostFactory" %>

 

 

Here are some simple tutorials if you want to learn more

http://dotnet.dzone.com/articles/creating-restful-wcf-service

http://agilewarrior.wordpress.com/2010/12/19/how-to-create-a-simple-wcf-rest-service/

http://www.c-sharpcorner.com/uploadfile/dhananjaycoder/rest-eanbaled-service-in-wcf-tutorial/

 

Picture from http://daarken.com/blog/2012/08/11/lotr-magic-and-other-news/

Hosk’s Top CRM 2013 articles of the week 23rd May 2014

Welcome to another exciting week of Hosk’s Top CRM articles

Hosk Video roundup

 

Article of the Week

a great article from CRM MVP Adam Vero on why you should use Access Teams. There have been quite a few blogs and a videos on how to use access teams and a quick introduction to access teams but this deep dive from Adam explains WHY you should use access teams.

http://blog.crmguru.co.uk/2014/05/16/why-use-access-teams-in-dynamics-crm-2013/

 

 

The Best of the Rest

This is a great article on migration tips, focusing on the database

11 Dynamics CRM Data Migration Tips

 

How to set up soap authentication for CRM Online using JavaScript.  A good example from Jason Lattimer CRM MVP

 SOAP Authentication to CRM Online using JavaScript

 

The CRM SDK update has brought in some refresh tools.  The Plugin Registration tool gets a face lift

Dynamics CRM 2013 SP1 Plugin Registration Tool Revamped!

 

Also in the new CRM 2013 SDK update is the migration tool, this allows you to bring things like duplicate detection rules from one CRM organisation to another, which saves you have to recreate them in each instance.

Dynamics CRM 2013 SP1 SDK – New Tool: Configuration Migration

 

You can add use security roles to filter dashboards

Dynamics CRM Quick Tip – How to Secure Your Dashboards

 

Comparing filter functionality between CRM 2011 and CRM2013

Comparison of the CRM 2011 and CRM 2013 Filter Functionality

 

Nice trick to show you how to colour code tracked appointments in outlook

Color Code Your Calendar for Tracked Appointments in Microsoft Dynamics CRM

 

Hosk CRM MVP questions for Blake Scarlavai

CRM MVP Question and Answer – Blake Scarlavai

 

 

Great Ribbon Workbench tutorial to show you how to add a custom advanced find in the command bar.  Very useful if you are planning to go through

Advanced Find from Form Command Bar in Dynamics CRM 2013

 

Hosk goes through auditing in CRM 2013 and then gives some key facts for the people studying MB2-703 CRM 2013 customization and configuration exam.

CRM 2013 – MB2-703 – Quick Overview of Auditing

 

linking CRM 2013 with Google Analytics – cheeky

http://www.crmconsult.co.uk/using-google-analytics-with-microsoft-dynamics-crm-2013/

 

A new CRM 2013 book is unleashed and available to buy

new CRM 2013 book – Microsoft Dynamics CRM Unleashed 2013

 

Joel Abbot tells you why the new changes in service and case in the spring wave are good and why we should be excited

Service & Case Changes…Small But Mighty! Microsoft Dynamics CRM 2013 – Spring Wave

 

Links to CRM 2013 documentation

CRM 2013 – Information and documentation to get you started in CRM 2013 but no User Guide

 

How you can add bing maps to entities quickly

 Add Bing Maps to CRM 2013 Entities Quickly and Easily

 

Really useful tip form Robert Peledie I had forgotten about.  When importing data into CRM 2013/2011 you have the option to create a new entity and then create new records.

Quick Create Entity in Dynamics CRM 2013 – Custom Country List Example

 

 

Videos

 

Video to show you how to create new entities and records using just a CRM import

Quick Create Entity in Dynamics CRM 2013

 

Hosk shows you how to quickly get the record id (guid) using Chrome and IE in CRM 2013

CRM 2013 – Quick way to get a guid for a record using Chrome and IE

 

A good/long tutorial on loading JavaScript from the CRM 2013 Developer toolkit and then how to debug the files

CRM 2013 – JavaScript tutorial using CRM 2013 Developer Toolkit

 

How auditing works and a few key facts from the Hosk

CRM 2013 – How Auditing works and key facts

 

Previous Week

If you want more great articles, why not go back and read last weeks top CRM articles again, did you read them?

Hosk’s Top CRM 2013 articles of the week 16th May 2014

if you find reading to difficult today, why not go and watch some CRM videos on my youtube channel

Hosk’s CRM Dev

CRM 2011/2013 Dialog’s and Custom Workflow example

I had piece of functionality I did at work recently and it had a few interesting parts, so I thought I would blog it down.  You can read the blog or watch the video

The required functionality required the ability to update multiple appointments, in this deployment we have created a new appointment entity called Client appointment but basically I needed to update multiple appointments.

The user wanted to specify a cancellation reason.

I was initial thinking of using a workflow and selecting lots of appointments but because they needed to specify a cancellation reason then this wasn’t an option

With input required a dialog seemed like a good option.

The problem I quickly found was Dialog’s can only be triggered on one record at a time and not multiple records like workflows.

Contact Dialog

So the plan was changed to be run on the contact.  I would have a dialog which ran on the contact entity the user would be prompted for a start date, end date and a cancellation reason.

I would call a Custom Workflow from with the dialog and pass selected values to it and then the custom workflow would do a query, select all the appointments, cancel them and then create a reschedule task and assign it to a reschedule queue.

I usually trigger code changes from plugins and wondered what circumstances would I move that code to be triggered into a Custom Workflow but this a good example.

This code isn’t really suitable to be triggered from a plugin because there isn’t anything being changed/updated or created so there is no natural plugin trigger point.

Thinking about this I can see that within certain workflows and dialog’s is the perfect place to call a custom workflow, particularly when nothing has been updated or modified and you want to trigger those changes and the changes are going to be complex which needs a code to do.  This is a good example because the code needs to retrieve a lot of appointments linked to a contact, this functionality couldn’t be achieved in workflow or definitely not easily.

After re-reading the requirements I noticed we needed to specify a start time and end time and this would also work in a slightly unusual manner.  If the user specified 08:00 to 12:00 with a start date and end date which went over more than one day.  The user wanted the morning appointments to be cancelled for each day specified but the afternoon appointments to be left alone.  This would provide a tricky piece of querying which I will go into later.

In theory this seemed like it would work, so I initially created a skeleton Dialog and a Custom workflow which logged the fields.

 

The first little problem I had was, how to show the time.  The choices I had were text single response, this would involve the user typing in the time, I didn’t like this option because it wasn’t easy for the user and had the potential for them to mistype.

The other option was to create an optionset with an hour value for each hour.  e.g. 01:00, 02:00 etc.  In then end I chose this option.

The user also wanted the ability to not select a time and this would mean they wanted to cancel the whole days appointments.

So I created the the optionSet with a default value of – Full Day and then 01:00 label would have the value of 1, 23:00 would have the value of 23.

 

dialog example

SET THE CORRECT DATA TYPE

One mistake I made at this point was to incorrectly set the Data type to text.  This is a real schoolboy error because once you set this you can’t change it.  So I had set it to text gone through adding all 24 hours and then realizing and had to do it all again, very frustrating.

What is also very frustrating is the fact you can use an optionSet created in CRM, you have to copy the values again.  This means there isn’t any schronisation between the OptionSet in your dialog and entity.  It also means you may have to create the values numerous times in a dialog because you can’t reuse it in a dialog.

In this example I had to create the same OptionSet for start date and end date.  Tedious indeed.

dialog example 1

 

The cancellation reason was the same kind of thing, I had to copy an OptionSet inside CRM and recreate it and give the OptionSet values the same as the values in the CRM OptionSet field, this way I could pass the value into the Custom Workflow and then it could use the value to set the OptionSet.

 

Warning Popup Message

When I did a demo of the functionality to the client, they said they would like a warning to pop up, if the dates specified were within 3 days.  The reason for this is if you cancel appointments with 3 days of today, it’s difficult to reorganize these so users should be certain they want to cancel these appointments.

Sometimes when someone asks you about how to achieve some functionality in CRM, you can be momentary stumped and can’t see how to do it and this was one of those moments.

I couldn’t see anyway to pop up a warning message.

It was only later that I was talking through the problem with the team that the obvious answer came to light.

Dialog’s are made up of pages and on each page you have a one or more prompt and responses.

So if I wanted a warning message all I needed to do was to create a new page, show the information the user had entered earlier in the dialog and ask them to confirm if they wanted to proceed with the changes using an OptionSet with Yes/No.

 

What I did was to check if the start date was greater than three days, if so put a confirmation page but if the start date was less than three days I would add the words warning.

dialog example 2

 

Sensible variable names

This is the same for workflows but when you are adding conditions or adding steps/prompt and responses make sure you use easily understood variable names because later you will need to use these fields to update an entity/pass to a custom workflow so you need to be able to easily understand what each field is.

Here is the Custom Workflow being called from within the dialog

dialog example 3

 

Below you can see the main code for the Custom Workflow, you can match it up with the screen shot above.  The actual code is in this class commonClientAppointment class

 


public sealed class CwaBulkAppointmentStatusChange : CodeActivity
{

/// <summary>
/// Gets or sets Min Wait Time
/// </summary>
[Input("Start Date")]
[RequiredArgument]
public InArgument<DateTime> StartDate { get; set; }

/// <summary>
/// Gets or sets Max Wait Time
/// </summary>
[Input("End Date")]
[RequiredArgument]
public InArgument<DateTime> EndDate { get; set; }

/// <summary>
/// Gets or sets Max Wait Time
/// </summary>
[Input("Start Time")]
[RequiredArgument]
public InArgument<int> StartTime { get; set; }

/// <summary>
/// Gets or sets Max Wait Time
/// </summary>
[Input("EndTime")]
[RequiredArgument]
public InArgument<int> EndTime { get; set; }

/// <summary>
/// Gets or sets Max Wait Time
/// </summary>
[Input("Cancellation Reason")]
[RequiredArgument]
public InArgument<int> CancellationReason { get; set; }

/// <summary>
/// Gets or sets Task Reference
/// </summary>
[Input("Contact")]
[ReferenceTarget("contact")]
public InArgument<EntityReference> Contact { get; set; }

/// <summary>
/// Executes the workflow activity.
/// </summary>
/// <param name="executionContext">The execution context.</param>
protected override void Execute(CodeActivityContext executionContext)
{
// Create the tracing service
ITracingService tracingService = executionContext.GetExtension<ITracingService>();

if (tracingService == null)
{
throw new InvalidPluginExecutionException("Failed to retrieve tracing service.");
}

tracingService.Trace("Entered CwaBulkAppointmentStatusChange.Execute(), Activity Instance Id: {0}, Workflow Instance Id: {1}",
executionContext.ActivityInstanceId,
executionContext.WorkflowInstanceId);

// Create the context
IWorkflowContext context = executionContext.GetExtension<IWorkflowContext>();

if (context == null)
{
throw new InvalidPluginExecutionException("Failed to retrieve workflow context.");
}

tracingService.Trace("CwaBulkAppointmentStatusChange.Execute(), Correlation Id: {0}, Initiating User: {1}",
context.CorrelationId,
context.InitiatingUserId);

IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

try
{

DateTime startDate = this.StartDate.Get(executionContext).ToLocalTime();
DateTime endDate = this.EndDate.Get(executionContext).ToLocalTime();
int startTime = this.StartTime.Get(executionContext);
int endTime = this.EndTime.Get(executionContext);
int cancellationReason = this.CancellationReason.Get(executionContext);
EntityReference contactRef = this.Contact.Get(executionContext);

CommonClientAppointment commonClientAppointment = new CommonClientAppointment();
commonClientAppointment.CancelHPAppointments(service, contactRef, startDate, endDate, startTime, endTime, cancellationReason);

}
catch (FaultException<OrganizationServiceFault> e)
{
tracingService.Trace("Exception: {0}", e.ToString());
}

tracingService.Trace("Exiting CwaBulkAppointmentStatusChange.Execute(), Correlation Id: {0}", context.CorrelationId);
}
}

 

Other interesting bits of code, below I set the start date to add the hours selected in the start time, unless it’s value is zero (which means whole day), which I then use the default time 00:00 and for enddate I give the value of 23:59 (e.g. the whole day)


if (startTime > 0)
{
startDate = startDate.Date;
startDate = startDate.AddHours(startTime);
}
else
{
startDate = startDate.Date;
}

if (endTime > 0)
{
endDate = endDate.Date;
endDate = endDate.AddHours(endTime);
}
else
{
endDate = endDate.Date;
endDate = endDate.AddHours(23).AddMinutes(59);
}

 

The other tricky bit of code was time specified code.  To recap if a time was specified then the appointments between the time should be cancelled on every day specified in the date criteria.  To do this I calculated the difference in days and then looped around that many times and added a day each time I went round  the loop.

e.g.

start date 01/01/2014

end date 07/01/2014

start time 07:00

end time 12:00

 

This would cancel all morning appointments for all the days (01, 02, 03, 04, 05 , 06, 07)

I had two options, I could either create one query with multiple date conditions or I could create one query and then repeatedly call this with the start and end date changed.

I couldn’t quite invisage doing one query so I called the query once for each day in the date range.

List<Entity> bookedAppointments = new List<Entity>();
if (startTime == 0 || endTime == 0)
{
//full days
bookedAppointments = CancelAppointmentsRetrieve(service, hpEntityRef, startDate, endDate, statusCode);
}
else
{
//time specified
int days = calculateDays(startDate, endDate);
int counter = 0;
DateTime loopEndDate = startDate.Date.AddHours(endDate.Hour);
while (counter <= days)
{
bookedAppointments.AddRange(CancelAppointmentsRetrieve(service, hpEntityRef, startDate, loopEndDate, statusCode));
startDate = startDate.AddDays(1);
loopEndDate = loopEndDate.AddDays(1);
counter++;
}
}

if (bookedAppointments != null && bookedAppointments.Count > 0)
{
this.UpdateBookedAppointments(service, bookedAppointments, cancelReasonInt);
}

&nbsp;
<pre>

 

 

 

CRM 2013 Tool – CRM Early Bound Generator

Tanguy CRM MVP creator of the excellent XrmToolbox has let the framework of the XrmToolbox the tool CRM Early Bound Generator and this is very kind and extremely useful.

here is the video review, which runs through using the file in your plugin code in visual studio.

Lets start with the basics, the tool is free and you can find the tool on codeplex

https://xrmearlyboundgenerator.codeplex.com/

The CRM Early Bound generator is basically a way to make it easier to create Early bound entities and it does this by creating an application wrapped around the CrmSvcUtil.exe.

To find out more about the CrmSvcUtil.exe click the link below

http://msdn.microsoft.com/en-us/library/gg327844.aspx

I have blogged about using the crmsvcutil in a couple of blogs

CRM 2011 – How to add crmsvcutil to the External tools menu in Visual Studio

CRM 2011 – Simple CrmSvcUtil example for creating early bound classes

So it was with some interest I cracked open this tool and the first thing you notice is the initial container is the XrmToolBox

You then have to add a connection and then you will get this page.  If you have already setup the XrmToolbox you can copy the mscrmtools2011 and it will bring the connections you have already made to this tool.

Now although you can do this Early bound generator stuff with the CRM Developer toolkit he hulk2484 (excellent name), here is a picture of him

here is a picture of the tool main page

So from here you can now see you have quite a lot of options to create the early bound class.  I would mention that the codeplex page has a detailed description of all the options and this tool is one of the best documentation tools I have seen, so well done with that aspect of the tool (especially consider developers had documenting things)

I noticed that clicking

Create One File Per Entity

Generates an error

Entity Path must be a directory

I guess this is a bug or maybe something I’m not changing but I’m not sure you would go for all this effort to split the files into separate files

The things I liked about the tool was this option

Entities To Skip

This will allow you to select entities to not generate CRM early bound files for, this is very useful in keeping the size of the file down and the time it takes to generate (which although small, you will have to do this lots of times).  Also it remembers which records you have chosen to exlude.

Another good feature is it can create enum mappings for optionsets which makes it easier and safer to use these.

The tool is very good and easy to use. good job.

CRM 2013 – Plugins – Simple update plugin – Redeploying, improving and updating

I recently did a YouTube video which stepped through the process of creating a simple CRM 2013 plugin which ran on the update of the account entity.

The purpose of the video was to step through the process of creating a plugin and with that in mind I wanted to create the simpliest plugin I could think of.  Once you can do the process of creating a simple plugin and deploying it, it’s then a case of adding in your own logic and doing the process yourself.

In the first video – CRM 2013 – Create a simple plugin in CRM 2013 using the CRM Development Toolkit I explained some of the fundamental logic of a plugin (extending the IPlugin interface, the all important Execute method etc).  I also wanted to show how useful the CRM Developer toolkit was, particularly when it comes to creating and deploying plugins because it does a lot of the hard work for you.

I wanted to continue the journey of learning about plugins but without doing too much new code but I still wanted to add some new code so it’s interesting.

So I created a new video

CRM 2013 – simple update plugin, Redeploying, improving and updating 

This video updates the previous basic update plugin and this time I only trigger the plugin when a certain field Account Rating gets changed.  This is important thing to consider in update plugins, particularly in these days of autosaving.  Only trigger the plugin to run if certain fields are triggered, this will save server resources by not firing your plugin every 30 seconds.

It’s amazing the things you learn whilst writing blogs and recording videos.  I didn’t previously know how you deleted plugins using the CRM Development toolkit, so I started sniffing about and then worked out how to.   Below I run through changing the fields which trigger the account pre update plugin

Go to the CRM Explorer

You will notice the green plugins are the plugins in the solution you are in

nudge the down arrow and you can see the plugin steps

Update plugin 1

Edit the plugin step

Update plugin 2

The CRM Developer toolkit also allows you to delete the plugin or plugin steps, useful stuff

In the video – CRM 2013 – Simple update plugin – Redeploying, improving and updating I also run through a couple of important plugin concepts.

What’s passed into a plugin

The CRM 2013 SDK is a great document but a bit dry and difficult to get you started but once you are up and running there are lots of great explanations of how things work, this page is very useful for people writing plugins

Understand the Data Context Passed to a Plug-In

It explains what is actually passed into the plugin, the ServiceProvider has lots of goodies in like

IPluginExecutionContext

This has lots of data in like the user who triggered the plugin

IOrganizationService

Use this to access CRM and Create, Read, Update and Delete CRM records

context.InputParameters and context.OutPutParameters

The input parameters hold a collection and in that collect is the Target entity object, this has the values changed from the account update

there is also the tracing object

 

In the example I am going to use all three of these item and in most plugins you will use them but the page also has this table which explains what objects are passed into the context.InputParameters because it’s not always the Target object you should look for.  The picture below is a screenshot from the page

Update plugin 3

So what you should understand from the table above is, when a record or action triggers a plugin then usually either the entity is passed into the context.InputParameters or it’s an EntityReference.  You usually retrieve and cast this object out and then pass this to your plugin logic.

The one that used to catch me out was SetStateRequest passing the EntityMoniker.  What happened to me was I copied my boilerplate plugin code and I couldn’t understand why it wasn’t going into the code and running.  The reason was I was checking to see if the Target existed and if it did casting it to an entity and passing that into another method to do the work but it never went into my code.

So I had to debug the code to find there was no Target! finally I found the oddly named EntityMoniker and I worked out what to do from there.

 

 Plugin Stages

In the first plugin I couldn’t remember what the stages of a plugin were and their significance, all I could remember was they were linked to the database transaction and something about numbers going up in 10.

So I have done my homework and once again found some great information in the CRM 2013 SDK

event execution pipeline

The page has an interesting overview of the whole CRM architecture and it simplifies the stages
PRE-EVENT
PLATFORM CORE
POST-EVENT
The picture below is a screen from the Event Execution Pipeline page
Update plugin 4

As you know from registering plugins we can only register plugins

Pre-Validation – 10

Pre-Event – 20

Post-Event -40

The actually database transaction finishes in step 30 – Platform core operation and you can interfere with this, this is where the system plugins will run and kick off and updating system values and triggering other things.

An interesting point is the Pre-Validation, this is triggered before security checks have happened, so before CRM has checked the user can update the record maybe, basically before CRM checks the security roles and the PrincipalObjectAccess table (where all the security stuff is stored for users) is checked.

So that is the end of my quick plugin theory lesson and back onto the code, So along with the changing the plugin filter records (which you can see the RegisterFile.crmregister) I changed the code.

I now want to trigger the update on the change of AccountRating and I am going to read the value, which those of you who watched the video will know, OptionSetValue’s in CRM are held as ints.  CRM also holds Metadata on the OptionSet which holds the text.

My code is going to run based on the Int value because I think maybe in the future people might change the text in the OptionSet from Gold, Silver, Bronze to 1, 2, 3 or Great, OK, Rubbish.

I also get the guid of the user (entity SystemUser)who triggered the plugin by updating the AccountRating field.  This value is passed in with the plugin context and can be retrieved

Guid userId = context.InitiatingUserId;

There are two different user guid passed into the context and you should know which is which

context.initiatinguserid: the systemuser GUID who actually triggered the plugin
context.userid : gets the impersonated systemuser GUID

In my case I want the user who triggered the plugin

I then lookup the fullname and domainname of the user because this is more useful than a guid to end users but the guid is great for retrieving more data about that record.  I use the IOrganisationService to retrieve more fields from the record.  To do this all I need is the entity logical name, guid and the fields I want to retrieve

Entity userName = service.Retrieve(“systemuser”, userId, new Microsoft.Xrm.Sdk.Query.ColumnSet(new[] { “domainname”, “fullname” }));

Then it’s a case of concatenting them into string and adding this to the account entity being updated.

The full code is below

 

// <copyright file="PreAccountUpdate.cs" company="Microsoft">
// Copyright (c) 2014 All Rights Reserved
// </copyright>
// <author>Microsoft</author>
// <date>4/3/2014 12:04:45 AM</date>
// <summary>Implements the PreAccountUpdate Plugin.</summary>
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.1
// </auto-generated>
namespace HoskCRMDev2013.Plugins
{
using System;
using System.ServiceModel;
using Microsoft.Xrm.Sdk;

/// <summary>
/// PreAccountUpdate Plugin.
/// Fires when the following attributes are updated:
/// All Attributes
/// </summary>
public class PreAccountUpdate: Plugin
{
/// <summary>
/// Initializes a new instance of the <see cref="PreAccountUpdate"/> class.
/// </summary>
public PreAccountUpdate()
: base(typeof(PreAccountUpdate))
{
base.RegisteredEvents.Add(new Tuple<int, string, string, Action<LocalPluginContext>>(20, "Update", "account", new Action<LocalPluginContext>(ExecutePreAccountUpdate)));

// Note : you can register for more events here if this plugin is not specific to an individual entity and message combination.
// You may also need to update your RegisterFile.crmregister plug-in registration file to reflect any change.
}

/// <summary>
/// Executes the plug-in.
/// </summary>
/// <param name="localContext">The <see cref="LocalPluginContext"/> which contains the
/// <see cref="IPluginExecutionContext"/>,
/// <see cref="IOrganizationService"/>
/// and <see cref="ITracingService"/>
/// </param>
/// <remarks>
/// For improved performance, Microsoft Dynamics CRM caches plug-in instances.
/// The plug-in’s Execute method should be written to be stateless as the constructor
/// is not called for every invocation of the plug-in. Also, multiple system threads
/// could execute the plug-in at the same time. All per invocation state information
/// is stored in the context. This means that you should not use global variables in plug-ins.
/// </remarks>
protected void ExecutePreAccountUpdate(LocalPluginContext localContext)
{
if (localContext == null)
{
throw new ArgumentNullException("localContext");
}

// TODO: Implement your custom Plug-in business logic.
// Obtain the execution context from the service provider.
IPluginExecutionContext context = localContext.PluginExecutionContext;
IOrganizationService service = localContext.OrganizationService;

// The InputParameters collection contains all the data passed in the message request.
if (context.InputParameters.Contains("Target") &&
context.InputParameters["Target"] is Entity)
{
// Obtain the target entity from the input parmameters.
Entity entity = (Entity)context.InputParameters["Target"];
string entityDescription = "HOSK CRM DEV FIRST PLUGIN HAS RUN AND UPDATED THE DESCRIPTION";

//accountratingcode
if (entity.LogicalName == "account")
{

try
{
if (entity.Attributes.Contains("accountratingcode"))
{
Guid userId = context.InitiatingUserId;
Entity userName = service.Retrieve("systemuser", userId, new Microsoft.Xrm.Sdk.Query.ColumnSet(new[] { "domainname", "fullname" }));
string fullname = (string)userName.Attributes["fullname"];
string domainName = (string)userName.Attributes["domainname"];
entityDescription = "user " + fullname + "has the domain name of " + domainName;
entityDescription = entityDescription + Environment.NewLine + DateTime.UtcNow.ToString();
OptionSetValue accountRatingCode = (OptionSetValue)entity.Attributes["accountratingcode"];
if (accountRatingCode.Value == 1)
{
entityDescription = entityDescription + Environment.NewLine + "account rating = gold";
}
else if (accountRatingCode.Value == 100000000)
{
entityDescription = entityDescription + Environment.NewLine + "account rating = silver";
} else {
entityDescription = entityDescription + Environment.NewLine + "account rating = bronze";
}

if (entity.Attributes.Contains("description"))
{
//string entityDescription = (string)entity.Attributes["description"];
//entityDescription = "HOSK CRM DEV FIRST PLUGIN HAS RUN AND UPDATED THE DESCRIPTION";
entity.Attributes["description"] = entityDescription;
}
else
{
//entityDescription = "HOSK CRM DEV FIRST PLUGIN HAS RUN AND UPDATED THE DESCRIPTION";
entity.Attributes.Add("description", entityDescription);
}

}
}

catch (FaultException ex)
{
throw new InvalidPluginExecutionException("An error occurred in the plug-in.", ex);
}
}
}
}
}
}

 

CRM 2013 – Workflow to set the current date and time

This question has popped up in the forums now and again so I thought I would write a blog post on it.

The solution on how to do this is simple, once you know where to look and how it works.  I can understand why some people struggle to find the answer to the question of setting a date field to the current date and time because you don’t see it mentioned very often and it isn’t obvious.

To set the a Date Time value in CRM to a when the workflow was run you can use the dynamic value

Process

Execution Time

This basically does what is says on the tin and sets a Date time value to Execution time of the workflow.

workflow for current date and time

Open up your workflow and choose the Update, select Account entity

To set a field

Select the field and in the example above, I clicked into the Account Date Field

In the look for I scrolled down to Process (it’s right at the bottom)

in the next field select Execution Time

Press OK

You will see the Account Date Field will now have a highlighted value.

Save and Close

Activate the workflow

CRM 2013 Video  Workflow to set date and time field and user when the primary contact on an account is changed

Awesome picture from here