Showing posts with label crm 2016. Show all posts
Showing posts with label crm 2016. Show all posts

Wednesday, December 6, 2017

Set Properties not working when using editable grids

I found a little issue using editable grids. The following error occurs in all version since Editable Grids was introduced

When I have editable grids on the primary entity form then I cannot set the values for that entity inside a workflow. To reproduce the error do the following

  1. Create a new custom entity (or use an existing entity if you dare)
  2. Add a 1:N relationship from entity1 to any other entity
  3. Add a sub-grid to the form of entity1
  4. Go to the controls tab of the sub-grid, and choose add control. Select the Editable Grid control, and activate it for web
    image
  5. Save and publish the form
  6. Create a new workflow for the entity
  7. Add an update or create step for the record, and open the “set properties” window
  8. When you select any field, the operator drop-down and field drop-down will be empty, and you cannot select any values
    image

Changing the control to the standard read-only grid will prevent this error. Also, this error only occurs for custom entities with editable grids, not for default entities with editable sub grids.

Diving in to the debug console of your browser you will see the following error:

SCRIPT5009: '$P_CRM' is undefined
File: crminternalutility.js, Line: 1, Column: 1786

Browsing through the code it looks like $P_CRM should be an instance of jQuery, but it is never assigned.

Wednesday, June 7, 2017

Default view in subgrid resets to system default after edit

I just found a small bug (probably) when you edit the default view from a subgrid in a form. When you close the edit window (whether you made any changes or not), the default view resets to the system default.
To provoke this do the following steps:

  1. Open a form editor for a form with a subgrid (or just add one).
  2. Open the subgrid control, if you already use the system default then change to another one (and save)
  3. Click the edit button
  4. Close the edit view popup
  5. The default view resets to the system default
This isn't a big thing, but if you don't pay attention you're suddenly publishing a form change into production that isn't supposed to be there, and depending on your deployment routines it could be some time before you have the opportunity to fix it.

EDIT: Also realized a much larger issue. When this happens it also resets the "selected views" (if selected). That means that selected views will reset from your selected ones to ONLY the system default view (e.g. My Activities).

Also, now you know that it isn't you who did something wrong.


Tested and verified bug since at least CRM2015, still included in the current edition.

Video of the bug in action:

Thursday, January 26, 2017

Sending email to an alternate / secondary email address

Small plugin to send email to an alternate / secondary email address


Those who have worked with Dynamics365:CRM for a while has undoubtedly encounter this issue, which is that whatever address you enter as a recipient the system will resolve the record and substitute the address with the primary email address of the record.
There are several different ways of working around this issue, like creating leads that can be merged into existing contacts, duplicate contacts with links, etc. but I have created a small plugin which allows you to send an email to the address you want.
All you have to do is to compile the following code and register it as a synchronous, pre-operation plugin, and add a pre-entity image with the "to" field included. The secret here is to register it on the "send" message for the email entity.

Just add the microsoft.crmsdk from nuget to your project, and you'll have all the libraries you need to compile this little thing.

public class SendToSafeEmail : IPlugin
{
    public void Execute(IServiceProvider sp)
    {
        var context = (IPluginExecutionContext)sp.GetService(typeof(IPluginExecutionContext));
        var factory = (IOrganizationServiceFactory)sp.GetService(typeof(IOrganizationServiceFactory));
        var service = factory.CreateOrganizationService(context.UserId);

        Entity email = context.PreEntityImages.Values.First();
        var recipient = ((EntityCollection)email.Attributes["to"]).Entities.FirstOrDefault<Entity>();
        var to = (EntityReference)recipient.Attributes["partyid"];
        var contact = service.Retrieve("contact", to.Id, new ColumnSet("emailaddress3"));
        ((EntityCollection)email.Attributes["to"]).Entities[0].Attributes["addressused"] = contact.Attributes["emailaddress3"];
        service.Update(email);
    }
}

As you can see this isn't particularly advanced, and I would like to start with pointing out that I've removed exception handling and tracing for illustration purposes, I'm usually a lot more tidy (it's true!).
First off we retrieve the usual suspects, the execution context and the orgservice factory. Then we generate a new org-service connection based on the user ID of the user which triggered the plugin. Next up we retrieve the email from the pre entity images. This imlies that this is a pre-operation, synchronous plugin, and we need to add a pre-entity image when we register the plugin.

