Default Solution and Publisher Ids

In writing my last post on Creating your own Dynamics Publisher, I stumbled across the below information on the default solution and publisher Ids within Dynamics.

Both, the default solution and publisher are the same Guids across all Dynamics environments.

DefaultPublisherId  – {d21aab71-79e7-11dd-8874-00188b01e34f}

Furthermore, you can access the Default Solution Id (consistent across all environments).

DefaultSolutionId – {FD140AAF-4DF4-11DD-BD17-0019B9312238}

I did a quick validation between an on-premise CRM 2015 tenant and my online Dynamics instance and both lined up.

Reference: https://msdn.microsoft.com/en-us/library/gg328257.aspx

Understanding Publishers with Dynamics

A Publisher in Dynamics is the entity by which your solutions are deployed to Dynamics CRM.

No publisher means no solution being deployed.

In any Dynamics install, there is always a Default Publisher which you can use across your solutions (if you like) but exists as the publisher for customizations made to the base system.

Creating a publisher can be accomplished by simply going to Settings >> Customizations >> Publishers and creating your own publisher.

But that’s pretty boring, so we’re going to create one using code.

Creating your Publisher

Once you initialized a connection to Dynamics, put together a little console app and use the following code to create your own Publisher that can be used for deploying your own solutions.

 Entity crmPublisher = new Entity("publisher");
 crmPublisher["uniquename"] = "ForgottenCoder";
 crmPublisher["friendlyname"] = "Forgotten Coder";
 crmPublisher["supportingwebsiteurl"] = "www.forgottencoder.com";
 crmPublisher["customizationprefix"] = "fgc";
 crmPublisher["emailaddress"] = "emailaddress@emailme.com";
 crmPublisher["description"] = "This publisher is used to create all customizations by Forgotten Coder.";
 crmPublisher["customizationoptionvalueprefix"] = Convert.ToInt32("59999");

PublisherId = CrmService.Create(crmPublisher);

(Where CrmService is the IOrganizationService reference to my connection object.)

Run your code and you should have a newly created Publisher in Dynamics.

1_Publisher.PNG

Some Publisher Specifics

Some important to pieces to understand with publishers (as they pertain to your solutions), the prefix is very important as all objects created within your solution will be prefixed with this prefix.  Also, the Option Value Prefix indicates what number your option set will start from.

2_publisher.PNG

It’s important to note that Publishers and Solutions are not 1-to-1, you can have one publisher deploy many solutions but a solution can only have one publisher.

Searching for your Publisher

If you want to get fancy, you can do a lookup on startup of your application to see if your publisher exists and if so, go grab it’s PublisherId (you’re going to need it for your solution deployment) and store it in memory before deploying your solution.

QueryExpression pubQuery = new QueryExpression
 {
 EntityName = "publisher",
 ColumnSet = new ColumnSet("publisherid"),
 Criteria = new FilterExpression()
 };

pubQuery.Criteria.AddCondition("uniquename", ConditionOperator.Equal, "ForgottenCoder");
 EntityCollection results = CrmService.RetrieveMultiple(pubQuery);

3_publisher

Note: The above code snippet was modified from the Microsoft sample “Solutions” project shipped with the Dynamics SDK.

Retrieving Email Addresses in Outlook

Sometimes it seems that what we thought was the easiest problem to solve actually turns out taking the longest amount of time to figure out.

Case in point – finding the email address of the currently logged in user running Outlook in a VSTO plugin.

If you are looking to do this, see below and let the code set you free.

Recipient CurrentUser = this.Application.Session.CurrentUser;

CurrentUser.AddressEntry.GetExchangeUser().PrimarySmtpAddress.ToString()

A little longer and less direct than I would have thought (i.e., at this stage, my user is not a recipient to anything) but the reasoning becomes a little more apparent if I am trying to find the email addresses on a set of recipients on either an appointment or mail message.

.Recipients[1].AddressEntry.GetExchangeUser().PrimarySmtpAddress.ToString()

A Scaled out CRM Solution Architecture

Recently I started work on a pretty big CRM project and I wanted to apply a more scaled out approach to my solution architecture.  CRM offers a great facility to deploy code in their solutions but when starting a new project you should always ask yourself the following questions before you starting adding entities into your solutions.

  1. What is the frequency of updates that will be requested by the users and to what components?
  2. Are there multiple users contributing to this project?
  3. How big do you expect this project to grow by?
  4. What kind of promotional model is in place for deployments?

I  have found that questions such as these generally drive the overall solution architecture I will put in place on a project.  For instance, if we are working with a client that has a Development to Production promotion model with only a developer or two on the project, I’ll suggest deploying as one solution.  However, if the project is quite large, has multiple developers on it coupled with multiple deployment stages (which invariably means a more formalized testing process) I’ll tend to go with a more scaled out architecture.

For this current project I went with a component based solution architecture broken out as follows;

  1. Entities – this contains all my core entities, client extensions and web resources.
  2. Security – this contains all my security roles.
  3. Reports – this contains all my custom reporting files.
  4. Workflows – this contains all custom workflows and plugin functionality.

The reason for this approach is to reduce the load on QA and allow the team to install what they need without fear of interfering with the work of others.

sol

Some scenario examples where this should help the team;

  1. When a developer makes a change to only 1 of the solutions, QA can rest easy deploying that single solution (instead of all 4) and not having to regression test all 4 but only 1 solution.
  2. Reports will most likely be handled by developers that are very familiar with developing custom RDL files, as such, they don’t need references to any of the underlying entities and based on user feedback, they will be able to deploy on their own schedule, outside of the core application.
  3. Having security in it’s own solution now opens this up to being managed by non-developer groups (huge).  Although I don’t recommend deploying an unmanaged solution to Production, this solution can actually start it’s “development” or “work” in a TEST or UAT where Business Analysts can create the security roles they think make sense against the new components built by the developer teams without worrying about interfering with any previous development to date.

These are only a few scenarios where I see this architecture helping out in the long-run.  I have gone through a couple of iterations of scaled out architectures from feature to product based but so far this one represents a consistent approach that can be replicated across projects.

My next step will be to minimize any complexity associated with deploying updates to different environments by writing a little component to deploy the correct solution in the correct order.  However as it stands right now, the solutions themselves are quite loosely coupled and can be deployed without error (i.e., reports) without triggering a solution import error.

Creating a New area in CRM 2015 – By Hand

Emphasis on the “By Hand”.  I’d previously blogged about how to modify the Site Map in Dynamics365 with some of the new  ribbon editing features very reminiscent of Ribbon Bench (here for reference Site Maps and Custom Entities – Oh My!) – but recently had the pleasure of having to do this in 2015, with no tools.

The modification of the XML customizations.xml file itself wasn’t too bad on it’s own, where things really became complicated was when I wanted to add an image to my area.

Modifying the Customizations.xml File

To create your new Groups and Areas – check out this post that does a great job of walking you through how to export, modify and import the XML file (along with screenshots).

Adding an Image to your Area

Now where things went off the handle was when I wanted to add an image to my new area.  In order to do this correctly, you need to ensure that the following values all line up exactly including the case and extension.  After banging my head against the wall I noticed that my URL for my web resource did not necessarily have the same display name and some of what it was mixed case.  So I deleted the image, re-uploaded and made sure that all three fields highlighted below.

ImageEdit.PNG

Lined up with the name being entered here.

ImageEdit2.PNG

After I did this, my solution was again able to import without issue and the image was now being consumed.  Let CRM add in your publisher information, no need to modify that.  After having figured this out, I was able to go back and update the image without issue.

Hopefully this saves you some time.

Creating a custom Tab in VSTO

If you haven’t used VSTO, it’s the framework for developing Office Integrations.  Yes, people are still developing Office plugins, although Flow is coming on strong, there is still a need for organizations to have components directly embedded in their primary applications of choice.

If you’re looking to get started on building your own Tab in Office you can do this very easily by adding a Ribbon.xml file to your VSTO project with the following syntax.

<?xml version="1.0" encoding="UTF-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui" onLoad="Ribbon_Load">
 <ribbon>
 <tabs>
 <!--<tab idMso="TabMail">-->
 <tab id="tabForgotten" label="Coder">
 <group id="MyGroup" label="Content">
 <button id="btnGo" label="Connect" 
 screentip="Go" onAction="OnConnectClicked"
 supertip="Go to start."/>
 </group>
 </tab>
 </tabs>
 </ribbon>
</customUI>

Once you’ve added that snippet, simply navigate back to your main AddIn.cs file and instantiate your ribbon.

protected override Microsoft.Office.Core.IRibbonExtensibility CreateRibbonExtensibilityObject()
{
return new SuperRibbon();
}

Compile and run (in this example, I created an Outlook VSTO plugin) and you can now see your new menu item.

Capture

Connecting the events are even easier as a complimentary .cs file is created where you can easily wire up this event.

public void OnConnectClicked(Office.IRibbonControl control)
{

System.Diagnostics.Debug.WriteLine("HERE");
}

Lastly, you’ll notice that in my XML tab declaration there is a value that is commented out called TabMail.  All built-in Tabs have their own tabs that you can piggy back off to include your controls therein instead of creating your own tab as was done previously.  All that needs to change is that value.