0
votes

I am experiencing an error in CRM workflows which run custom activities which reference common assembly from GAC, but different versions. The situation is as following:

Assembly A and assembly B (both custom activities) reference assembly C which contain a base class (inheriting from CodeActivity) for A and B as well as crmsvcutil generated class. Assembly C exists in GAC with multiple versions. Now, I created a new attribute in CRM, regenerated early types with crmsvcutil, updated the version of assembly C to 1.0.0.3 and put it into GAC, rebuilt assembly B (which uses the new attribute) and updated it using plugin registration tool.

The error shows up in workflows which reference both assembly A and B with an error message that "assembly.type" cannot be converted to "assembly.type". In base class (assembly C) we set an assembly property to be able to work with strong types:

IOrganizationServiceFactory serviceFactory = executionContext.GetExtension<IOrganizationServiceFactory>();
var type = Type.GetType("Microsoft.Crm.Workflow.SynchronousRuntime.WorkflowContext, Microsoft.Crm.Workflow, Version=5.0.0.0");
type.GetProperty("ProxyTypesAssembly").SetValue(serviceFactory, typeof(XrmServiceContext).Assembly, null);
IOrganizationService service = serviceFactory.CreateOrganizationService(context.UserId);

It seems to me that CRM caches the base class together with proxy types and tries to use it on assembly B, despite that it references new version of C. If I create a workflow with just activity from assembly B, it works fine, it is only if the assembly A is referenced in same WF and before B.

This is a problem now in production environment and I am trying to find a fix for it. I know I can update assembly A to use new version of C and I did it in test environment, but since there are a lot of more assemblies then two, many tests must be performed.

  1. Can I somehow point updated assembly B to an older version of C(and use indexer with attribute name for new attribute)? I tried reverting assembly version of C to 1.0.0.2, compiling again B, but then I get an error that assembly cannot be updated in plugin registration tool.
  2. Can someone explain how and where does an assembly keep version of a referenced assembly. How does this work in .NET in general?

The strangest thing is that I tried to copy the base class and early types class into the assembly B (in it's own namespace), completely remove the reference to assembly C, updated in plugin registry tool and I got exactly the same error, this time that "AssemblyC.type" cannot be converted to "AssemblyB.type". I don't understand how when I completely removed reference to assembly C.

Any suggestion is appreciated, thanks in advance.

EDIT: I have just found out that this relates only to dialogs. It works fine with workflows. Does that ring any bell?

1

1 Answers

0
votes

Several ideas.

For me it looks like that early-bound assemblies sometimes create more problems, than helps to solve. And main issue here is lack of transparency. Everything is done behind the scene implicitly. User have no any control on this.

I've noticed that CRM automatically resolves early-bound assemblies within one AppDomain. This basically means, that if you have two assemblies that uses different version of same early-bound assembly, the assembly that loaded first, will drag its early-bound assembly into AppDomain and all further plugins, CWAs will be forced to use that previously loaded early-bound assembly.

How to fix? If these Custom Workflow Activities are used in different workflows — try to register assemblies in isolation. I haven't tried that scenario, but if these workflows won't share same AppDomain early-bound types will not be messed up.

Another approach: try to bundle all you early-bound assemblies with your CWA. Could result to abnormally huge files, but most likely will solve your problem (and you also can remove unused definitions from early-bound assembly to make it slimmer).

One more idea: check this link. Here in XrmToolBox we're trying to find solution for that problem. Basically, there is a way to manually cast late-bound assemblies to selected early-bound.

XrmToolBox also contains this proposal, that allows to specify directly which assembly to use.