Next up we get the recipient from the "to" list. My code example does not take into account several recipients, it doesn't do any exception handling, and it's hard-coded for contacts. You'll have to make it work for your purpose on your own :)
The contact is retrieved from the system, and finally we do the following:
From the to recipient list, we update the "addressused" field on the first one, to the "emailaddress3" of the contact collected.
Next we update the entity back into the system, and continue the execution context.

That's all it takes, and some of your own logic of course.

A few thought on this solution before I wrap up:
It seems like a small, simple plugin for sending to alternate email addresses, but notice how we're hooking up to the "send" message for the email entity? That means that this plugin will trigger for all emails sent from the system. This doesn't need to have a large impact on your system, because there are a lot of optimizations in place in MSDYN365, but every line of code that has to execute causes a tiny bit of extra load on the system, and then multiply it by the number of emails sent from the system.

Wednesday, January 25, 2017

getEventArgs().getSaveMode() does not work for send email

getSaveMode() does not display the correct value

So I'm working on a customer who wants to perform some logic before sending an email. We used to hook onto the save event on the email form to perform this, but using global variables to store whether the user had been prompted earlier and doing several look ups made the form too slow.
PS: Please vote on ideas to change this https://ideas.dynamics.com/ideas/dynamics-crm/ID0000842

I looked into the details for the save event, and found this bit from the SDK which explains the different save modes used.

