Thursday, March 22, 2012

Extending CrmSvcUtil (Filtering the generated classes)

Most people use the CrmSvcUtil  in its native form. But CrmSvcUtil exposes some interfaces to extend its functionality. Here is the list of all the extension interfaces. One of my personal favourite is ICodeWriterFilterService. This interface can control which entity/attribute/relationship etc. would be created by CrmSvcUtil. By default, CrmSvcUtil generates all the entities, attributes and relationships. If you run the CrmSvcUtil for an out of box CRM online organization, it will generate a file of around 5 mb with all the entities and attributes. In reality we need to generate very few entities for our solutions. We do not need all the extra code generated by the utility. The size of the file is even more important when we are writing code for CRM online. In this blog, we are going to learn how to filter the entities generated by the code generation utility.
Here are the steps:
  1. Open up the solution we created in our last blog.
  2. Add a new class file to the project. I named my class file BasicFilteringService.cs. I copied this file from the sdk samples. Here is the code. The code will restrict the code generation utility to generate just the custom entities.
    using System;
    using Microsoft.Crm.Services.Utility;
    using Microsoft.Xrm.Sdk.Metadata;
    namespace CRMExtensions
    {
        /// 
        /// Sample extension for the CrmSvcUtil.exe tool that generates early-bound
        /// classes for custom entities.
        /// 
        public sealed class BasicFilteringService : ICodeWriterFilterService
        {
            public BasicFilteringService(ICodeWriterFilterService defaultService)
            {
                this.DefaultService = defaultService;
            }
    
            private ICodeWriterFilterService DefaultService { get; set; }
    
            bool ICodeWriterFilterService.GenerateAttribute(AttributeMetadata attributeMetadata, IServiceProvider services)
            {
                return this.DefaultService.GenerateAttribute(attributeMetadata, services);
            }
    
            bool ICodeWriterFilterService.GenerateEntity(EntityMetadata entityMetadata, IServiceProvider services)
            {
                if (!entityMetadata.IsCustomEntity.GetValueOrDefault()) { return false; }
                
                return this.DefaultService.GenerateEntity(entityMetadata, services);
            }
    
            bool ICodeWriterFilterService.GenerateOption(OptionMetadata optionMetadata, IServiceProvider services)
            {
                return this.DefaultService.GenerateOption(optionMetadata, services);
            }
    
            bool ICodeWriterFilterService.GenerateOptionSet(OptionSetMetadataBase optionSetMetadata, IServiceProvider services)
            {
                return this.DefaultService.GenerateOptionSet(optionSetMetadata, services);
            }
    
            bool ICodeWriterFilterService.GenerateRelationship(RelationshipMetadataBase relationshipMetadata, EntityMetadata otherEntityMetadata,
            IServiceProvider services)
            {
                return this.DefaultService.GenerateRelationship(relationshipMetadata, otherEntityMetadata, services);
            }
    
            bool ICodeWriterFilterService.GenerateServiceContext(IServiceProvider services)
            {
                return this.DefaultService.GenerateServiceContext(services);
            }
        }
        //
    }
    
  3. Add codewriterfilter parameter to CrmSvcUtil.exe.config file. <add key="codewriterfilter" value="CRMExtensions.BasicFilteringService, CRMExtensions"/>
  4. Press F5 to debug the solution. It will generate a file  with the name specified in “o” or output parameter.
  5. Check the size of the file. It will be very very small as compare to the file generated without codewriterfilter. The size of the file created for default CRM online  organization with codewriterfilter is just 44 kb as compared to 4.7 mb without codewriterfilter.
Note if we replace the following line in BasicFilteringService.cs
if (!entityMetadata.IsCustomEntity.GetValueOrDefault()) { return false; }
with
if (entityMetadata.LogicalName!="account") { return false; }
The utility will generate just account entity. Happy programming.

8 comments:

  1. Brilliant, thanks for the tip Amreek.

    ReplyDelete
  2. Thanks for the feedback buddy.

    ReplyDelete
  3. really helped me! thanks

    ReplyDelete
  4. Really nice. Thanks Amreek. Do you know if this works on the crmsrvutil in 4.0?

    ReplyDelete
  5. Try this tool (https://xrmearlyboundgenerator.codeplex.com/)! It will also limit which Entities are generated, as well as a whole list of other features.

    ReplyDelete