Showing posts with label Plugin. Show all posts
Showing posts with label Plugin. Show all posts

Tuesday, October 14, 2014

How to debug a sandbox plugin in CRM 2013 online

How to debug a sandbox plugin in CRM 2013 online

Preface

Debugging a sandboxed plugin in CRM 2013 online may sound a little obscure at first but don't you deny that it would be really life saver. Maybe you've given up the idea and instead decided to do something that I call poor man's debugging - throwing InvalidPluginExecutionExceptions everywhere and hoping to find a solution? I admit, I used to do that a lot too but this is just wrong. Throwing exceptions is not a solution for debugging, it is solution for handling exceptions and should stay that way.

In this blog post I'm teaching you, step by step, how you can debug a plugin in CRM and save a huge amount of time and effort in the future.

First we go through what you'll need. You probably own all necessary components already since you are a CRM programmer.

Then I explain an example scenario that I'm using while going through this debuggin process.

You may now close all other tabs in your browser. This blog post contains all you need in order to debug a plugin in CRM Online.

What you need

  1. Plugin to debug
  2. CRM 2013 online (although this might work for on-premises as well)
  3. CRM 2013 SDK
  4. Visual Studio (I'm using Visual Studio 2012)

Scenario

Let's pretend we are developing a plugin that has to generate an email address for a contact. Email address is generated by using contact's full name and by adding a fixed "@exampledomain.com" to the end. 

We've created a plugin that'll be fired always when a contact is created or updated (running a plugin on every update is not preferred in this case but just play along). 

Both steps are registered on pre-operation stage of execution.

Below is my plugin code. Note that I've divided some of the common plugin logic to its own class (Plugin.cs) which we are inheriting in our actual plugin. 


So what happens there is we take target entity's full name property and add "@exampledomain.com" to it. Then we assign that new email string to entity's emailaddress1 property. Since this is a pre-operation plugin we don't have to call update.

This plugin works well on create because full name is business required field. But for some reason on update this is not working... Well we all know the reason already, but let's pretend we don't.

It's debugging time!

Debug a plugin

Step 1
Open your plugin registration tool. It is located in SDK\Tools\PluginRegistration folder.


Step 2
While plugin registration opened you want to install something called a profiler. All you need to do is to press "Install Profiler" and wait for a moment. 



When the profiler is installed (when you see "Profiler Installed Succesfully") press Ok. 

Note: This (profiler) creates a new managed solution to CRM. As I was writing this tutorial something weird happened (CRM happened) and my plugin registration tool lost a connection to CRM. I wasn't able to connect CRM for a little moment so I went and deleted that managed solution from CRM manually. I don't know if it was only coincidence or if it actually helped but everything worked normally after that. So that's something to keep in mind for sure!

Step 3
Choose a plugin and a plugin step you want to debug.

As described in the scenario our plugin is crashing on update event. So we want to debug our plugin on update step / event. 

Highlight a correct step and press "Start Profiling"



Step 4
Set up profiler settings. You may want to leave them as they are. Press OK when ready.



Step 5
Once you've started the profiler you have to raise an event that will fire the plugin. In our case that means we have to update an existing contact.

I'm updating Fernando Alonso's job title to 1st driver which will raise an update event but will also crash our plugin (well, you know why don't you). When that happens a profiler gives us a log file that we have to download and store locally for further use.

Download the log file and then close business process error popup by pressing ok.



Step 6
Go back to your plugin registration tool and press debug.



Step 7
Replay Plug-in Execution popup opens on the screen. There are three fields that has to be filled.

1. To "Profile" field search the log file you just downloaded in step 5.
2. Assembly Location: To this field you need to search for your plugin's DLL file. When you are building your projects in Visual Studio it creates a debug folder under a bin directory. Use the DLL file from the debug folder.
3. Select the right plugin

Do not press Start Execution yet



Step 8
Open Visual Studio and your plugin solution / project if not already opened.

Add break points to your code. 

So from now on it works as normal debugging. I add one break point to beginning of the plugin.



Step 9
Attach Visual Studio to PluginRegistration process.

When Visual Studio and your plugin solution / project is opened go to Debug -> Attach to process.



Step 10
Select PlugingRegistration.exe from the list. If you have more than one opened at the same time make sure to select a right one. Then press attach. Your Visual Studio will go to a debug mode.

Step 11
This is the moment we've been waiting for. Go back to plugin registration tool and press "Start Execution".



Step 12
Now you can actually debug your code, step by step!



Step 13
Enjoy! When you're done stop profiling and remove profiler. I'm sure you'll find out how, just do the steps in reverse order :)

Final step
Find the problem and fix it.

For those who wonder the problem was that target entity didn't carry full name property because it was not changed and thus not passed for the execution context. That's why we got "The given key was not present in the dictionary"


Final words

Thank you for reading. Hopefully I was able to clear things out. This may seem little overkill but trust me on this, it'll save you a lot of time on a long run.

Please do not pay too much attention to code in this post. I wanted to keep it simple as possible. Don't do what I do, do what I say :)

Wednesday, September 4, 2013

How to copy an entity using C# plugin and early bound classes

Hello,

In this post I'm going to explain you how to copy an entity by using plugin written in C#. I'm also demonstrating you the power of CrmSvcUtil which "generates early-bound .NET Framework classes that represent the entity data model used by Microsoft Dynamics CRM" for your Visual Studio project. I'm not going through how to use CrmSvcUtil. If you need help getting started with it please refer Create Early Bound Entity Classes with the Code Generation Tool (CrmSvcUtil.exe).

As an example I'm going to use Contact entity. I'm going to attach my plugin in Delete event / message so that when ever the user deletes the contact my plugin will run and copy that contact.

Some prerequisites are

  • You have Visual Studio and know how to create a solution and a project.
  • You have plugin registration tool and know how to register a plugin
  • You have CrmSvcUtil and know how to generate classes and import them as part of your Visual Studio project.
  • You have Microsoft Dynamics CRM SDK (which actually includes plugin registration tool and CrmSvcUtil)
So let's get started. I'm writing this post as I'm doing this task so you may want to do some things in different order maybe.

Step 1

Create a new solution (or use existing one) and add new project into it. There are some assemblies you have to add.
  • Microsoft.Xrm.Sdk (this can be found inside the SDK)
  • Microsoft.Xrm.Sdk.Client
  • System.ServiceModel
  • System.Runtime.Serialization

Step 2

Generate classes by running CrmSvcUtil.exe from console. You may want to check all available attributes from the link I provided in a beginning. As a reference this is how my command looks like

C:\Program Files (x86)\Microsoft Dynamics CRM 2011 SDK\bin>CrmSvcUtil.exe /url:https://antaumus601.crm4.dynamics.com/XRMServices/2011/Organization.svc /out:EarlyBoundClasses.cs /username:"myUsername" /password:"myPassword" /namespace:AntaumusCRMSolution

When the .cs file is ready add it to your Visual Studio project.

Step 3

Write the core plugin components (implement IPlugin interface etc.). If you need help with writing plugin please refer Plug-in Development for Microsoft Dynamics CRM

Step 4

Now let's write the actual logic.Very important part when using early bound types is OrganizationServiceContext class. Please refer Use the Organization Service Context Class. In this case it will help us to add our new contact easily to CRM but it has a lot of good benefits (for example LINQ providing).

"To instantiate the context class, you must pass the class constructor an object that implements the IOrganizationService interface."

Fortunately we can create IOrganizationService indirectly from IServiceProvider that is passed for Execute method by writing following lines

IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
IOrganizationService service = serviceFactory.CreateOrganizationService(executionContext.UserId);
OrganizationServiceContext orgServiceContext = new OrganizationServiceContext(service);  

So in shortly what happens here is we take IOrganizationServiceFactory from service provider and then use the factory for creating a service. If you want to know more about factories this might be good place to start: Exploring the Factory Design Pattern

Now when everything is settled you can create new entities like this

Contact newContact = new Contact();

And access its properties like this

newContact.FirstName

You can add entity / entities for set OrganizationServiceContext is tracking by using AddObject method. When running SaveChanges() function all changes are  performed for entities that are in the set.

Very simple. I'm not going to explain my whole code here but instead I'll paste it to the end so you can take a look at it by yourself. To keep it very simple I did not copy whole contact in my code, only first name and last name. The approach I'm using in this example may not be the best. If I should really copy the whole contact (and related entities) I might think about using LINQ for sure.

Step 5

Register your plugin in a way you want. I registered it in Post-operation Delete message synchronously and created Pre Entity image. You may have to sign you Visual Studio project first.



















Final result