a.k.a – Once I did a session twice
Just like last year in Lisbon, I did a developer focused session during eXtreme365 in Dubrovnik. Last year I had full focus on how to develop plugins for analysis, primarily using the Plug-in Trace Log in the code and how to best analyze the results of it.
This year I took a bit wider approach with an ambition to help developers become more productive and get higher quality of their code. In this article I will go through the five different areas I covered in the session.
The presentation can be viewed and downloaded from SlideShare on this link.
There are of course many different approaches that can help your development and just as many opinions as there are developers, but I focused on the following five areas:
- Visual Studio Extensions
Customizing Visual Studio for Dynamics 365 development
- C# Extensions
Get more functionality from standard SDK types
- Base Classes
Generalize behavior and structure of plugin classes
- VSTS Build Extensions
Automate CI / CD for the Dynamics 365 platform
- XrmToolBox helping out
A few tools to take your development the last kilometer
1. Visual Studio Extensions
VS extensions can make your development environment a bit more “aware” of Dynamics 365 and the special characteristics of development for the platform.
There are a few of these out there, and as always you start with looking for something from the “source”, i.e. Microsoft. They do have the Microsoft Dynamics 365 Developer Toolkit which unfortunately still does not support VS2017. That currently is a deal breaker for many of us, but there is hope! Matt Barbour announced during eXtreme365 that they now have a team of a handful people devoted to developer tooling, so we are looking forward to some improvements!
Another option which looks really good is the XrmToolkit extension by Simpler Software. It contains most of the features you might need and as a well polished addition to the VS experience. The downside here is of course that this is not a community effort, they charge for each developer on your team.
A community based option is the D365 Developer Extensions by MVP Jason Lattimer. These extensions got a true revival when support for VS2017 was introduced, while the one from Microsoft still does not have that.
With these extensions you can easily speed up your development by using project templates and item/class templates. These will add NuGet references to the CRM SDK and provide base classes to facilitate plugin development and much more.
2. C# Extensions
Creating your own C# extensions to existing classes is a great way to make these classes behave just the way You want to.
A classic example is to add a GetParent and GetChildren extensions to the Entity class from the SDK. That makes it so much easier to traverse the information structure to get related information:
var account = contact.GetParent(service, "parentcustomerid", "name", "revenue"); var cases = account.GetChildren(service, "incident", "customerid", "ticketnumber", "subject");
The first line gets the account referenced in the Parent Customer attribute of a contact, and returns the account with attributes Name and Revenue.
The second line gets all cases where the account is referenced in the Customer attribute, and returns Ticket Number and Subject for the cases.
The syntax to create the extensions above would be:
public static Entity GetParent(this Entity entity, IOrganizationService svc, string lookupattribute, params string attributes) public static IEnumerable<Entity> GetChildren(this Entity entity, IOrganizationService svc, string childtype, string lookupattribute, params string attributes)
Other useful extensions to the Entity class are GetAssociated, Associate, Disassociate, Clone, Merge and so on.
There are a few really nice C# extension packages published, where one example is MVP Daryl LaBar’s DLaB.Xrm package that among other things contains very useful extensions to make the creation of QueryExpression objects so much easier.
Where the C# extensions make existing classes perform more actions than they used to, the base classes are an extra layer of code, taking care of all the boring plumbing and generalizing the behavior that you without them would have to write again and again for each plugin or other code executing in similar context.
Base classes for plugins are available in most VS Extensions, and I think anyone who has developed more than three plugins is definitely using existing base classes or have created their own. We just don’t like to repeat code. Period.
When you are building your plugins using a base class, you don’t directly implement the IPlugin interface from the SDK. Instead you inherit a class that implements the interface. The base class usually initiates the OrganizationService, TracingService and extracts the PluginExecutionContext, to make these directly available to the plugin developer through a custom “context”.
It is also a great way to add your own metrics to your code, without having to add timing functionality in all custom code. You can add all CRUD methods available on the OrganizationService directly on the custom context, which can then automatically write the actions to the Plug-in Trace Log, adding timestamps and timers and even automatic indentation of trace lines etc, to make the log easier to digest for efficient analysis.
4. VSTS Build Extensions
Building and deploying artifacts for the Dynamics 365 platform is not easy only using out of the box tools. To make it bearable, there are a few extensions to Visual Studio Team Services.First, most popular, and most diverse is the xRM CI Framework by Wael Hamze. This toolkit contains a number of custom tasks for VSTS related to Dynamics 365, such as Update Assembly, Update WebResources, Set Solution Version, Export Solution, Unpack Solution, Backup Online Instance, and many more.The second one, released by me and probably still most used by us at Innofactor, is called DevOps for Microsoft Dynamics 365. This extension does not contain all the tasks that Wael produced, but has the advantage of fully supporting Shuffle based operations where you with very detailed granularity can specify which solutions and data to export, and how to import that to target environments. More information about the Shuffle and the VSTS extensions can be found here: Build and Deploy Microsoft Dynamics 365 projects using VSTS.Another VSTS extension that we use, though not related to Build and Deploy, is NuGet Package Manager from Microsoft. We use this for internal distribution of the base classes and C# extensions we use throughout all of our development. This way, we get a controlled delivery process for the tools we use to build our solutions.
5. XrmToolBox helping out
As we all know by now:…and there is no process that cannot be improved by utilizing the power of a few XrmToolBox tools.
- So if you are working with early bound classes, you simply must use the Early Bound Generator by Daryl LaBar to create just the style of classes that you need for your project.
- If you are instead going late bound, try my Latebound Constants Generator to create constant files and classes for the entities, attributes and optionsets in your project. No more typos, no more inconsistent constant structures.
- When you just want to try out your code, or perhaps create a one-time gadget to fix broken data, investigate something, or just want to play around with the SDK, you really should try the Code Now tool by Alex Shlega. This tool offers you an OrganizationService, and you can go where you want from that. The code can be compiled and executed immediately, or compiled into an exe file that you can ship to be executed on-site.
- For me, who rarely do things early bound, the Metadata Browser by Tanguy Touzard himself helps me out a lot. I don’t investigate the system in the CRM UI, it is just too slow and clicky for me. I use this excellent XrmToolBox tool when there is anything metadata related I need to know.
- A super simple click saver is the Plugin Auto Updater by Alexey Shytikov. With this tool you just connect to CRM, select a dll file on your disk, and as soon as that dll is updated on disk it will find corresponding plugin registration and update it in CRM. So when you are developing you just edit your code, compile the file, and a second later you can try it out in CRM. With no clicks.
- I use FetchXML Builder when I need help to compose a QueryExpression query, but want to build it and be able to test it along the way. Just compose the query, and see corresponding C# code develop along with it. One day, it will have the possibility to generate WebAPI queries too…
- Finally, my plugin development would not be the same without my personal favorite; the Plugin Trace Viewer. Since I don’t debug plugins and automated tests never cover everything, I make sure I get verbose and readable logs written from my code and my frameworks. And I investigate using PTV, since the OOB UX absolutely s*cks.
There is a sample solution from my session that can be downloaded or forked from GitHub:
It contains two plugin classes, ContactPlugin1 and ContactPlugin2, that do the same thing. The first is based on the plugin base class from Jason Lattimer’s D365 Developer Extensions for Visual Studio. The second one is based on the JonasPluginBase class available in GitHub package Rappen.Xrm.JonasPluginBase. This example class has been described in my blog previously: I get by with a little help from my [base class].
Registering the assembly and adding a step for Update Contact Fax, and adding a post image with all attributes can give you this log in the Plugin Trace Log:
19:19:17.996 *** Enter 19:19:18.407 [JPB] Context details: Step: Plugin.ContactPlugin2: Update of contact Msg: Update Stage: 40 Mode: 0 Depth: 1 Corr: 6148b9d3-2875-4bdc-8a51-66dfa1e9bf6e Type: contact Id: 7b143128-8d27-e811-a951-000d3a276633 User: 10da6cc3-8627-e811-a954-000d3a26abad IUser: 10da6cc3-8627-e811-a954-000d3a26abad 19:19:19.074 [JPB] Incoming contact contactid = 7b143128-8d27-e811-a951-000d3a276633 (Guid) fax = 0101-121212 (String) 19:19:19.085 Hello world 19:19:19.085 BEGIN Checking images 19:19:19.085 PreImage count: 0 19:19:19.095 PostImage count: 1 19:19:19.095 END Checking images 19:19:19.106 BEGIN Doing the things 19:19:19.106 Entity is contact 7b143128-8d27-e811-a951-000d3a276633 19:19:19.106 [JPB] Retrieve(account, 0f143128-8d27-e811-a951-000d3a276633, 2) 19:19:20.179 [JPB] Retrieved in: 1074 ms 19:19:20.179 Parent is account Alpine Ski House (sample) 19:19:20.241 [JPB] RetrieveMultiple(incident) 19:19:20.316 [JPB] Retrieved 2 records in: 76 ms 19:19:20.326 Found 2 cases: CAS-01002-N7R1J4, CAS-01006-C1F4Z4 19:19:20.326 BEGIN Looping cases 19:19:20.326 Updating entity 19:19:20.326 [JPB] Update(incident) 29143128-8d27-e811-a951-000d3a276633 (5 attributes) 19:19:20.463 [JPB] Updated in: 139 ms 19:19:20.463 Updating entity 19:19:20.463 [JPB] Update(incident) 31143128-8d27-e811-a951-000d3a276633 (5 attributes) 19:19:20.568 [JPB] Updated in: 103 ms 19:19:20.568 END Looping cases 19:19:20.568 END Doing the things 19:19:20.568 [JPB] Internal execution time: 1491 ms 19:19:20.568 *** Exit
Once I did a session twice
What’s up with the subtitle?
Well, we were all overwhelmed by the interest for my session. In a room with ~70 seats we crammed in well over 100 people, and the organizers had to turn down another 40 something at the door. So they squeezed in another spot for me and I did the same session the next day too!
The presentation from eXtreme365 can be viewed and downloaded from SlideShare on this link.