I use Erik Pool's implementation of ICodeWriterFilterService
and Manny Grewal's GenerateOption
function as a model to filter out unwanted entities in the file that CRMSvcUtil
generates. While Erik recommends returning true
for the GenerateOptionSet
method to generate enums
for option sets, doing so duplicates any of the global option sets that are used by any particular entity (as mentioned in one of the comments on that post).
To address this, I check to see if the option set has been already generated, and if so, I return the default option (presumably false
for most cases) as in the below.
//list of generated option sets, instantiated in the constructor
private List<string> GeneratedOptionSets;
public bool GenerateOptionSet
(OptionSetMetadataBase optionSetMetadata, IServiceProvider services)
{
if (!GeneratedOptionSets.Contains(optionSetMetadata.Name))
{
GeneratedOptionSets.Add(optionSetMetadata.Name);
return true;
}
return _defaultService.GenerateOptionSet(optionSetMetadata, services);
}
But when incorporating the generated file in my CRM projects, the compilation error
Cannot convert type 'Microsoft.Xrm.Sdk.OptionSetValue' to 'int'
is always thrown by every line of code that looks like
this.SetAttributeValue
("address1_shippingmethodcode", new Microsoft.Xrm.Sdk.OptionSetValue(((int)(value))));
.
As a workaround, I use a separate project where I filter the entities I need, run CRMSvcUtil
with the arguments Erik suggests, replace the troublesome part of the code (int)(value)
(where value
is an OptionSetValue
) with value.Value
after the file is generated, and then resave the file, and all issues go away.
My question is this: do I need to do something differently that will fix this compilation error with the default CRMSvcUtil
generated file without doing something so hackish as altering that generated file?
You can use the
ICustomizeCodeDomService
interface to rewrite theSetAttributeValue
method for the optionSets. Snippet below:}
It looks like there was a bug in the crmsrvcutil that has since been fixed. My code for OptionSet properties now looks like this:
And I get no error setting the OptionSetValue...
It turns out that this fault is to do with the code attempting to make optionsets that look like the code below when the types are available for use. Note the only difference is the correct type being chose for the return type and the cast.
It should be possible to update the codegen stuff to fix this bug, but it might be better to get microsoft to fix the damn thing properly, I would make a solution but I don't really have time to implement it right now because we have a mostly working solution even if we have to deal with the optionsetvalue class.
Some changes to the UpdateEnumSetter method:
I'm betting that Guarav's answer is the real way to go, but in the absence of documentation surrounding
CRMSvcUtil
, I'm forced to use my workaround. (I use a separate project where I filter the entities I need, runCRMSvcUtil
with the arguments Erik suggests, replace the troublesome part of the code(int)(value)
(wherevalue
is anOptionSetValue
) withvalue.Value
after the file is generated, and then resave the file.)Not a perfect solution, but it's been working on the few samples I've worked with so far.
I finally am able to generate early bound class with a filtered set of entities and error free option set. I found the bulk of my answer through this thread, so thanks guys. The problem though is it's difficult to compile all of the various suggestions into something that actually... compiles. So I thought I'd post my final solution for the benefit of others, here's what worked for me.
I used Erik Pool's, Manny Grewal's, and Peter Majeed's solution for outputting only distinct enums with proper values, then combined that with Gaurav Dalal's solution (updated by JFK007 to fix the cast error) to re-write the
SetAttributeValue
that caused the(int)(value)
error. And as an added bonus, I used the same solution for filtering distinct option sets to also filter for distinct option set values (which was an issue in my org).The result is a class library containing
CodeWriterFilter
andCustomizeCodeDomService
, the cmd batch file to runCrmSvcUtil.exe
, and thefilter.xml
to filter the entities.In your class library add references to
CrmSvcUtil.exe
,Microsoft.Xrm.Sdk
, andSystem.Runtime.Serialization
then compile the dll and copy it to the same the folder as yourCrmSvcUtil.exe
. Use the command I've included to reference your new assembly and build the early bound class file.CodeWriterFilter
:CustomizeCodeDomService
:CrmSvcUtil_run.cmd
Command Batch File:filter.xml