Table of Contents

Plugin configuration

Plugins inheriting from PluginBase2 use JSON for configuration.

using Hsl.Logging;
using Hsl.Xrm.Sdk;
using Hsl.Xrm.Sdk.Plugin;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
using System;
using System.Linq;
using System.Net.Http;
using System.Text.Json;

namespace Sample.Plugins
{
    public class ExampleConfiguredBulkPlugin : PluginBase2, IPlugin
    {
        #region Configuration/Fields
        private int totalNumber;
        private SecureConfigSettings apiConfig;
        
        // Any configuration that is sensitive OR that differs between environments should be stored in the secure configuration
        public class SecureConfigSettings
        {
            public string ApiKey { get; set; }
            public string ApiUrl { get; set; }
        }

        // The unsecure configuration is moved with solutions so don't include information that differs between environments.
        public class UnsecureConfigSettings
        {
            public int SomeNumber { get; set; }
            public int SomeNumber2 { get; set; }
        }

        protected override void LoadConfiguration(string unsecureConfig, string secureConfig)
        {
            // Recommended approach is to use LoadConfiguration to deserialize the configuration.
            // The platform gives a confusing error if the constructor throws an exception.
            // LoadConfiguration will surface an error with a reasonable message to the user.
            // Recommended approach is to use System.Text.Json.JsonSerializer to deserialize the configuration.
            var unsecureConfigObj = JsonSerializer.Deserialize<UnsecureConfigSettings>(unsecureConfig, new JsonSerializerOptions
            {
                AllowTrailingCommas = true,
                ReadCommentHandling = JsonCommentHandling.Skip,
            });

            apiConfig = JsonSerializer.Deserialize<SecureConfigSettings>(secureConfig);

            // You can have validation logic in LoadConfiguration.
            if (unsecureConfigObj.SomeNumber <= 0)
                throw new InvalidPluginExecutionException($"Invalid plugin configuration. SomeNumber must be positive. Please contact a system administrator");

            // You can also do calculations or other actions based on the config.
            totalNumber = unsecureConfigObj.SomeNumber + unsecureConfigObj.SomeNumber2;

            // To control LogLevel via config, see https://docs.hitachisolutions.com/hslxrmsdk/articles/getting-started-plugins.html#trace-configuration
        }
        #endregion


        public override void ExecuteAction(IPluginEventContext2 pluginEventContext)
        {
            var logger = pluginEventContext.Logger;
            var systemService = pluginEventContext.XrmContext.SystemOrgService;
            var targets = pluginEventContext.Targets;

            // GetValue<T> will get the expected value after the plugin operation - will check the images if available.
            var parentAccountIds = targets.Select(x => x.GetValue<Guid>("hsl_accountid")).Distinct();

            var parentAccountsById = systemService.BulkRetrieveByIds("account", parentAccountIds, new ColumnSet("name", "customertypecode"))
                .ToDictionary(x => x.Id);

            foreach (var target in targets)
            {
                var parent = parentAccountsById[target.GetValue<Guid>("hsl_accountid")];
                var parentType = parent.GetFieldValue<CustomerTypeCode>("customertypecode");

                if (parentType == CustomerTypeCode.ParentGroup && target.GetValue<int>("hsl_fielda") >= totalNumber)
                {
                    // If multiple records are being created/updated, CreateException will include information about which record failed.
                    // If only a single record is being created/updated, it will not so that the user doesn't get confused by an error message
                    // like "Error on 7B4D499F-4FB0-45CC-A074-853E7EDE2263 index 0: Field A must be less than 8" a user editing a single record
                    // will just see "Field A must be less than 8".
                    throw target.CreateException($"Field A must be less than {totalNumber:N0}");
                }
                else
                {
                    var number = target.GetValue<string>("hsl_someidentifier");

                    var request = new HttpRequestMessage(HttpMethod.Get, $"{apiConfig.ApiUrl}/{number}");
                    request.Headers.Add("ApiKey", apiConfig.ApiKey);

                    var response = client.SendAsync(request).Result;

                    if (response.IsSuccessStatusCode)
                    {
                        var responseString = response.Content.ReadAsStringAsync().Result;
                        logger.LogInfo($"Got result {responseString}");
                    }
                    else
                    {
                        throw target.CreateException($"Request to some intergrated service failed with status {response.StatusCode}");
                    }
                }
            }
        }

        private static readonly HttpClient client = new();

        public enum CustomerTypeCode
        {
            Prospect = 1,
            Customer = 2,
            Competitor = 3,
            ParentGroup = 296010001,
        }

        #region Constructors
        public ExampleConfiguredBulkPlugin()
        {
        }

        public ExampleConfiguredBulkPlugin(string unsecureConfig, string secureConfig) : base(unsecureConfig, secureConfig)
        {
        }
        #endregion

    }
}

Trace Configuration

"TraceConfiguration" can be used to configure plugin trace settings. You can add it to the root object of your configuration.

{
	// Comments are allowed in plugin configuration.
	"ApiKey": "your-api-key",
	"ApiUrl": "https://example.com",
	// Trace config
	"TraceConfiguration": {
		"LogLevel": "Warning", 
		"Indent": "  ", 
		"LogContext": false,
	},
}

The following log levels are available:

  • None (least messages)
  • Critical
  • Error
  • Warning
  • Info
  • Debug
  • Trace (most messages)

The trace configuration can appear in either the unsecure or secure config. If it appears in both, the secure config will be used. If not supplied at all, LogLevel defaults to Info.