Total Pageviews

Thursday, 21 April 2016

Generate Early Bound Class for specific entities

Generate Early Bound Class for specific entities:

As a crm developer we need to write plug-in, workflows, console application for migration purpose. Writing the code is not a matter but while executing the code we may get some field miss spelling issues or before writing the code we need to waste our time to get the details of fields in order to work properly . These things may waste the time . To save the time MS team has given the feature to generate the ear ly bound classes for each entity.

Using these early bound classes we may not get the error’s like misspelling field names and also it provides the intelligence.

But while generating early bound classes crm will generate all the classes for all entities , it may cause increase the class file size.

To overcome this i am goanna show you how to generate the early bound classes only for specific entities.

Step 1: 

Create one Class Library project and add CrmSvcUtil.exe(which will find in Crm Sdk) as References.

Step 2: 

Add the below class to the project which you created recently.

using System;
using System.Collections.Generic;
using System.Xml.Linq;
using Microsoft.Crm.Services.Utility;
using Microsoft.Xrm.Sdk.Metadata;

namespace GenerateSpecificEntityClasses
{
    public class CodeWriterFilter : ICodeWriterFilterService
    {
        //list of entity names to generate classes for.
        private HashSet<string> _validEntities = new HashSet<string>();

        //reference to the default service.
        private ICodeWriterFilterService _defaultService = null;

        /// <summary>
        /// constructor
        /// </summary>
        /// <param name="defaultService">default implementation</param>
        public CodeWriterFilter(ICodeWriterFilterService defaultService)
        {
            this._defaultService = defaultService;
            LoadFilterData();
        }

        /// <summary>
        /// loads the entity filter data from the filter.xml file
        /// </summary>
        private void LoadFilterData()
        {
            XElement xml = XElement.Load("filter.xml");
            XElement entitiesElement = xml.Element("entities");
            foreach (XElement entityElement in entitiesElement.Elements("entity"))
            {
                _validEntities.Add(entityElement.Value.ToLowerInvariant());
            }
        }

        /// <summary>
        /// /Use filter entity list to determine if the entity class should be generated.
        /// </summary>
        public bool GenerateEntity(EntityMetadata entityMetadata, IServiceProvider services)
        {
            return (_validEntities.Contains(entityMetadata.LogicalName.ToLowerInvariant()));
        }

        //All other methods just use default implementation:

        public bool GenerateAttribute(AttributeMetadata attributeMetadata, IServiceProvider services)
        {
            return _defaultService.GenerateAttribute(attributeMetadata, services);
        }

        public bool GenerateOption(OptionMetadata optionMetadata, IServiceProvider services)
        {
            return _defaultService.GenerateOption(optionMetadata, services);
        }

        public bool GenerateOptionSet(OptionSetMetadataBase optionSetMetadata, IServiceProvider services)
        {
            return _defaultService.GenerateOptionSet(optionSetMetadata, services);
        }

        public bool GenerateRelationship(RelationshipMetadataBase relationshipMetadata, EntityMetadata otherEntityMetadata, IServiceProvider services)
        {
            return _defaultService.GenerateRelationship(relationshipMetadata, otherEntityMetadata, services);
        }

        public bool GenerateServiceContext(IServiceProvider services)
        {
            return _defaultService.GenerateServiceContext(services);
        }
    }
}

Step 3:
For now I just want to be able to determine which entities are generated, so in the constructor I read from an XML file (filter.xml) that holds the list of entities to generate and put the list in a Hashset.  The format of the xml is this:

<filter>
  <entities>
    <entity>systemuser</entity>
    <entity>team</entity>
    <entity>role</entity>
    <entity>businessunit</entity>
  </entities>
</filter>
Note:create xml file and give the name what ever you wish . but that name should pass in above method LoadFilterData()  
In above Xml file i just given four entities you can include as many entities as you want.

Take a look at the methods in the class. In the GenerateEntity method, we can simply check the EntityMetadata parameter against our list of valid entities and return true if it's an entity that we want to generate.

For all of the other methods we want to just do whatever the default implementation of the utility is.  Notice how the constructor of the class accepts a defaultService parameter.  We can just save a reference to this default service and use it whenever we want to stick with the default behavior.  All of the other methods in the class just call the default service.

To use our extension when running the utility, we just have to make sure the compiled DLL and the filter.xml file are in the same folder as CrmSvcUtil.exe, and set the /codewriterfilter command-line argument when running the utility (as described in the 
SDK):
Step 4:
Now we have class library project and xml file . All we have to do is build the project and copy the xml file and paste it in bin folder of project which we compiled now.
Step 5:
Now we need to run the CrmSvcUtil.exe as
Open command prompt and change the directory to the class project library bin->debug folder and execte the command as like :
CrmSvcUtil.exe  /url:<Url>    /out:<OutputFileName>.cs /username:<UserName> /password:<password> /namespace:<Nampespace> /serviceContextName:<servicecontext> /codewriterfilter:<ClasslibraryProjectNameSpace>.<ClassName>,<ClasslibraryProjectNameSpace>

That’s all we have to generate the early bound classes .



No comments:

Post a Comment