To get this object, all you need to do is check the box for "pass execution context as the first parameter" and you're good to go. The code I'm using includes something like this (don't worry, the actual code uses namespaces)

var performSaveActions = function(context) {
    if (context.getEventArgs().getSaveMode() === 7) {
        console.log("This never executes");
};

This looks OK, right? Well sadly it doesn't. Even though the SDK clearly states that when sending an email the getSaveMode() method should return 7, but it doesn't, it returns 1.

More specifically, when you hit the send button, the function executes 2 times, one time to save the content of the record, and one time before actually sending it. So I put a breakpoint in the code just to check the event arguments, and both of the times the breakpoint hits the getSaveMode() method returns 1, and never a 7.
So I tested for autosave, but that one actually returns 70, so that works as expected. I tried getting help from the different community channels, but it seems like this is a bug that hasn't gotten any attention yet.

So that's it really, if you're here looking for the same answer I was looking for then I'm afraid you're out of luck this time. What I ended up doing was hooking onto the normal save event (getSaveMode() === 1).

Also, I prevented autosave from triggering on the email form. There is a bug with autosave on the email form which can be quite annoying. If you've triggered a change on the email form and then start editing the email text field, when autosave triggers it will not include the text you've written since the dirty bit was triggered. Not only that, when the autosave is finished the text box will refresh and everything you've written will disappear.

So I implemented this snippet in the same method which stops autosave from happening (relax, this will present the user with a warning when leaving or refreshing the form if the changes haven't been saved):

if (context.getEventArgs().getSaveMode() === 70) {
    context.getEventArgs().preventDefault();
    return;
}

Monday, October 31, 2016

Microsoft CRM + Azure Service Bus, part 4 (two-way relaying and using Azure Event Hubs)

Integrating Microsoft Dynamics CRM with Microsoft Azure Service Bus, using queues, topics, relays and the Event Hub

In the previous posts we've looked at using endpoints in CRM, how we can create a simply workflow to push the Activity Context to the Azure Service Bus, using queues and creating a simple one-way listener. In this post we'll focus on extending the code to enable two-way relaying, which will allow us to return data back to CRM. We'll also look at how we can integrate CRM with Azure Event Hubs, a service based on ASB which allows for a lot of throughput.

Allow return value in the CRM Workflow step

The first thing we'll do is to write some more logic for our workflow, to enable us to use a return value. The relay service only returns a string, which means that we could easily push JSON or base64 through the bus to have even more meaningful feedback from the service. Be sure to remember the maximum message size for your service bus, and the timeout values. I do not recommend keeping a connection for a long time to transfer end-to-end data, but there are loads of scenarios where you'd like to get something back.

[Output("Return value")]
public OutArgument<string> ReturnValue { get; set; }
OK, so what we've done here is to add an output variable to our workflow step. This allows us to take the return value and use it inside our workflow in later steps.

protected override void Execute(CodeActivityContext executionContext
{
    var context = executionContext.GetExtension<IWorkflowContext>();
    var serviceEndpointNotifySvc = executionContext
        .GetExtension<
IServiceEndpointNotificationService>();
    
var result = serviceEndpointNotifySvc.Execute(
        ServiceEndpoint.Get(executionContext), context
    );

    ReturnValue.Set(executionContext, result);
}

The code looks mostly the same as it did in part2 of this series, with a couple of additions. Firstly, we assign the return value from the notification service's Execute method to a variable "result". Next we set the value of the new output variable "ReturnValue" to the result, using the execution context of the workflow.
Now just build and deploy the updated workflow, and we'll head into MSCRM. Navigate to the Settings -> Processes area, and open up the workflow created earlier. Deactivate the workflow to enable editing, and then add an update step after the custom workflow step.
I'm going to update the Description field on the Account to the ReturnValue from our custom workflow step.


Finally, go into the plugin registration tool to update the relay service we added in part3. Make sure it's changed to a two-way relay, and eventually update the name and path if you want that. Just make sure to update the same values inside the service.

Writing a two-way relay service

To enable two way communication we first have to change our service behavior class. We have to change the interface it inherits from and add a return value.

[ServiceBehavior]
public class RemoteService : ITwoWayServiceEndpointPlugin
{
    public string Execute(RemoteExecutionContext c)
    {
        Console.WriteLine(
            $"Entity: {c.PrimaryEntityName}, id: {c.PrimaryEntityId}");
        return "Message processed in two-way listener";
    }
}

As you can see we're now inheriting from the ITwoWayServiceEndpointPlugin interface, modified the Execute method to expect a return value, and we added a return statement after printing out to the console. This means that whenever our relay service is triggered it will print out the message as before, but will also return our magic string.

The only other change we have to make is to change the typeof implementation. Earlier we specified IServiceEndpointPlugin, so we have to change it to ITwoWayServiceEndpointPlugin. I've done a little dirty hack, because I've been changing back and forth between relay types while testing, so mine looks like this:
sh
    .AddServiceEndpoint(
        typeof(RemoteService).GetInterfaces().First(), 
        new WS2007HttpRelayBinding(), 
        AppSettings["SBusEndpoint"]
    ).Behaviors.Add(tcEndpointBehavior);
sh.Open();
Console.WriteLine("TwoWay-listener, press ENTER to close");
Console.ReadLine();

sh.Close();

While this may seem like reflection and a good idea, it will only work until you've built yourself a framework to reuse across different projects/customers, and all of a sudden you're implementing several interfaces and everything stops working. For this demo, it's OK, but I'd rather specify the interface type in production code.

Testing two-way relaying

Now that we've got that out of the way, it's time to test our new implementation. Start your new and improved service, and go to CRM and trigger the plugin. If everything goes as planned you'll be looking at the following window for your relay service

 And if we go into CRM and check out the description on our contact entity we'll see the following

So that's all it takes to have two-way communication working in a relay service. We've got CRM on one side, Azure Service Bus as the communication channel, and a simple console project on the other side.

What's a REST listener?

One option I haven't mentioned so far is the REST listener which can be specified in the plugin registration tool. This is simply a two-way relay which uses REST endpoints instead of .Net binaries. This would allow you to create and run a relay service in Node.js, apache tomcat, powershell, IIS, or whichever web server you'd want. Just to trigger all the popular buzwords, this can enable you to use MSCRM, Azure Service Bus, and deploy node.js relay services in docker containers.

Azure Event Hubs

Azure Event Hubs is a special kind of service bus which is designed to handle huge amounts of messages, we're talking millions of messages per second. It's probably not what you're looking at for general integration purposes, but there are several scenarios where it could benefit your company in a big way.
The first thing I thought of was using this for auditing. Just write a simple workflow or plugin which pushes any creates, updates and deletes as messages to the event hub. Then you can use stream analytics or some other technology to populate an auditing system with actions performed by your users and integration systems. Anyone who's used the out-of-the-box auditing functions in MSCRM knows that processing the information is tedious, at best, and more often than not close to impossible to get any useful data from. But if you start pushing it into an external auditing system based on Azure services then you could use clever stuff like temporal tables to design a robust, maintainable system.

The second thing I thought of was predictive analysis. Pushing raw data to the event hub, which allows for transfer to an Azure Data Warehouse for real-time data crunching and you have a great additional source of data that can be used for predictive analysis or (buzzword warning) machine learning.

There are probably a lot of cool things you can do with this, but I won't elaborate all my ideas in this blog post. What I want to stress is the price tag. It is incredibly cheap compared to legacy systems based on clusters of servers running different messages queues with some expensive bus technology on top. And the performance is great, no matter which size you pick. It doesn't matter if you're running hundres, thousands, or hundreds of millions of messages per day, the performance is always great but there's no entry level cost, the price scales with usage.


That's all for this blog series (at least for now). I might come back to visit later on when I've done some more in-the-field deployments with the ASB.

Sunday, October 30, 2016

Microsoft CRM + Azure Service Bus, part 3 (creating a relay service and endpoint)

Integrating Microsoft Dynamics CRM with Microsoft Azure Service Bus, using queues, topics, relays and the Event Hub

In this, third part of my blog series on using the Azure Service Bus capabilities I'm going to demonstrate how to set up a relay service and add the relay namespace as an endpoint in MSCRM.
Relaying allows us to have active listeners who can either just accept messages or accept and reply to them. This allows for business critical systems like ticket reservation and receipts to ensure we're working on updated and valid data.
Click here for part1
Click here for part2
Click here for part4

What is a relay service?

A relay service works by using the Service Bus like a kind of tunnel, in which the relay is an active listener at the other end. Unlike queues and topics, where the message is "dropped off", using a one-way or two-way (or REST) relay requires that somebody pick up the message immediately. With one-way the sender is happy as long as somebody accepts it, while in a two-way scenario the receiver has to return a value. In this post we'll start out with a one-way relay, but in the next one we'll look at how we can extend that into a two-way relay.

Creating a one-way relay

First off we write a service behavior class. This represents the code we're running whenever a message is received. I'm just going to write out something to the console.

[ServiceBehavior]
public class RemoteService : IServiceEndpointPlugin
{
    public void Execute(RemoteExecutionContext c)
    {
        Console.WriteLine(
            $"Entity: {c.PrimaryEntityName}, id: {c.PrimaryEntityId}");
    }
}

So nothing magical happening here. It's an extension of the IServiceEndpointPlugin, which writes the entity name and id to the console in it's execute method.
Next up we go to the main method and define a servicehost variable and a new endpoint behavior.

var sh = new ServiceHost(typeof(RemoteService));
var tcEndpointBehavior = new TransportClientEndpointBehavior(
    TokenProvider.CreateSharedAccessSignatureTokenProvider(
        AppSettings["SharedAccessKeyName"],
        AppSettings["SharedAccessKey"]
    )
);

OK, so here we've got ourselves a new servicehost variable, which we'll use to add a new service endpoint, with our newly created RemoteService service behavior as the type. Then there's the endpoint behavior. We create a new TransportClientEndpointBehavior, with a shared access signature as the token provider.
NB! In the SDK and the MSDN article this is specified as "Shared Secret Token Provider", but that's ACS and is no longer supported in Azure. You have to use Shared Access Signature (SAS) for authentication or it won't work.

sh
    .AddServiceEndpoint(
        typeof(IServiceEndpointPlugin), 
        new WS2007HttpRelayBinding(), 
        AppSettings["SBusEndpoint"]
    ).Behaviors.Add(tcEndpointBehavior);

Here we add a service endpoint to the host. The type is IServiceEndpointPlugin, which is what the CRM async service sends to the Service Bus. We use WS2007HttpRelayBinding to match the source system, and we collect the endpoint from the app.config (formatted like the following: https://yournamespace.servicebus.windows.net/yourpath/ ).
What's important to note here is that the path specified should not be the same as an existing path. If you have a queue or topic with the same path specified, it will be overridden and you cannot recreate it in the Azure Portal afterwards. This also means that it's up to you which path you want to use for the relay, which also means you can modify it dynamically using the web.config or in advanced integration scnearios.
Finally we add the endpoint behavior we created ealier.

sh.Open();
Console.WriteLine("OneWay-listener, press ENTER to close");
Console.ReadLine();
Close();

Finally, we open up the service host connection, which makes it start listening to new messages. This means we're ready to set up the service in the plugin manager and start sending messages.

Switching to relaying in MSCRM

First off we need to create a new shared access policy in Azure. It's the same as we did in part1, except that this time we create it on the bus itself instead of on a queue.
Then we head over to the plugin registration tool, connect to our organization and add a new service endpoint. This time it'll look kind of like this when it's filled in:
What's important to note here is the namespace address and path. The namespace address should be the complete path, and the path should just be a forward slash (the tool does not accept blank values). If you specify the path in the path box then it won't be able to find and connect to your relay service (that took me a while to figure out). In addition, this is an https endpoint, not an sb endpoint
Next up we go into CRM to edit our workflow (for more info see part2 of this blog series). The only thing we need to do here is deactivate and update the service endpoint. Then save and activate it again. I've kept the workflow running synchronously, just to be able to verify that it works as expected.
Now, just to demonstrate how it looks if you've specified the wrong endpoint, or if the relay isn't running, here's the error message you get. It is the same error you'll get if you specify the path in the path box instead of in the namespace box.

Now, for the fun part instead. Start your relay service and wait for the host to be ready. Then go into CRM and trigger the plugin. If you've done everything right then you'll see a command window looking something like this

And that means we've successfully posted a message from our MSCRM system, through our azure service bus and out of the relay service. This example isn't very exciting, but just think of the possibilities you get if you put this service out into Azure (or on a web server if you're still into that whole old school infrastructure stuff ;) ).

That's it for this blog post. In the next and (for now) final post in this series we'll look at how we can extend this into a two-way relay, as well as integrating with Azure Event Hub which is a service based on the ASB.

Wednesday, October 26, 2016

Microsoft CRM + Azure Service Bus, part 2 (creating a custom workflow and consuming service endpoints)

Integrating Microsoft Dynamics CRM with Microsoft Azure Service Bus, using queues, topics, relays and the Event Hub

In part two of this blog series we're going to look at how to create a custom workflow to post messages to the Azure Service Bus queue created in part1. I'm assuming that you have basic knowledge about the C# language and that you are familiar with the custom workflow step and plugin concepts in MSCRM.

Creating a workflow

First off, I have to give thanks to Jason Lattimer for all his contributions to all CRM developers and customizers everywhere. He has made available a free version of Dynamics CRM Developer Toolkit which makes building code and deploying stuff a breeze. Be sure thank him if you ever run into him.

[Input("ServiceEndpoint")]
[ReferenceTarget("serviceendpoint")]
[RequiredArgument]
public InArgument<EntityReference> ServiceEndpoint { get; set; }

First off I've just specified a simple input parameter for the workflow step. It takes an entityreference of type (logicalname) serviceendpoint, which is the type registered through the plugin registration tool.

protected override void Execute(CodeActivityContext executionContext
{
    var context = executionContext.GetExtension<IWorkflowContext>();
    var serviceEndpointNotifySvc = executionContext
        .GetExtension<
IServiceEndpointNotificationService>();
    serviceEndpointNotifySvc.Execute(

        ServiceEndpoint.Get(executionContext), context
    );
}

Next is the execution content of the workflow. As you can see there's no real magic here. I'm getting the workflow context and the service endpoint notification service from the codeactivitycontext. Then I use the Execute method of the notification service, which takes a service endpoint as an entity reference, and an ExecutionContext (here in the form of an IWorkflowContext) as input.
What the execute method does is posting the execution context to the provided service endpoint, which in turn means that the message received in the service bus queue contains a copy of the information contained in the execution context. This means you can add shared variables and images to supply additional information to whichever system will end up reading the message.
And that's it, you've got a working custom workflow step which can be built and uploaded to CRM.


Using workflows to send messages to ASB

The next step is to start using our new workflow step inside MSCRM. Just go into Settings -> Processes and hit New to create a new process. I like to start out with a synchronous one just to make sure that everything works, and then switch to background when I know it's OK. Even though you can run this step synchronously I wouldn't do it. The network latency alone is enough to make it a bad experience for users, so I would put much effort into using it as a background WF.

I've set the workflow to run on-demand, and then I add our custom workflow action as a step. On the properties-page, search for the service endpoint registered and add that as an input to the workflow step.

Now that we have configured a workflow, go ahead and save and activate it, and we're ready to start populating the ASB with messages.
I went ahead and triggered the workflow 5 times, and as you can see from my Azure portal there's messages ready to be processed.

Processing messages

Now that we have messages ready for processing we'll write a tiny application that allows us to read the messages posted. I've created a simple console-project in Visual Studio and added the CRM sdk through nuget (search for Microsoft.crmsdk)

var queue = MessagingFactory.CreateFromConnectionString(
    ConfigurationManager.AppSettings["ServiceBusPath"]);
var client = queue.CreateMessageReceiver(
    ConfigurationManager.AppSettings["EntityPath"], 
    ReceiveMode.PeekLock);
var message = client.Receive();
var context = message.GetBody<RemoteExecutionContext>();

The first thing I'm doing is creating a queue class using the ServiceBus sdk, and I've stored the connection string and queue path in the app settings. These strings are sensitive, so don't share them with anyone.
Next I'm instantiating up a new client class, using the queue connection and the entity path, and I've set the receive mode to PeekLock. This allows me to retrieve a message from the queue without deleting it, and then I can choose to delete (.Complete()) the message or return it to the queue (.Abandon()).
Then I use the receive method to get the next available (unlocked) message from the queue, and finally retrieve the message body. The message body is of type "RemoteExecutionContext", a Microsoft CRM SDK object which the notification service creates from the ICodeActivityContext.

If we put a breakpoint in our code we see that we have the familiar attributes available, like inputparameters, shared variables, parentexecutioncontext, primaryentityid, etc.
By utilizing the shared parameters we can add additional information in workflows or queues, which allows us to build complex logic in the queue listeners.

That's it for this post. In the next one we'll look into relaying with Azure Service Bus, which allows us to send replies back to MSCRM.

Sunday, October 23, 2016

Microsoft CRM + Azure Service Bus, part 1 (creating queues and adding service endpoints)

Integrating Microsoft Dynamics CRM with Microsoft Azure Service Bus, using queues, topics, relays and the Event Hub

Todays post is kind of a wrap up from the previous Oslo Dynamics 365 meetup which was held on October 17th. We'll look into the native support for Azure Service Bus (ASB) in MSCRM  and how we can use service endpoints inside our plugins and workflows. This post will focus on creating a bus, queue and access keys in Azure, and how to register the endpoint in MSCRM using the plugin registration tool.
Click here for part2

What is Azure Service Bus (ASB)

ASB is a service bus used for sending messages between different endpoints, which allows you to build and manage interconnected applications and systems without having to worry about the communication channel (within reasonable limits).
ASB supports several different destination types and communication protocols, and in this blog series I'll focus on the ones supported by Dynamics CRM.

Creating a queue and access key

The first step to adding an ASB endpoint in MSCRM is to create it and generate access policies. We'll start by logging into the Azure Portal and adding a new resource. Simply search for Service Bus and you'll find the following available

Fill in the required information to create the new resource, and hit the create button to start provisioning your brand new queue.
TIP: If you're using CRM Online, optimize performance in MSCRM by creating the bus in the same location as your tenant. This will minimize latency and will be very helpful in scenarios where you use Event hub for advanced auditing or similar high-ouput situations.

Now that we have a brand new service bus, it's time to add a queue to it. Navigate to Queues in the left hand navigation box and click on the [+ Queue] button. Give it a name and hit "Create" to get started.
Please note that the size option is the storage size of the queue, not the message size. In my tests the messages typically were between 13 and 60kB, so a 1GB queue would hold between 16k and 77k. Even if that seems much (after all, messages are deleted after processing), remember to plan for system downtime and SLA response times. if you generate a total of 20k messsages per day then you could be looking at data loss before gets a chance to take a look at it. I highly recommend you read up on queues and how to build a robust system using ASB aside from this blog post. I'm just presenting you with a simple way to get it working, not a complete integration strategy.
Now, open up your queue and navigate to Shared Access Policies. By default there won't be any policies in a new queue (there is one for the parent bus, I'll come back to that in the post about relaying), so click Add to create a new Shared Access Policy. Now you'll be asked to specify the claims added for this policy, which are "send", "listen" and "manage". Manage automatically gives the other two, but you could add a "send" access policy without "listen", and the other way around. The claims are pretty self-explanatory. Listening allows an application to read and complete messages, sending allows an application to send messages to the queue, and manage allows an application to make changes to the queue itself. I recommend a least-access-policy, ie. create seperate keys for systems that will listen and send messages, and don't overuse the keys across multiple systems. For demo purposes, using a full access key or a send&listen key is good enough.
Now you have a service bus, a queue, and an access key. You're ready to integrate MSCRM with Azure Service Bus.

Adding a service endpoint to MSCRM

To add a new service endpoint to MSCRM we have to use the plugin registration tool. You'll find it inside the MSCRM SDK under tools. Run the PluginRegistration.exe file and connect to your MSCRM organization. Once connected you'll have a new tab for your organization with a set of actions you can perform. Click on the register button, and then on the "register new service endpoint" option. You'll be presented with two options, either entering a connection string or starting with a blank connection window. I recommend pasting in the connection string from the azure portal, giving you a completely filled out connection settings window.

Message format

You have three different formats to choose from; .NETBinary, JSON and XML. This is simply the data representation of the message content. If you're planning to integrate with websites or other non-.NET technologies, or if you don't want to be dependent on the CRM SDK in your processor applications then you can simply choose one of the other message formats. Just keep in mind that XML can be quite bloated when it comes to size, so if you expect to send messages near the size limit then I would go for JSON (or even better, .NETBinary)

Take note that you can also choose to send the UserId as a parameter as well. This allows for additional authorization checks in your processing steps, and can be very useful to help determine who did what.
Now hit save, and you're done! A new service endpoint registered and you're ready to go.

In the next post in this series I'll demonstrate how to write a custom workflow step to use the service endpoints.


I also recommend to read up on the technologies. I'm just giving you a simple demo on how to actually do this, but there's a lot more to know and understand in order to plan and implement this successfully in your environment.

MSDN article on integrating Azure with CRM (NB: the samples for relay listeners are outdated as of 2016-10-23)

Thursday, February 4, 2016

Handling CRM 2016 organizations (and a tuning tip)

Handling organizations in MSCRM 2016

This post is about handling organizations in Dynamics CRM 2016 using the Deployment Manager tool and SQL Server Management studio. Just a heads up, this will be along one, but there's lots of pictures too.

What is an organization?

An organization is... well, an organization! You can think of it as an instance in your CRM deployment. Multiple organizations can exist in the same deployment of CRM services, but they are completely separated from each other. The benefit of having multiple organizations is mainly for enterprise size companies, who have large organizations with almost completely different needs in regard to customization and work methologies. When this is the case you can create multiple organizations with it's own set of customizations and web parts.
In addition, if you have multiple developer teams working on different things in your CRM environment then each team can get their own organization to deploy their changes in, and it doesn't require multiple servers with CRM and SQL Server, dozens of AD groups, etc.

An organization is actually just a SQL Server database, as we will see later in this post, and that is part of the reason why you are required to have unique organization names.

Organization overview and deployment administrators

To get an overview of your organizations you can simply open up the Deployment Manager from a CRM Server with the "Deployment Server" roles installed. One caveat is that you'll have to be added as a deployment administrator first, and you need login permissions on the SQL Server where the organization and configuration database is stored, and permissions to the MSCRM_CONFIG database. If you try to open the deployment manager without these permissions first then you'll get the following error message
To add new deployment administrators, log on with the user account used to install MSCRM, and open up the deployment manager tool. Navigate to "Deployment Administrators" and click on the "Add Deployment Administrator" link on the right hand side. Type in the name of the user you want to add, and click OK.


Now, to find your organizations simply navigate to "Organizations" on the left hand menu, and you'll get a list of all the connected organizations in your environment, both active and disabled (but not deleted, more on that in a little while). The overview lets you see the name (this is the unique name), display name, status, version and update availability of all your organizations.


You can also right click the organization to open up the properties for it

Adding organizations

Next let's step through the process of adding a new organization. From the organization overview simply hit the "New organization" link on the right hand side. This will give you the "New Organization Wizard", which collects the basic information needed to create a new organization.
Now, here are a few steps to complete, starting with display name and unique database name. Remember _MSCRM is appended to the unique database name, so it will look like this in SQL Server: myorganization_MSCRM. The display name is the name visible in the navigation bar beneath your name on the right hand side (depending on your screen resolution).

Next choose the base currency. Remember! None of the settings below "Unique Database Name" can be changed after the organization has been created. 
If you click the browse button and find your country from the list it will automatically fill in the currency code, name, symbol and precision.
Now, here's a pro tip: If you install additional language packs on the server then you're able to deploy multiple organization with different base languages. There are a lot of people who think that once the base language is chosen you have to uninstall to change it, but you really just have to deploy a new organization (which suddenly becomes a problem if you've already added tons of data to the old one, but lets hope you spot the mistake early on).
OK, last one out, the SQL Collation. Make sure you choose the same collation as the default one in your SQL Server. If you don't know which collation it has, ask your DBA. But just to be nice, here's how you do that yourself using tsql:
SELECT CONVERT (varchar, SERVERPROPERTY('collation'));

Next, select the SQL Server you want to store that databases on (it automatically fills in the same server as the MSCRM_CONFIG database is stored on), and the reporting URL. The slightly negative thing about the reporting URL is that it won't check which URLs the other environments use, it will just pick the SQL Server name and add HTTP:// to the front and /ReportServer at the back. So if you want to be sure you're using the correct SSRS server then you can copy that from the details about one of your other organizations (see the part about organization overview).
Please note that adding a new organization and importing existing organizations requires the SRS Data Connector to be installed beforehand. See my previous blog post for more information on installing this component.

Now, rock on through to the summary screen, and hopefully it will be one warning accompanied/succeeded by two green flags. The warning is for data encryption which will be activated, and that you should backup you encryption key.

Just a heads up, it is not unusual for the creation to take a long time during the "Microsoft.Crm.Tools.Admin.ImportDefaultDataAction" and similar screens. I've seen these take well over 30 minutes before so just get yourself a decent cup of coffee and come back later (or stare at it intensively, that's always fun)

When the creation is complete the new organization will be visible in the Organizations overview in the Deployment Manager



Deleting an organization

In this section we'll go through how to delete an organization. I'll show you some related topics along the way like editing the organization settings and the overview in SQL Server.

First off, to delete an organization you need to start with disabling it. Simply right click the organization from the overview in the Deployment Manager, and click disable. After you've done this, right click it again to delete it from the deployment. Please be aware that this does NOT delete the database, it simply removes it from the "organizations" table in the MSCRM_CONFIG, the database is still present and online in SQL Server. One thing you might notice when you've disabled the organization is that a new option is available; edit organization. This allows you to specify new values for an existing organization.


Importing an organization

This chapter explains how to import an organization. This typically happens when you want to clone your production environment into test or migrate from one server environment to another.
Start in the "Organizations" overview in Deployment Manager, and click the "Import organization" link on the right hand side.
This will bring up the "Import Organization Wizard", which automatically lists the organizations available for import on the SQL Server specified. Organizations that already exists in the deployment will not be listed.


Next you'll be able to edit both the display name and the unique database name. Editing the unique organization name does not actually edit the database name, it only edits the unique name stored in the database tables, which is appended to Internet Facing Deployment URLs.

Next specify the SSRS server URL you'll be using for this organization, and proceed to the next screen. Now, the installation will ask you for user mappings. This is for mapping the users in the organization to AD user accounts, and you can either choose automatic mappings or manual mappings. Automatic mapping is best when you're importing into the same active directory domain as it previously was. Manual mapping allows you to to specify all users manually, or create an import schema which you can edit in Excel.


I'll stick to automatic, because there's only one user in the organization.
To proceed with the import you have to map the current logged in user to a system administrator in the organization. If you try to continue without mapping this user you will be presented with the following error message

When this is done you'll be ready to import the organization, and you'll be presented with the familiar CRM process bar. Please note that if you've imported an older database, for example CRM 2015 or a previous update rollup, the database schema will be updated during import


And you're done! Organization imported and everything is (hopefully) nice and dandy. If you go into SQL Server you should be able to see that the databases are present, and the name of your organization has not been edited

Bonus round

Parallelism in SQL Server

A good tip I can't give often enough is the Max Degree of Parallelism (MAXDOP) setting in SQL Server. Some years ago in the "Best practices" documentation for CRM 2011 it was adviced to set MAXDOP to 1, meaning only one thread per SQL statement. This can cause horrible performance problems in CRM, because almost all queries rely on joins and filtering based on those joins, and that requires a lot of work if you can't execute it in parallel. Subsequently, this recommendation was removed, but the practice has continued with many consultants and IT Pros (this could also be because MAXDOP 1 is an actual best practice for Microsoft SharePoint).
So my tip: set MAXDOP to 0, and set threshold for parallelism to 4 or 1/4 of the number of processor cores on your SQL Server (whichever is higher). This is a generic recommendation, so do keep in mind that YMMV.

Developer resources in CRM

One of my favorite new things in the new CRM navigation is the improvements to the Developer Resources, available from Settings -> Customization

This new page gives you a lot of great information, starting with useful links for devlopers, the new WEP API available per instance, the organization id and the unique name, as well as the new discovery web api (and the old SOAP api, but SOAP is like, totally so 2009).



That's it for today, I hope you found this post useful.
Tomorrow I'll do a post on how to create an Office365 tenant and activate the CRM feature.
With the Deploying Microsoft Dynamics CRM Online exam it is increasingly important to know your way around the Office365 instance.
Until then, happy CRM-ing!