Skip to content

Integrate EarlyBound Generator API #383

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from

Conversation

daryllabar
Copy link

PR for Integrate EarlyBound Generator #378

Added a new useEarlyBoundGeneratorApi flag to allow for using the EBG vs the Spkrl logic. Mapped all settings of earlyboundtypes except generateStateEnums and GenerateGlobalOptionSets as there are no settings currently for this in the EarlyBoundGenerator.

Updated EarlyBoundTypeConfig to inherit from DLaB.EarlyBoundGeneator.Settings.POCO.ExtensionConfig. This means all settings in the EarlyBoundGenerator will be allowed (except it they are overriden with the current settings of the EarlyBoundTypeConfig. Also added names for the action, and optionSet.

Updated Tests.

daryllabar added 3 commits May 6, 2020 10:50
Removed Previous CrmSvcUtil Utilities.
Mapped all settings of earlyboundtypes except generateStateEnums and GenerateGlobalOptionSets.   There are no settings currently for this in the EarlyBoundGenerator, and I can't think of a good reason why you would not want to include these.

Updated EarlyBoundTypeConfig to inherit from DLaB.EarlyBoundGeneator.Settings.POCO.ExtensionConfig.  This means all settings in the EarlyBoundGenerator will be allowed (except it they are overriden with the current settings of the EarlyBoundTypeConfig.  Also added names for the action, and optionSet.

Updated Tests.

Updated VS.  Not sure that matters...
@daryllabar
Copy link
Author

Not sure why, but the tests failed for the older logic when generating a file per entity because the entities.cs file wasn't getting deleted. I don't believe I've done anything to remove any code that deletes those files, so I've left it there. If I have some how, then let me know and i'll figure out how to add it back I guess.

@daryllabar
Copy link
Author

Here is the update to the documentation:

Wherever you can, it's best practice to use early bound types in your C# code. You can easily get spkl to generate these classes in a way that can be repeatedly run and refreshed when your schema changes.

There are two main options for generating earlybound types, spkl has it's own built in generator, as well as the EarlyBoundGeneratorApi, the same one built for the XrmToolBox.

To use the spkl internal generator your spkl.json would look like:

{
  "earlyboundtypes": [
    {
	  "useEarlyBoundGeneratorApi": false
      "entities": "account,contact,quote",
      "actions": "dev1_simpleaction",
      "generateOptionsetEnums": true,
      "generateStateEnums": true,
      "generateGlobalOptionsets": true,
      "filename": "EarlyBoundTypes.cs",
      "classNamespace": "TestPlugin",
      "serviceContextName": "XrmSvc",
	  "oneTypePerFile": false
    }
  ]
}
  • useEarlyBoundGeneratorApi - Optional, defaults to false.
  • entities - Comma seperate list of entity logical names. I've not provided support for -all- entities because this results in unnecessarily large plugins!
  • actions - Comma separated list of actions request/responses to generate - leave empty or omit for none
  • generateOptionsetEnums - Set to 'true' to generate Enums for optionsets
  • generateStateEnums - Set to 'true' to generate Enums for States and Statuses
  • generateGlobalOptionsets - Set to 'true' to generate Enums for Global optionsets
  • filename - The path (relative to this file) to output
  • classNamespace - The namespace to put the classes under
  • serviceContextName - The name of the Service context to create - leave blank or omit for none
  • oneTypePerFile - Splits the files into seperate files.

To use the EarlyBoundGeneratorApi your spkl.json would look like:

{
  "earlyboundtypes": [
    {
	  "useEarlyBoundGeneratorApi": true,
      "entities": "account,contact,quote",
      "actions": "dev1_simpleaction",
      "classNamespace": "TestPlugin",
     
	  // Optional - Recommend only including if needed
	  "generateOptionsetEnums": true,
      "filename": "Entities.cs",
      "actionFilename": "Actions.cs",
      "optionSetFilename": "OptionSets.cs",
	  "serviceContextName": "XrmSvc",
	  "oneTypePerFile": true,
	  "AddDebuggerNonUserCode": true,
	  "AddNewFilesToProject": true,
	  "DeleteFilesFromOutputFolders": false,
	  "EntityAttributeSpecifiedNames": "EntityName1:FirstAttributeNameWithCustomCasing,SecondAttribute|EntityName2:FirstAttributeNameWithCustomCasing,SecondAttribute",
	  "GenerateActionAttributeNameConsts": true,
	  "GenerateAttributeNameConsts": true,
	  "GenerateAnonymousTypeConstructor": true,
	  "GenerateConstructorsSansLogicalName": false,
	  "GenerateEntityRelationships": true,
	  "GenerateEntityTypeCode": false,
	  "GenerateOnlyReferencedOptionSets": true,
	  "GenerateOptionSetMetadataAttribute": true,
	  "InvalidCSharpNamePrefix":"_",
	  "MakeAllFieldsEditable": false,
	  "MakeReadonlyFieldsEditable": false,
	  "MakeResponseActionsEditable": true,
	  "LocalOptionSetFormat": "{0}_{1}",
	  "OptionSetLanguageCodeOverride": 1033,
	  "ProjectNameForEarlyBoundFiles": "MyEarlyboundProject.proj",
	  "PropertyEnumMappings": "EntityName.PropertyName,EnumName|EntityName2.PropertyName,EnumName",
	  "RemoveRuntimeVersionComment": true,
	  "ReplaceOptionSetPropertiesWithEnum": true,
	  "UseTfsToCheckoutFiles": false,
    }
  ]
}
  • useEarlyBoundGeneratorApi - Required since it defaults to false if not provided.
  • entities - Comma seperate list of entity logical names. I've not provided support for -all- entities because this results in unnecessarily large plugins!
  • actions - Comma separated list of actions request/responses to generate - leave empty or omit for none
  • classNamespace - The namespace to put the classes under
  • generateOptionsetEnums - Set to 'false' to not generate Enums for optionsets. Default is true
  • filename - The path (relative to this file) to output of the entities. Defaults to entities.cs. If oneTypePreFile is specified, used as the folder name.
  • actionFilename - The path (relative to this file) to output of the entities. Defaults to actions.cs If oneTypePreFile is specified, used as the folder name.
  • optionSetFilename - The path (relative to this file) to output of the entities. Defaults to optionsets.cs If oneTypePreFile is specified, used as the folder name.
  • serviceContextName - The name of the Service context to create
  • oneTypePerFile - Splits the files into seperate files.
  • AddDebuggerNonUserCode - Specifies that the debugger should skip stepping into generated entity files.
  • AddNewFilesToProject - Adds newly created files to Project File
  • AddOptionSetMetadataAttribute - Adds the OptionSetMetadataAttribute to enums to be able to access enum metadata. Ensure Generate Option Set Metadata Attribute is true to generate the attribute definition, unless this has been handled in some other manner.
  • DeleteFilesFromOutputFolders - Clears all .cs files from output folders prior to file generation. This helps to remove files that are no longer being generated. Only used if Create One File Per Action/Entity/OptionSet is true.
  • EntityAttributeSpecifiedNames - Formatted as a single string in the format of "EntityName1:firstAttributeName, ... ,lastAttributeName|EntityName2:firstAttributeName, ... ,lastAttributeName|..." Basically split each entity by pipe, use then split by colon, then comma, with the first value being the entityName Allows for the ability to specify the capitalization of an attribute on an entity
  • GenerateActionAttributeNameConsts - Specifies the generation of an Attributes Struct containing logical names for all attributes for the Action
  • GenerateAttributeNameConsts - Specifies the generation of an Attributes Struct containing logical names for all attributes for the Entity
  • GenerateAnonymousTypeConstructor - Specifies the generation of AnonymousType Constructors for entities
  • GenerateConstructorsSansLogicalName - Adds Constructors to each early bound entity class to use constructors available to Microsoft.Xrm.Sdk.Entity
  • GenerateEntityRelationships - Specifies the generation of Relationships properties for Entities
  • GenerateEntityTypeCode - By default the CrmSvcUtil generates the Entity Type Code, this is considered dangerous and not recommended since it is a system generated value, and not one defined in the solution metadata, changing from environment to environment.
  • GenerateOnlyReferencedOptionSets - Specifies that only option sets that are referenced by Entities that are generated.
  • GenerateOptionSetMetadataAttribute - Generates an OptionSetMetadataAttribute class used to allow for storing of the metadata of OptionSetValues i.e. display order, name, description, etc. Only used if Add Option Set Metadata Attribute is true.
  • InvalidCSharpNamePrefix - Specifies the Prefix to be used for OptionSets that would normally start with an invalid first character ie "1st"
  • MakeAllFieldsEditable - Defines that Entities should be created with all attributes as editable. Helpful for writing linq statements where those attributes are wanting to be returned in the select.
  • MakeReadonlyFieldsEditable - Defines that Entities should be created with editable createdby, createdon, modifiedby, modifiedon, owningbusinessunit, owningteam, and owninguser properties. Helpful for writing linq statements where those attributes are wanting to be returned in the select
  • MakeResponseActionsEditable - Specifies that the properties of Response Actions should be editable.
  • LocalOptionSetFormat - Defines the format of Local Option Sets where {0} is the Entity Schema Name, and {1} is the Attribute Schema Name. The format Specified in the SDK is {0}{1}, but the default is {0}{1}, but used to be prefix{0}_{1}(all lower case)
  • OptionSetLanguageCodeOverride - Overrides the default (English:1033) language code used for generating Option Set Value names (the value, not the option set)
  • ProjectNameForEarlyBoundFiles - The name of the project to add newly created files to. If not value is provided, the first one found will be used.
  • PropertyEnumMappings - Used to manually specify an enum mapping for an OptionSetValue Property on an entity. Format: EntityName.PropertyName,EnumName|
  • RemoveRuntimeVersionComment - Remove the Runtime Version in the header comment
  • ReplaceOptionSetPropertiesWithEnum - Used in Conjunction with GenerateEnumProperties. Allows for replacing the OptionSet properties, rather than duplicating them
  • UseTfsToCheckoutFiles - Uses TFS to checkout files.

No matter which generator you use, you can refresh the classes file by calling:

spkl earlybound

@filcole
Copy link
Contributor

filcole commented May 16, 2020

This is a great idea. I wonder about a slightly different use case.

Could the earlyboundconfig generated by XrmToolbox be referenced in the config when using Daryls Early Bound generator within spkl? This gives the benefits of the XrmToolbox configuration screens, whilst the consistent/combined usage within spkl, something like:

"earlyboundtypes": [
{
"useExternalEarlyBoundGeneratorApi": true,
"earlyboundConfigXml": #
}

I'm not sure if that will introduce tool close a version dependency - e.g. if XrmToolbox logic is updated, but spkl doesn't have a corresponding release using the updated EBG library then the config might not be used. A thought anyway.

@daryllabar
Copy link
Author

In order to be as compatible with the Spkl framework as possible, I used the config settings from spkl to override the EBG settings. Where there wasn't a compatible setting, I used the same settings as the EBG. So it would not be too hard to transfer the settings over manually. And if you are opening the EBG to generate the config, you might as well just use the EBG to generate your entities.

@pawelgradecki
Copy link
Contributor

This is great @daryllabar ! Would you mind to also add possibility of having entities and actions as collection like proposed by me in #353 ? This really matters for big projects with a lot of entities and many people merging spkl.json in parallel and it's super simple to have it as an alternative to single, comma separated string.

@daryllabar
Copy link
Author

The EBG itself supports putting the logical names on new lines, while still being pipe delimited, so if it's essential, you can decide just to use that instead. Problem is I use the same method as the Spkl framework to get the logical names, so that won't work in your case. The simplest thing I can think of is to create an override setting that points to an EBG xml file, Instead of the JSON. Once this PR gets approved, feel free to submit a PR for either approach, it would be rather trival.

@scottdurow
Copy link
Owner

Not sure why, but the tests failed for the older logic when generating a file per entity because the entities.cs file wasn't getting deleted. I don't believe I've done anything to remove any code that deletes those files, so I've left it there. If I have some how, then let me know and i'll figure out how to add it back I guess.

This looks like it's because of c53631f#diff-a3e89ccc902720e9929d5a1f5ef72f68

@daryllabar
Copy link
Author

Sorry, it's been awhile since i looked at this. I'm guessing you want me to make the older tests pass, and to check out the code that you are calling out as the culprit?

@scottdurow
Copy link
Owner

Thanks @daryllabar - No it's fine - I've got a branch where I'm testing before merging - I've added the delete of entities.cs back in.

@ewingjm - I think the issue here is that the code splitting should split out the context - rather than leaving the original entities.cs in there.

@scottdurow
Copy link
Owner

scottdurow commented Jun 30, 2020

@daryllabar - Not sure why, but the EbgApi version of the integration tests take 10 times longer to run - any idea why?

@daryllabar
Copy link
Author

Not sure. I do a lot of work with naming of entities that require me to go loop through the generated code multiple times before it's actually written to disk. Maybe that's it? Any improvement for tests that don't split the file up into multiple files?

@ewingjm
Copy link
Contributor

ewingjm commented Jul 1, 2020

@ewingjm - I think the issue here is that the code splitting should split out the context - rather than leaving the original entities.cs in there.

Ah, yes - that makes much more sense!

@scottdurow
Copy link
Owner

Done some testing this morning:

  • It is spkl not sprkl 😋
  • It seems to require the DLaB.EarlyBoundGenerator.Api package to be installed even if not using it for early bound generation
  • The DLaB.EarlyBoundGenerator.Api needs to be added to the nuspec because it's a dependency of the tasks assembly now.
  • I've done some tests using a local packaged version of the NuGet package and it seems that even when useEarlyBoundGeneratorApi=false - the DLaB.Xrm.EarlyBoundGenerator.Api package is required

@daryllabar
Copy link
Author

It is spkl not sprkl 😋
Doh! Do I need to update this?

It seems to require the DLaB.EarlyBoundGenerator.Api package to be installed even if not using it for early bound generation
Yeah, the reason for this is I reference the POCO objects in the DLaB.EarlyBoundGenerator.Api to create the serialization entities, so that is why the package is required. Did you assume that it would download whatever it needed when you first flipped the flag to use the EBG.API?

The DLaB.EarlyBoundGenerator.Api needs to be added to the nuspec because it's a dependency of the tasks assembly now.
Do I need to update this?

I've done some tests using a local packaged version of the NuGet package and it seems that even when useEarlyBoundGeneratorApi=false - the DLaB.Xrm.EarlyBoundGenerator.Api package is required
This could probably be undone by moving the EBG.Api logic. into a different class so it doesn't attempt to load the assembly. And again, would you like me to do anything?

@scottdurow
Copy link
Owner

I can fix those things.
I've had to make the loading of the crmsvcutil in the spkl version specifically look for the coretools because it always tries to pick up the latest version of the coretools - rather than deploy a version with spkl it's self.

Also - I had to add logic to only set MaskPassword to true if the connection string contains a password - currently the https://github.com/daryllabar/DLaB.Xrm.XrmToolBoxTools/blob/033048492159d7bbd2a5354e3c7f6b01143804c7/DLaB.EarlyBoundGenerator.Logic/Logic.cs#L217 will fail with Index was out of range.

@scottdurow
Copy link
Owner

Also - in your PR - you've added a reference to Microsoft.VisualBasic - is that really needed?

scottdurow added a commit that referenced this pull request Jul 1, 2020
@daryllabar
Copy link
Author

I've added an issue on my side for the Mask Password thing. Thanks for pointing it out.
As far as the VB thing, what's going on? Are you a little VB Phobic? LOL. Actually I had to look at the check-ins and no, that is no longer needed. I do use it in a different project since it will parse CSVs for you really nicely. I'll remove that dependency, and I can push that out now if it makes a difference to you.

@scottdurow
Copy link
Owner

Replaced by #389

@scottdurow scottdurow closed this Jul 1, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants