November 2010 - Posts
Finding out what information gets handed to you via the IPluginExecutionContext is not easy, most of the time you’ll hook up a remote debugger or write to a log file to find out which is tedious and time consuming to setup.

To help you, we’ve created an application that you can run on your desktop, point it at the crm server, select the messages, entities, stages and modes, click a button and start watching crm in real time.
Here’s an example

As you can see from the above screenshot, you don’t have to worry about decoding the parameters that are within the IPluginExecutionContext, we’ve done it all for you, if you find that some items aren’t getting decoded or you want to tweak the application, full source code is available at http://mspy.codeplex.com
Enjoy!
You have a workflow, you have 5000+ records, and you do an advanced find, it brings back the records only to find that you can run the workflow on a maximum on 250! (With unsupported customizations you can increase this limit but let’s stay out of that space for now)
If it’s a one off you can manually go through each page, run the workflow and move onto the next page, but if you have to perform this task everyday it becomes a nightmare. The good news is with a small ISV extension and a click of a button it’s done, magic!
To do this, we’ll be using the FetchXml form input that’s exposed when an advanced find query is run, once we have the FetchXml we simply create an instance of CrmService, execute the query and perform whatever action we like on the result set.
How to find the FetchXml form input

- Do an advanced find query on anything
- Open IE Developer Toolbar by pressing F12
- Use the Select Element By Click option highlight the advanced find result section
- Expand the form node and you’ll see the FetchXml
That’s great, how do we get access to this programmatically?
- Export the isv.config file
- Open it up and add the following xml
<Entities>
<Entity name=”account”>
<Grid>
<MenuBar>
<Buttons>
<Button … JavaScript="window.showModalDialog('/isv/magnetism/action.aspx', this, 'dialogHeight: 300px; dialogWidth: 300px;');”>
- Import and publish customizations
The reason we’re not using the out of the box Url attribute is because we want to reference the parent window from the child window (/isv/magnetism/action.aspx) so that we can access any element from our custom aspx page. To do that we pass ‘this’ as a parameter to the showMoalDialog methods’ dialogArguments input parameter.
Are we there yet?
The final step is to create the aspx page, grab the FetchXml then execute. The example below grabs the query (FetchXml) from the advanced find page and puts it into a textbox that you have full control over, therefor it can be accessed with server side code enabling you to do whatever you wish…
<%@ Page Language="cs" %>
<html>
<head runat="server">
<base target="_self" />
<meta http-equiv="Expires" content="-1">
<meta http-equiv="Pragma" content="no-cache">
</head>
<body>
<asp:TextBox ID="fetchxml" runat="server" />
<script type="text/javascript">
var o = window.dialogArguments;
document.getElementById("fetchxml").value =
o.parent.document.getElementById("FetchXml").value);
</script>
</body>
</html>
Since this is a modal dialog, couple of tips
- Use base target=”_self”, otherwise when you post back it’ll pop another window
- Force the browser not to cache the page
Enjoy!
Lately I’ve been hearing this word “It can’t be done” or “It’s not possible” all the time and it’s getting annoying, these words/phrases are poison to developers, especially young people who are just starting out their career, when all they hear is “can’t / not possible” it conditions them to think that way by default, it gets even worse when you get them in-front of customers and instead of thinking and coming up with a solution the default answer becomes “can’t” or “not possible”.
Let’s take a real word example using CRM 2011.
Today we were talking about field level security and couple of people said “It can’t be done for out of the box fields in CRM 2011”, “it’s not possible for out of the box fields”…this is simply not true, the Dynamics CRM team are a smart bunch of people that won’t hard code limitations like that, so to clear this up let’s open up SQL Management Studio and take a peek at the metadata.
Open up the MetadataSchema.Attribute table from *_MSCRM org database, filter on any attribute (eg: accountnumber)

By default the CanBeSecured* columns will be set to False, all you have to do is make these fields True, then you have the ability to enable/disable Field Security on the attribute.

So far so good, making progress…odds not looking good for the nay sayers…
The only other thing that’s left to do is to insert 2 rows into the FieldPermissionBase table, first row with ComponentState=2 and second row with ComponentState=0

| FieldPermissionIdUnique |
has to be a unique guid for both rows |
| ComponentState |
0 or 2 |
| SolutionId |
find the default solution or your solution id and use that guid |
| Can* |
4 |
| SupportingSolutionId |
empty guid |
| FieldSecurityProfileId |
grab one from the FieldSecurityProfileBase |
| EntityName |
mislabelled db column, it’s actually wanting the typecode of the entity, not the logical name |
| OverwriteTime |
set to 1900-01-01 |
| AttributeLogicalName |
logical name of the attribute |
And the result

There we have it! Field Level Security on out of the box attributes. Next time consider saying “I don’t know” instead of “can’t”.
The plugin registration tool is great when you want to quickly register, change and test plugins, but if you have an automatic build/testing environment you need some way to creating a new CRM organisation, importing customizations, register custom plugins/workflows and run your tests.
Below you’ll find some handy snippets of code that you can use to register plugins programmatically.
Request & Response
string assemblyPath = @".\blah.dll";
RegisterSolutionRequest request = new RegisterSolutionRequest
{
PluginAssembly = GetPluginAssembly(assemblyPath),
Steps = GetSteps()
};
RegisterSolutionResponse response = sdk.Execute(request) as RegisterSolutionResponse;
Guid solutionId = response.PluginAssemblyId;
solutionId is useful when you want to unregister the solution.
GetPluginAssembly Method
It’s recommended that you store the plugin it the database, one of the main reasons is if you have multiple front-ends you don’t have to copy the plugin to disk or GAC, CRM will automatically load and execute. The plugin content is stored as base64 therefor we have to read all the bytes from the dll and convert to base64.
Assembly assembly = Assembly.LoadFile(assemblyPath);
string[] prop = assembly.GetName().FullName.Split(",= ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
pluginassembly asm = new pluginassembly
{
name = prop[0],
culture = prop[4],
version = prop[2],
publickeytoken = prop[6],
sourcetype = new Picklist(AssemblySourceType.Database),
content = Convert.ToBase64String(File.ReadAllBytes(assemblyPath))
};
GetSteps Method
Sample code below shows how you can create a single step, to register multiple steps, create an array, store each step inside the array and assign to the Steps property of the RegisterSolutionRequest.
var step1 = new SdkMessageProcessingStepRegistration
{
CustomConfiguration = "",
Description = "Example Post Create",
FilteringAttributes = "", // all attributes
Mode = 1, // async
MessageName = "Create",
PrimaryEntityName = "mag_example",
Stage = 50, // post
SupportedDeployment = 0,
PluginTypeName = "Xyz.Abc.ExamplePlugin",
PluginTypeFriendlyName = "Abc - Example",
InvocationSource = 0 // parent pipe
};
PluginTypeName is the namespace.classname of the plugin, PluginTypeFriendlyName is what’s displayed in the plugin registration tool, if you have multiple steps on the sample class make sure to keep the PluginTypeFriendlyName the same so it’s grouped nicely in the registration tool.
More Posts