{"content":"As a Power Platform developer, I have always been a strong advocate for the use of early-bound classes in customization projects that targets Dataverse tables and actions. Early-bound classes not only increase code readability and maintainability, they also significantly reduce the risk of errors. I think that being proficient and fast in generating early-bound classes is a must-have skill for any developers who works with the platform.\nRecently, the Microsoft Power Platform CLI ( PAC CLI) introduced the new modelbuilder command group that enables early bound classes generation directly from the CLI. Traditionally the generation of early-bound classes was primarily accomplished through a specialized tool called CrmSvcUtil. Yet, integrating these capabilities into a more versatile and widespread tool like PAC CLI is a logical step forward that will undoubtedly improve user adoption in the long run.\nThis post takes a closer look at the PAC CLI modelbuilder, delving into its inner workings and examining some of the key command group switches and their impact on the resulting classes. Additionally, we\u0026rsquo;ll explore how to effectively generate these classes on the fly within a Dataverse plugin project.\nBut first, let\u0026rsquo;s recap on the early-bound classes concept.\nEarly bound classes In Dataverse, early-bound classes are used to provide a strongly-typed representation of the Dataverse tables (entities), columns (attributes) and choices (optionsets) in .NET languages, such as C# and VB.NET.\nTypically, a code generation tool establishes a connection to the target Dataverse organization and inspects the metadata to create a collection of classes that represents each entity and its attributes as a corresponding property within that class.\nBy using early-bound classes, developers can write code that references Dataverse entities and their attributes using strongly-typed objects, rather than using string literals ( a.k.a. magic strings). This makes the code more readable, maintainable, and less error-prone.\nFurthermore, early-bound classes provide compile-time type checking, which helps to detect errors early in the development process, rather than catching them at runtime. They also provide intellisense, making it easier for developers to discover and use available entities and attributes.\nAs an example, the following screenshots compares early-bound vs late-bound coding style. You can appreciate the difference in style and readibility. I personally find the late-bound notation hard to understand.\nPAC CLI modelbuilder That being said, let\u0026rsquo;s explore the new modelbuilder command group of the PAC CLI to produce these early-bound classes.\nPre-requisites There are some prerequisite to use the PAC CLI, the first one is to have it installed on your computer. You can find the official docs here, but the easiest way is to install it through the Power Platform Tools Visual Studio Code extension. This will install the CLI globally on your machine and you\u0026rsquo;ll be able to use it from any command prompts.\nNow, before generating the classes, it is necessary to connect to an actual Dataverse environment. There are several methods to create connections using the CLI but for the simplicity of the post, we will use this type of command :\npac auth create \u0026ndash;url https://{yourenv}.crm.dynamics.com \u0026ndash;name {yourenv-friendly-name}\nIssuing this command will pop-up an account sign-in screen where you can enter your credentials and connect to the desired environment\nOnce authenticated, the connection will be created and selected as the active connection.\nFor more in-depth information on creating and managing Dataverse connections with the CLI, check out this helpful blog post.\nPower Platform CLI: Installing, Connecting, and Selecting an Organization – Nicolas Nowinski (nicknow.net)\nSimple modelbuilder command Now that we are connected to a Dataverse environment, we can issue modelbuilder commands to generate early-bound classes. Please refer to the official documentation of the PAC CLI below for the most up to date information.\nMicrosoft Power Platform CLI modelbuilder command group - Power Platform | Microsoft Learn\nIn its simplest form you can issue a command like this one.\npac modelbuilder build \u0026ndash;outdirectory Models \u0026ndash;serviceContextName XrmContext \u0026ndash;namespace ModelBuilderTest\nHere\u0026rsquo;s a brief explanation of the parameters and switches.\n--outdirectory This is the directory where the early-bound classes will be created. the directory can be a full path (ex. C://MyOutputPath) or a relative path to the folder where the command is executed.\n--serviceContextName This is the desired name of the generated ServiceContext class. It creates a class in the output directory that extends the OrganizationServiceContext from the SDK and provides Queryable collections for every tables (entities) present in the model, thus enabling the usage of LINQ queries over the Dataverse table data. I personnaly use the name \u0026lsquo;XrmContext\u0026rsquo;.\nWith a servicecontext instantiated you can now produce powerful and easy to understand queries on the business model.\nMore on OrganizationserviceContext here OrganizationServiceContext Class (Microsoft.Xrm.Sdk.Client) | Microsoft Learn\n--namespace This is the desired namespace that the code generation tool use for every generated files\nRunning the command will generate a bunch of files in the folder specified in the \u0026ndash;outdirectory parameter. The Entities folder will contain one file for each tables detected and the OptionSets folder will contain enums representing the global choices (optionsets)\nThe main problem with this pac modelbuilder statement is that it generates huge amount of files (1 file for every tables in the environment) weighing around 25 MB and it took about 2 minutes to completes. In a real life project you should only generate the early-bound classes for the tables that are needed in the business logic of your project.\nLet\u0026rsquo;s see how to optimize the ouput files using other available switches.\nOptimized modelbuilder command There are numerous other switches and parameters available in the modelbuilder command group that will have an effect on the gerated code and files produced, here are the most notable.\n--entitynamesfilter When working with early-bound classes in a customization project, chances are that you\u0026rsquo;ll only need to target a small subset of tables to perform your business logic. The entitynamesfilter parameter in allows the user to provide a semicolon-separated list of table names to filter the exported table classes accordingly.\nFor example, if you only want to use Accounts and Contacts use the following :\n\u0026ndash;entitynamesfilter \u0026ldquo;account;contact\u0026rdquo;\n--generateActions When included, this switch will include early-bound classes for Actions and CustomApis. Actions classes exposes robust and easy to use wrappers around actions/customapi request and response calls.\nSee how easy it is to consume a custom api with early-bound classes with the example shown below. I\u0026rsquo;m using the GetEnvironmentVariable that is part of my generic Custom API collection project.\n--messagenamesfilter This is used to filter the generated messages/actions classes. Same idea as the entitynamesfilter, you can provide a list of Actions/CustomAPI separated with a semicolon\n🐛There is currently slight bug with this feature, to correctly filter the desired actions you need to add a wildcard \u0026lsquo;*\u0026rsquo; at the end of each actions/customapi present in the filter list. I have opened an issue on the CLI github repo and hopefully it will be resolved soon.\npac modelbuilder - generateActions and messagenamesfilter inconsistencies · Issue #495 · microsoft/powerplatform-vscode (github.com)\n--emitfieldsclasses Adding this switch to your model generation command will generate constants out of the fields name of each table in your model.\nAs seen below in the generated account.cs file, this will add a static class called Fields inside the Account class that lists all the fields of the account table as string constants.\nThose constants are then easilly acessible troughout the codebase. This feature is particularly useful in reducing the use of magic strings when you need to fall back to late-bound style for any reason. As demonstrated in the example below.\nAs far as I know, this is a unique feature of the PAC CLI modelbuilder and is not possible when using the (older) crmsvcutil tool. Thus, I highly recommend incorporating this switch for model generation.\n--generateGlobalOptionSets If you include this switch, this will emit classes for all the global optionsets(choices) present in the environment. If you omit the switch, only the global optionset used in the entities produces by the model will be generated. So as a rule of thumb I don\u0026rsquo;t use it.\n--suppressGeneratedCodeAttribute This switch will remove a bit of noise in the output files by removing unecesary and redundant lines of code. If you are a neat freak, you\u0026rsquo;ll definitely want to use it.\n--suppressINotifyPattern By default all properties will expose a INotify pattern that can be used in your code. Issuing that switch will remove the pattern implementation and delete 2 lines of code per properties. I personally never used this pattern in my projects so I\u0026rsquo;m using the switch.\n--writesettingsTemplateFile Using this switch will produce a builderSettings.json file in the output directory.\nThe builderSettings.json file will contain a representation of all the parameters and switches used in the issued pac modelbuilder command. As we will see in the next section, this file can be put in source control and reused on demand.\nMy final optimized statement will look something like this\npac modelbuilder build --outdirectory Models --serviceContextName XrmContext --namespace ModelBuilderTest --emitfieldsclasses --entitynamesfilter \u0026#34;account;contact\u0026#34; --generateActions --messagenamesfilter \u0026#34;driv_GetEnvironmentVariable*\u0026#34; --suppressGeneratedCodeAttribute --suppressINotifyPattern --writesettingsTemplateFile Having limited the number of tables and actions only to what\u0026rsquo;s needed, the whole operation is completed in a couple of seconds and the Models folder weighs around 300 kb, that is much better.\nAll this is great, but not very practical in a real-life project. I want to be able to regenerate the classes on-demand as my project grows in complexity and I don\u0026rsquo;t want to have to remember this big command. Most of all I want to store the configuration in source control where it can be reused by other team members.\nLet\u0026rsquo;s push this a bit further and simplify our lives with the use of a template file.\nGenerate classes from a template file As seen in the previous example, the --writesettingsTemplateFile switch will produce a builderSettings.json that can be used as template to feed into the PAC CLI. In fact, once you have a template file, you dont even need to issue commands that contains all these switches and parameter. You can grab this one as an example to build upon.\nInstead we will use the settingsTemplateFile parameter to supply the settings to the command.\n--settingsTemplateFile This parameter expects the name of the file that contains the parameters and switches. If the file is not located in the directory from where you are issuing the command, put the full path.\nWith this, the command to issue is way more simple, as you only need to provide the output directory and the template file. This file can be stored in source control and can evolve throughout the project\u0026rsquo;s lifecycle.\npac modelbuilder build --outdirectory Models --settingsTemplateFile builderSettings.json With all the necessary components in place, we can now easily generate the early-bound classes on demand as your model and business logic evolves.\nAn example is shown below, with a Dataverse plugin project containing a builderSettings.json file and an earlybound.bat file that runs the PAC CLI command at the project root. Simply executing the .bat file allows for quick and efficient generation of the classes.\nLimitations Here are some limitations I came upon during my experimentation.\nModels folder not cleared The model folder is not cleared between each modelbuilder invocation. Meaning that if you remove a table from your desired early-bound classes, the file that was created from an earlier call would not be deleted. This could potentialy cause noise and unwanted behavior.\nThere\u0026rsquo;s an issue on the PAC CLI repo regarding this : [Feature request] Add clobber option to pac modulebuilder build · Issue #365 · microsoft/powerplatform-vscode (github.com)\nTherefore I advise to find a way to clear the folder before generating the classes.\nLots of files to include in the .csproj I really like that the generated model files are well separated in folders and having one file per artifact (tables, choices, messages) as it\u0026rsquo;s easy to understand and visualize the outputs. But one of the drawback is when used in a C# class library project, everytime a new file appears in the models folder, it must be manually included in the project.\nYou can mitigate this by modifying the .csproj file so that any new files (or deleted filed) that appears in the models folder gets picked and included in the project automatically. By including the following lines :\n\u0026lt;Compile Include=\u0026#34;Models\\*.cs\u0026#34; /\u0026gt; \u0026lt;Compile Include=\u0026#34;Models\\Entities\\*.cs\u0026#34; /\u0026gt; \u0026lt;Compile Include=\u0026#34;Models\\OptionSets\\*.cs\u0026#34; /\u0026gt; \u0026lt;Compile Include=\u0026#34;Models\\Messages\\*.cs\u0026#34; /\u0026gt; I had some issues with this technique as sometimes, I had to shut down and restart the project to get the files included or the include statements gets re-written for no reason.\nFor that reason I would like to have the possibility to emit the generated models in 1 single file that would be included in the project. I know its a bit of an anti-pattern but this was possible with the CrmSvcUtil tool.\nEarly Bound Generator V2 All the examples shown up to here were done using the PAC CLI directly, but you might want to have a look at the Early Bound Generator V2 for XrmToolBox by Daryl Labar. The tool leverages the PAC CLI modelbuilder and adds a lot of extra features including mitigation for the limitations listed above.\nEarly Bound Generator · XrmToolBoxEarly Bound Generator · XrmToolBoxEarly Bound Generator · XrmToolBox\nEarly Bound Generator V2 (linnzawwin.blogspot.com)\nTakeaway That\u0026rsquo;s it for now, It was a lot to cover.\nI hope this post has shed light on the benefits of using the PAC CLI to generate early-bound classes for your Dataverse projects.\nPhoto by Pierre Bamin on Unsplash\n","date":"2023-04-12T03:37:47Z","image":"/how-to-generate-dataverse-early-bound-classes-with-pac-cli-modelbuilder/pierre-bamin-18T72jBinvI-unsplash.jpg","permalink":"/how-to-generate-dataverse-early-bound-classes-with-pac-cli-modelbuilder/","title":"How to Generate Dataverse Early-Bound Classes with PAC CLI ModelBuilder"}