This is an accompanying blog post to my YouTube video Dynamics 365 Customer Engagement Deep Dive: Creating a Basic Jscript Form Function, the first in a series that aims to provide tutorials on how to accomplish developer focused tasks within Dynamics 365 Customer Engagement. You can watch the video in full below:

Below you will find links to access some of the resources discussed as part of the video and to further reading topics.

PowerPoint Presentation (click here to download)

Full Code Sample

function changeAddressLabels() {

    //Get the control for the composite address field and then set the label to the correct, Anglicised form. Each line requires the current control name for 'getControl' and then the updated label name for 'setLabel'

    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_line1").setLabel("Address 1");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_line2").setLabel("Address 2");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_line3").setLabel("Address 3");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_city").setLabel("Town");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_stateorprovince").setLabel("County");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_postalcode").setLabel("Postal Code");
    Xrm.Page.getControl("address1_composite_compositionLinkControl_address1_country").setLabel("Country");

    if (Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_line1"))
        Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_line1").setLabel("Address 1");

    if (Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_line2"))
        Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_line2").setLabel("Address 2");

    if (Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_line3"))
        Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_line3").setLabel("Address 3");

    if (Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_city"))
        Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_city").setLabel("Town");

    if (Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_stateorprovince"))
        Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_stateorprovince").setLabel("County");

    if (Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_postalcode"))
        Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_postalcode").setLabel("Postal Code");

    if (Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_country"))
        Xrm.Page.getControl("address2_composite_compositionLinkControl_address2_country").setLabel("Country");
}

Download/Resource Links

Visual Studio 2017 Community Edition

Setup a free 30 day trial of Dynamics 365 Customer Engagement

W3 Schools JavaScript Tutorials

Source Code Management Solutions

Further Reading

MSDN – Use JavaScript with Microsoft Dynamics 365

MSDN – Use the Xrm.Page. object model

MSDN – Xrm.Page.ui control object

MSDN – Overview of Web Resources

Debugging custom JavaScript code in CRM using browser developer tools (steps are for Dynamics CRM 2016, but still apply for Dynamics 365 Customer Engagement)

Have any thoughts or comments on the video? I would love to hear from you! I’m also keen to hear any ideas for future video content as well. Let me know by leaving a comment below or in the video above.

Did you know that you can write Plug-ins for Dynamics 365 Customer Engagement/Dynamics CRM (D365CE/CRM) using Visual Basic .NET (VB.NET)? You wouldn’t have thought so after a thorough look through the D365CE/CRM Software Development Kit (SDK). Whilst there is a plethora of code examples available for C# plug-ins, no examples are provided on how to write a basic plug-in for the application using VB.NET. This is to be expected, perhaps due to the common status that the language has when compared with C#. Whilst VB.NET knowledge is a great asset to have when extending Office applications via Visual Basic for Applications, you would struggle to find many at scale application systems that are written using VB.NET. C# is pretty much the de facto language that you need to utilise when developing in .NET, and the commonly held view is that exclusive VB.NET experience is a detriment as opposed to an asset. With this in mind, it is somewhat understandable why the SDK does not have any in-depth VB.NET code examples.

Accepting the above, it is likely however that many long-standing developers will have knowledge of the BASIC language, thereby making VB.NET a natural choice when attempting to extend D365CE/CRM. I do not have extensive experience using the language, but I was curious to see how difficult it would be to implement a plug-in using it – and to hopefully provide assistance to any lonely travellers out there who want to put their VB.NET expertise to the test. The best way to demonstrate this is to take an existing plug-in developed in C# and reverse engineer the code into VB.NET. We took a look at a fully implemented plug-in previously on the blog, that can be used to retrieve the name of the User who has created a Lead record. The entire class file for this is reproduced below:

using System;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;

namespace D365.BlogDemoAssets.Plugins
{
    public class PostLeadCreate_GetInitiatingUserExample : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            // Obtain the execution context from the service provider.

            IPluginExecutionContext context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));

            // Obtain the organization service reference.
            IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

            // The InputParameters collection contains all the data passed in the message request.
            if (context.InputParameters.Contains("Target") &&
                context.InputParameters["Target"] is Entity)

            {
                Entity lead = (Entity)context.InputParameters["Target"];

                //Use the Context to obtain the Guid of the user who triggered the plugin - this is the only piece of information exposed.
      
                Guid user = context.InitiatingUserId;

                //Then, use GetUserDisplayCustom method to retrieve the fullname attribute value for the record.

                string displayName = GetUserDisplayName(user, service);

                //Build out the note record with the required field values: Title, Regarding and Description field

                Entity note = new Entity("annotation");
                note["subject"] = "Test Note";
                note["objectid"] = new EntityReference("lead", lead.Id);
                note["notetext"] = @"This is a test note populated with the name of the user who triggered the Post Create plugin on the Lead entity:" + Environment.NewLine + Environment.NewLine + "Executing User: " + displayName;

                //Finally, create the record using the IOrganizationService reference

                service.Create(note);
            }
        }
    }
}

The code above encapsulates a number of common operations that a plug-in can seek to accomplish – updating a record, obtaining context specific values and performing a Retrieve operation against an entity – thereby making it a good example for what will follow in this post.

With everything ready to go, it’s time for less talking and more coding 🙂 We’ll build out a VB.NET version of the above class file, covering some of the “gotchas” to expect on each step, before then bringing all of the code together in a finished state.

Importing References

As you would expect within C#, a class file requires references to the D365CE SDK DLL files. These should be imported into your project and then added to your class file using the Imports statement:

With these two lines of code, there are immediately two things which you may need to untrain yourself from doing if you have come from a C# background:

  1. Make sure not to add your semi-colons at the end of each line, as it is not required for VB.NET
  2. You may be tempted to use the Return key to auto-complete your syntax, which works fine in a C# project…but will instead skip you down to the next line in VB.NET. Instead, use the Tab key to autocomplete any IntelliSense prompts.

Adding a Namespace

By default, a VB.NET class project does not implement a Namespace for your class. This will need to be added next, underneath the project references like so:

Implementing the IPlugin Interface

So far so good…and things continue in the same vein when implementing the IPlugin interface. This is configured like so:

The only thing to remember here, if you are still in C# mode, is that your colon is replaced with the Implements statement and that this part of the code needs to be moved to the next line.

Putting together the Execute Method

The Execute method is the heart and soul of any plug-in, as this contains the code that will execute when the plug-in is triggered. In C#, this is implemented using a void method (i.e. a block of code that does not return a specific value, object etc.). It’s equivalent within VB.Net is a Sub – short for “Subroutine” – which needs to be additionally peppered with an Implements statement to the IPlugin.Execute sub:

Implementing Variables

Here’s where things start to get different. Variables within C# are generally implemented using the following syntax:

<Type> <Variable Name> = <Variable Value>;

So to declare a string object called text, the following code should be used:

string text = “This is my string text”;

Variables in VB.NET, by contrast, are always declared as Dim‘s, with the name and then the Type of the variable declared afterwards. Finally, a value can then be (optionally) provided. A complete example of this can be seen below in the implementing of the IPluginExecutionContext interface:

In this above example, we also see two additional differences that C# developers have to reconcile themselves with:

  • There is no need to specifically cast the value as an IPluginExecutionContext object – a definite improvement over C# 🙂
  • Rather than using the typeof operator when obtaining the service, the VB.NET equivalent GetType should be used instead.

The process of creating variables can seem somewhat labourious when compared with C#, and there are a few other things to bear in mind with variables and this plug-in specifically. These will be covered shortly.

The If…Then Statement

Pretty much every programming language has an implementation of an If…Else construct to perform decisions based on conditions (answers in the comments if you have found a language that doesn’t!). VB.NET is no different, and we can see how this is implemented in the next bit of the plug-in code:

Compared with C#, you have to specifically remember to add a Then statement after your conditional test and also to include an End If at the end of your code block. It’s also important to highlight the use of different operators as well – in this case, And should be used as opposed to &&.

Assigning Values to a CRM Entity Object

The assignment of entity attribute values differs only slight compared with C# – you just need to ensure that you surround your attribute Logical Name value behind brackets as opposed to square brackets:

String concatenates also work slightly differently. Be sure to use & as opposed to to achieve the same purpose. For new line breaks, there is also an equivalent VB.NET snippet that can be used for this, vbCrLf.

Obtaining the Users Display Name Value

The final part of the class file is the retrieval of the Full Name value of the user. This has to be done via a Function as opposed to a Dim, as a specific value needs to be returned. Keep in mind the following as well:

  • Parameters that are fed to the Function must always be prefaced with the ByVal statement – again, another somewhat tedious thing to remember!
  • Note that for the GetAttributeVale method, we specify the attribute data type using the syntax (Of Stringas opposed to <string>

Other than that, syntax-wise, C# experienced developers should have little trouble re-coding this method into VB.NET. This is evidenced by the fact that the below code snippet is approximately 75% similar to how it needs to be in C#:

Bringing it all together

Having gone through the class file from start to bottom, the entire code for the plug-in is reproduced below:

Imports Microsoft.Xrm.Sdk
Imports Microsoft.Xrm.Sdk.Query

Namespace D365.BlogDemoAssets.VB

    Public Class PostLeadCreate_GetInitiatingUserExample
        Implements IPlugin

        Private Sub IPlugin_Execute(serviceProvider As IServiceProvider) Implements IPlugin.Execute

            'Obtain the execution context from the service provider.

            Dim context As IPluginExecutionContext = serviceProvider.GetService(GetType(IPluginExecutionContext))

            'Obtain the organization service reference.
            Dim serviceFactory As IOrganizationServiceFactory = serviceProvider.GetService(GetType(IOrganizationServiceFactory))
            Dim service As IOrganizationService = serviceFactory.CreateOrganizationService(context.UserId)

            'The InputParameters collection contains all the data passed in the message request.
            If (context.InputParameters.Contains("Target") And TypeOf context.InputParameters("Target") Is Entity) Then

                Dim lead As Entity = context.InputParameters("Target")

                'Use the Context to obtain the Guid of the user who triggered the plugin - this is the only piece of information exposed.

                Dim user As Guid = context.InitiatingUserId

                'Then, use GetUserDisplayCustom method to retrieve the fullname attribute value for the record.

                Dim displayName As String = GetUserDisplayName(user, service)

                'Build out the note record with the required field values: Title, Regarding and Description field

                Dim note As Entity = New Entity("annotation")
                note("subject") = "Test Note"
                note("objectid") = New EntityReference("lead", lead.Id)
                note("notetext") = "This is a test note populated with the name of the user who triggered the Post Create plugin on the Lead entity:" & vbCrLf & vbCrLf & "Executing User: " & displayName

                'Finally, create the record using the IOrganizationService reference

                service.Create(note)

            End If

        End Sub
        Private Function GetUserDisplayName(ByVal userID As Guid, ByVal service As IOrganizationService) As String

            Dim user As Entity = service.Retrieve("systemuser", userID, New ColumnSet("fullname"))
            Return user.GetAttributeValue(Of String)("fullname")

        End Function

    End Class

End Namespace

Conclusions or Wot I Think

C# is arguably the de facto choice when programming using D365CE/CRM, and more generally as well for .NET. All of the code examples, both within the SDK and online, will favour C# and I do very much hold the view that development in C# should always be preferred over VB.NET. Is there ever then a good business case for developing in VB.NET over C#? Clearly, if you have a developer available within your business who can do amazing things in VB.NET, it makes sense for this to be the language of choice to use for time-saving purposes. There may also be a case for developing in VB.NET from a proprietary standpoint. VB.NET is, as acknowledged, not as widely disseminated compared with C#. By developing custom plug-ins in VB.NET, that contain sensitive business information, you are arguably safeguarding the business by utilising a language that C# developers may have difficulty in initially deciphering.

All being said, C# should be preferred when developing plug-ins, custom workflow assemblies or custom applications involving D365CE/CRM. Where some work could be made is in ensuring that all supported programming languages are adequately provisioned for within the D365CE SDK moving forward. Because, let’s be honest – there is no point in supporting something if people have no idea how to use it in the first place.

The world of database security and protection can be a difficult path to tread at times. I often find myself having to adopt a “tin-foil hat” approach, obsessing over the smallest potential vulnerability that a database could be compromised with. This thought process can be considered easy compared with any protective steps that need to be implemented in practice, as these can often prove to be mind-bogglingly convoluted. This is one of the reasons why I like working with Microsoft Azure and features such as Azure SQL Database Firewall Rules. They present a familiar means of securing your databases to specific IP address endpoints and are not inordinately complex in how they need to be approached; just provide a name, Start/End IP range and hey presto! Your client/ application can communicate with your database. The nicest thing about them is that the feature is enabled by default, meaning you don’t have to worry about designing and implementing a solution to restrict your database from unauthorised access at the outset.

As alluded to above, Database Firewall Rules are added via T-SQL code (unlike Server Rules, which can be specified via the Azure portal), using syntax that most SQL developers should feel comfortable using. If you traditionally prefer to design and build your databases using a Visual Studio SQL Database project, however, you may encounter a problem when looking to add a Database Firewall rule to your project. There is no dedicated template item that can be used to add this to the database. In this eventuality, you would have to look at setting up a Post-Deployment Script or Pre-Deployment Script to handle the creation of any requisite rules you require. Yet this can present the following problems:

  • Visual Studio will be unable to provide you with the basic syntax to create the rules.
  • Related to the above, Intellisense support will be limited, so you may struggle to identify errors in your code until it is deployed.
  • When deploying changes out to your database, the project will be unable to successfully detect (and remove) any rules that are deleted from your project.

The last one could prove to be particularly cumbersome if you are tightly managing the security of your Azure SQL database. Putting aside the obvious risk of someone forgetting to remove a rule as part of a deployment process, you would then have to manually remove the rules by connecting to your database and executing the following T-SQL statement:

EXECUTE sp_delete_database_firewall_rule 'MyDBFirewallRule'

Not the end of the world by any stretch, but if you are using Visual Studio as your deployment method for managing changes to your database, then having to do this step seems a little counter-intuitive. Fortunately, with a bit of creative thinking and utilisation of more complex T-SQL functionality, we can get around the issue by developing a script that carries out the following steps in order:

  • Retrieve a list of all current Database Firewall Rules.
  • Iterate through the list of rules and remove them all from the database.
  • Proceed to re-create the required Database Firewall Rules from scratch

The second step involves the use of a T-SQL function that I have traditionally steered away from using – Cursors. This is not because they are bad in any way but because a) I have previously struggled to understand how they work and b) have never found a good scenario in which they could be used in. The best way of understanding them is to put on your C# hat for a few moments and consider the following code snippet:

string[] array = new string[] { "Test1", "Test2", "Test3" }; 

foreach(string s in array)
    {
        Console.WriteLine(s);
    }
    

To summarise how the above works, we take our collection of values – Test1, Test2 and Test3 – and carry out a particular action against each; in this case, print out their value into the console. This, in a nutshell, is how Cursors work, and you have a great deal of versatility on what action you take during each iteration of the “loop”.

With a clear understanding of how Cursors work. the below script that accomplishes the aims set out above should hopefully be a lot clearer:

DECLARE @FirewallRule NVARCHAR(128)

DECLARE REMOVEFWRULES_CURSOR CURSOR
	LOCAL STATIC READ_ONLY FORWARD_ONLY
FOR
SELECT DISTINCT [name]
FROM sys.database_firewall_rules

OPEN REMOVEFWRULES_CURSOR
FETCH NEXT FROM REMOVEFWRULES_CURSOR INTO @FirewallRule
WHILE @@FETCH_STATUS = 0
BEGIN
	EXECUTE sp_delete_database_firewall_rule @FirewallRule
	PRINT 'Firewall rule ' + @FirewallRule + ' has been successfully deleted.'
	FETCH NEXT FROM REMOVEFWRULES_CURSOR INTO @FirewallRule
END
CLOSE REMOVEFWRULES_CURSOR
DEALLOCATE REMOVEFWRULES_CURSOR

GO

EXECUTE sp_set_database_firewall_rule @name = N'MyDBFirewallRule1',
		@start_ip_address = '1.2.3.4', @end_ip_address = '1.2.3.4';

EXECUTE sp_set_database_firewall_rule @name = N'MyDBFirewallRule2',
		@start_ip_address = '1.2.3.4', @end_ip_address = '1.2.3.4';
		

To integrate as part of your existing database project, add a new Post-Deployment Script file and modify the above to reflect your requirements. As the name indicates, the script will run after all other aspects of your solution deployment has been completed. Now, the key caveat to bear in mind with this solution is that, during deployment, there will be a brief period of time where all Database Firewall Rules are removed from the database. This could potentially prevent any current database connections from dropping or failing to connect altogether. You should take care when using the above code snippet within a production environment and I would recommend you look at an alternative solution if your application/system cannot tolerate even a second of downtime.

A software upgrade/update always starts out with such good intentions and hopeful optimism. There are perhaps two opposing schools of thought that emerge when it comes to the merits and necessity of always ensuring you’re on the latest version of an application. The arguments for and against will generally look something like this:

In Favour

  • Having the latest version protects against potential exploits or security vulnerabilities present within an older version of the application.
  • The latest version of the application is easier to use, supports X feature etc.
  • The application will be end of life in the very near future, so we need to be proactive as opposed to reactive*

Against

  • The upgrade will take time to complete – we will have to perform in-depth testing and schedule time outside of normal business hours to carry this out.
  • As part of the XXX update, X feature is no longer available and we have to instead use Y feature instead.
  • The current version of the application works just fine – upgrading could cause us problems as a result of a bad security patch or similar.

*”very near future” is becoming more commonplace these days, particularly with Microsoft Cloud products. For example, Office 2013 is technically considered end of life for ProPlus customers at the end of this month.

Whilst I would argue strongly that keeping your important business applications up to date should always be an ultimate priority, the reality is less straightforward and even I have fallen foul of this in the past. Case in point: I recently upgraded to the Windows 10 Anniversary Edition from Windows 10, on a personal machine that had Hyper-V installed and a number of virtual images. The update went fine, but I was informed after the update that the latest version of .NET Framework needed to be downloaded. I dismissed the error message, as I was in the middle of something else, and then spent many hours later on attempting to figure out why the update had removed the Hyper-V program feature from my machine; after researching, I determined it was because of the prompt I had received when first booting up Windows and that the updated version of Hyper-V required the latest .NET Framework. I was able to get the role installed and re-configure all of my virtual images accordingly, but it did take some time and was definitely an unwelcome distraction! Suffice to say, an upgrade can never go exactly to plan, which is why I would always encourage the need for dedicated testing environments within your business for your primary IT systems. This will grant that you sufficient latitude to perform all required testing of an update and to give you the confidence that it can be deployed safely into your production environment(s).

Of course, the above does not help very much if you are upgrading your test environment and everything goes wrong there, such as what happened to me recently. The business in question was wanting to upgrade from Visual Studio 2013 to Visual Studio 2015. Their development environment was a virtualised, remote desktop server, which all of the developers logged into as their primary working environment. Development was carried out using the “out of the box” templates included in Visual Studio (C#, ASP.NET etc.) and also using SQL Server Data Tools for BIDS/SSIS development. All projects/solutions were stored in a central Git repository.

The process of installing Visual Studio 2015 and the current “production ready” 16.5 version of SQL Server Data Tools for Visual Studio 2015 went (rather too) swimmingly, and we began to run tests confirming that all Team Services projects opened without issue. We immediately came across an issue when attempting to open certain .rdl report files – Visual Studio would hang for about 10-15 minutes every time the report was opened, with the following prompt stuck on the screen and the application remaining in a non-responsive state:

The report would open fine in the end, but the issue was repeated whenever the report was re-opened.

We initially tried the following in an attempt to resolve the problem:

  • Re-cloned the repository – no joy.
  • Attempted to open the report from VS 2013 – the report opened fine without issue, so definitely a problem with VS 2015
  • Created a brand new Report Project template in VS 2015, added the report into the project (both as a copy and as a new report, with the underlying .xml definition copy + pasted) and then tried re-opening – the same issue occurred.

Being officially stumped at this juncture, I then did some further research online to see whether anyone else had encountered the same issue. Fortunately, I came across the following TechNet thread which contained the exact same symptoms we were experiencing:

https://social.technet.microsoft.com/Forums/sqlserver/en-US/ba55ce1b-0bac-4997-9e02-8748dfd38fae/opening-large-reports-in-ssrs-2016-takes-a-long-time-after-migratting-from-ssrs2012?forum=sqlreportingservices&prof=required

The thread seemed to attract some confused answers (in the sense that they didn’t grasp the underlying problem), before petering out with no apparent solution. Without holding my breath too much, I replied to the thread in the hopes of getting a definitive answer, which I received in almost record time:

Yes we did, we got a fix from Microsoft: https://go.microsoft.com/fwlink/?linkid=837939. After installing the reports where opening fine.

Not wishing to look a gift horse in the mouth at all, I did first double check the contents of the link to verify it – and it turned out to be 17.0 RC2 of SQL Server Data Tools for Visual Studio 2015. What’s worth noting is that the first hit on Google for SQL Server Data Tools Visual Studio 2015 is the download page for version 16.5 and not the following page that contains links to both versions:

https://docs.microsoft.com/en-us/sql/ssdt/download-sql-server-data-tools-ssdt

Those who have already read through the TechNet thread will know how things panned out in the end, but just to summarise – installing this fixed the issue. So major credit to Erwin de Kreuk for doing all of the “hard work” to finding the solution in this unusual case and in responding so quickly to my forum post. This is definitely a great example of the old adage “You don’t ask, you don’t get” and how the wider community can often prove invaluable when resolving an especially troublesome IT issue.

So what should you do if you are planning to upgrade SSDT from Visual Studio 2013 to Visual Studio 2015?

The key takeaway from the above should be the fact that a release-candidate version of SSDT provided a resolution to the problem at hand. It would, therefore, be foolhardy to recommend a general upgrade from VS 2013 whilst 17.0 remains at a release-candidate version. Given that this version was released at the start of the year, it is highly likely to expect that a production-ready version of 17.0 will be released in the very near future. I would recommend holding off on your upgrade if your organisation works with a large number of SSRS reports, lest you also fall foul of this surprisingly strange bug.

The recent releases of Dynamics CRM have very much been missing something for developers who work with the product. Whilst a number of exciting new features have been added to the product – the Web API, Interactive Service Hub and Portals, to name a few – there very much feels to be a lack of attention towards surrounding support tools to give developers a head start in progressing their careers and facilitating more agile and efficient development of bespoke CRM solutions. Exams are one area that has been guilty of this, with no up to date exam for developers released for over 3 years. In today’s modern world, 3 years is a lifetime of change and can leave developers in a situation where they are not aware of the latest technologies and potentially developing solutions that will soon be deprecated or lead to additional development time and administrative headroom to manage.

With this in mind, it is pleasing to hear that an updated version of the Visual Studio Developer Toolkit will be released for Dynamics 365 and that a beta version of this tool is now available to be downloaded. For those who have not used the earlier version of this tool for Dynamics 2013 and earlier, it provides developers the mechanism to create Visual Studio project templates that can store all of your related development assets, facilitate the deployment of these assets to your CRM instance from within Visual Studio and allow you to generate early-bound class files of your CRM entities and the requisite template class files for your Plugins; enabling you to focus more on developing your business logic. I have some experience using the tool myself in a sparing manner and have found it somewhat cumbersome to use. For example, I have had issues where I have had to sign into a development CRM system every time the project loads and I have not found it straightforward to use alongside existing CRM solutions. The tool is also only compatible with Visual Studio 2012 and earlier, which means developers running the latest version of Visual Studio will miss out on being able to use the toolkit. Nevertheless, the ability to generate the required code for your plugins in a quick manner is a major boon and, with the new release, a major opportunity is present in order to improve the tool and resolve some of its glaring issues. I’ve been taking a look at the Beta release of the Dynamics 365 Toolkit, and here are some of the new features which I am most excited about and feel will be a big help to developers in the months ahead:

Templates for Mobile App Development

For most standard deployments, the out of the box Dynamics 365 for Tablet/Mobile app will be sufficient for your users. You could even look at developing a simple app using PowerApps. For more advanced scenarios, the SDK would be your next port of call in order to develop a mobile app that connects up with CRM/D365E. This is a popular approach to take when developing a mobile app with a specific function, as it enables you to leverage the full functionality of CRM/D365’s processes as part of your app, whilst ensuring that the data model conforms to a familiar, SQL Server-based model. The analogy I have used before with other developers is that developing for Dynamics CRM is like developing for SQL Server on steroids 🙂

Previously, there were some code examples included as part of the SDK in order to help developers “get started” with developing a Windows Store, iOS and/or Android app that connects to CRM. Now, the Dynamics 365 Toolkit includes a number of Project templates that help with developing a mobile, store and/or universal app:

1

The only caveat with these templates is that they are designed solely for Windows-based devices; for a truly cross-platform application, then you would need to look at utilising a tool like Xamarin in order to meet your requirements.

Configuring Paths to SDK/Plugin Registration Tool

This is a minor new feature, but something that is important and, arguably, essential if you are frequently developing new CRM/D365E developer solutions. Within the settings page for the toolkit, you can now specify the location for your SDK DLL’s and Plugin Registration tool; which will then be used across all of the projects you create in Visual Studio moving forward:

7

This is a huge time-saving step and removes a rather tedious task that is often involved when it comes to setting up your Visual Studio projects.

Configure Microsoft Dynamics 365 Solution Wizard

When you now create a new Dynamics 365 solution template in Visual Studio, you are greeted with a simple and clear wizard that helps facilitates the following scenarios:

  • Specification of a persistent connection to CRM/D365E, that can then be re-used across different projects within Visual Studio and provides a familiar UI experience with the existing tools within the SDK (such as the Plugin Registration Tool):

 

38

 

  • The ability to select or create a brand new solution from within Visual Studio (previously, you only had the option of selecting an existing solution):

2

  • Granular level control of which templates to include in your project – including Plugins, Custom Workflow Assemblies or Web Resources/Assets:

 

6

With all these changes put together, the process of setting up new projects that are targeting a single CRM environment is greatly simplified and you can ensure that your project contains just the assets that you need.

Why the Developers Toolkit is important

One of the major hurdles that developers generally face is having to deal with all of the stuff that is non-development related – setting up environments, installing development tools and resolving environment configuration issues, to name but a few. Whilst all of this is useful experience and gives developers a flavour for how a potential application deployment will look, it can often get in the way of a developer’s primary responsibility; to just code. This is one of the reasons why DevOps is becoming an increasingly more important area of focus for businesses who employ developers, as having an effective DevOps strategy, plan and resource will ensure greater productivity from your existing resource and help to foster an environment where projects are being run the “right” way. The Developers Toolkit is an important tool in your DevOps arsenal, as it works towards meeting all of the above objectives and begins to foster an approach where set standards are followed across multiple projects. It also helps take out the administrative effort often involved with, for example, setting up a Plugin class file manually within Visual Studio. Although the Dynamics 365 Developers Toolkit is still in beta, and not ready for Production use, I would very much hope to see a full release in the near future. Tools of this nature (such as XRMToolBox and the Ribbon Workbench) help to encourage greater efficiency, which is often essential for many IT projects these days.