Pages

Tuesday, January 25, 2011

CrmSvcUtil generates classes that are not compilable and workaround

CrmSvcUtil is a code generator that generates code for the Early-Bound classes in Dynamics CRM 2011.

Depending on the customizations in your system in can happen, that it generates two properties that have the same name. This is the case, when you have a relationship and an attribute in the customization that have the same name.

While I consider it not to be a best practice to have the same name in the relationship and the attribute sometimes you just have to live with existing customizations.

First thing to do was to file a bug with Microsoft. While they also consider that to be a problem in the current version of the CrmSvcUtil, they also said, that this will not be fixed in RTM.

So, time for a workaround:

The CrmSvcUtil allows replace or extend some parts of the code generation, giving you also a point to where you can fix this problem.

Documentation for this is not very detailed in the Sdk so here is they way to do that.

  • Create a C# class library project and add the CrmSvcUtil.exe as reference
  • Add a class that implements INamingService (this class can be found in the CrmSvcUtil reference
  • Add a constructor that takes an INamingService as parameter, the CrmSvcUtil than injects the DefaultNamingService, which allows you to extend that functionality
  • Delegate the implementation of the INamingService interface to the DefaultNamingService, only extend the implementation of GetNameForRelationship
  • Create a CrmSvcUtil.exe.config and configure your implementation as NamingService

I implemented my NamingService this way:

using System;
using Microsoft.Crm.Services.Utility;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Metadata;

namespace Ksection.MsCrm.XrmTools.CrmSvcUtil
{
public class NamingService : INamingService
{
private readonly INamingService _defaultNamingService;

public string GetNameForOptionSet(EntityMetadata entityMetadata, OptionSetMetadataBase optionSetMetadata, IServiceProvider services)
{
return _defaultNamingService.GetNameForOptionSet(entityMetadata, optionSetMetadata, services);
}

public string GetNameForOption(OptionSetMetadataBase optionSetMetadata, OptionMetadata optionMetadata, IServiceProvider services)
{
return _defaultNamingService.GetNameForOption(optionSetMetadata, optionMetadata, services);
}

public string GetNameForEntity(EntityMetadata entityMetadata, IServiceProvider services)
{
return _defaultNamingService.GetNameForEntity(entityMetadata, services);
}

public string GetNameForAttribute(EntityMetadata entityMetadata, AttributeMetadata attributeMetadata, IServiceProvider services)
{
return _defaultNamingService.GetNameForAttribute(entityMetadata, attributeMetadata, services);
}

public string GetNameForRelationship(EntityMetadata entityMetadata, RelationshipMetadataBase relationshipMetadata, EntityRole? reflexiveRole, IServiceProvider services)
{
return _defaultNamingService.GetNameForRelationship(entityMetadata, relationshipMetadata, reflexiveRole, services) + "Relationship";
}

public string GetNameForServiceContext(IServiceProvider services)
{
return _defaultNamingService.GetNameForServiceContext(services);
}

public string GetNameForEntitySet(EntityMetadata entityMetadata, IServiceProvider services)
{
return _defaultNamingService.GetNameForEntitySet(entityMetadata, services);
}

public string GetNameForMessagePair(SdkMessagePair messagePair, IServiceProvider services)
{
return _defaultNamingService.GetNameForMessagePair(messagePair, services);
}

public string GetNameForRequestField(SdkMessageRequest request, SdkMessageRequestField requestField, IServiceProvider services)
{
return _defaultNamingService.GetNameForRequestField(request, requestField, services);
}

public string GetNameForResponseField(SdkMessageResponse response, SdkMessageResponseField responseField, IServiceProvider services)
{
return _defaultNamingService.GetNameForResponseField(response, responseField, services);
}

public NamingService(INamingService defaultService)
{
_defaultNamingService = defaultService;
}


}
}


Und die passende CrmSvcUtil.exe.config:


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="namingservice" value="Ksection.MsCrm.XrmTools.CrmSvcUtil.NamingService, Ksection.MsCrm.XrmTools.CrmSvcUtil"/>
</appSettings>
</configuration>


This implementation just adds Relationship as postfix to each relationship, therefore avoiding the problem.

No comments:

Post a Comment