I'm working on a Dynamics 365 Marketing form where I use a custom plugin for server-side validation. The plugin runs correctly and does not throw exceptions. It deserializes the msdynmkt_formsubmissionrequest, checks a custom field (nnc_event_registration_id) against a custom entity, and sets a response based on whether the code is valid.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.IO;
using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Query;
namespace DynamicsPlugins
{
public class nnc_event_registration_code_validierung : IPlugin
{
public void Execute(IServiceProvider serviceProvider)
{
var tracingService = (ITracingService)serviceProvider.GetService(typeof(ITracingService));
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
var serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
var service = serviceFactory.CreateOrganizationService(context.UserId);
tracingService.Trace("Starting plugin execution.");
try
{
tracingService.Trace("Checking input parameters.");
if (!context.InputParameters.Contains("msdynmkt_formsubmissionrequest") || context.InputParameters["msdynmkt_formsubmissionrequest"] == null)
{
tracingService.Trace("Form submission request is missing.");
throw new InvalidPluginExecutionException("Form submission data not found.");
}
var requestString = (string)context.InputParameters["msdynmkt_formsubmissionrequest"];
if (string.IsNullOrWhiteSpace(requestString))
{
tracingService.Trace("Form submission request string is empty.");
throw new InvalidPluginExecutionException("Empty form submission data.");
}
tracingService.Trace($"Form submission request string: {requestString}");
tracingService.Trace("Deserializing form submission request.");
var requestObject = Deserialize<FormSubmissionRequest>(requestString);
if (requestObject == null)
{
tracingService.Trace("Deserialized form submission object is null.");
throw new InvalidPluginExecutionException("Invalid form submission data.");
}
if (requestObject.Fields == null || !requestObject.Fields.Any())
{
tracingService.Trace("Fields list is missing or empty.");
SetValidationResponse(context, false, "Bitte geben Sie einen Einladungscode ein.");
return;
}
tracingService.Trace($"Fields count: {requestObject.Fields.Count}");
foreach (var field in requestObject.Fields)
{
tracingService.Trace($"Field: {field.Key} = {field.Value}");
}
var fieldsDict = requestObject.Fields.ToDictionary(f => f.Key, f => f.Value);
if (!fieldsDict.TryGetValue("nnc_event_registration_id", out string registrationCode) || string.IsNullOrWhiteSpace(registrationCode))
{
tracingService.Trace("nnc_event_registration_id not provided.");
SetValidationResponse(context, false, "Bitte geben Sie einen Einladungscode ein.");
return;
}
tracingService.Trace($"Registration code received: {registrationCode}");
var query = new QueryExpression("nnc_einladungsversand_empfanger")
{
ColumnSet = new ColumnSet("nnc_registration_abgeschlossen"),
Criteria = new FilterExpression
{
Conditions = {
new ConditionExpression("nnc_name", ConditionOperator.Equal, registrationCode)
}
}
};
tracingService.Trace("Executing query against nnc_einladungsversand_empfanger.");
var results = service.RetrieveMultiple(query);
if (results == null || !results.Entities.Any())
{
tracingService.Trace("Invitation code not valid.");
SetValidationResponse(context, false, "Dies ist kein gültiger Einladungscode.");
return;
}
var empfaenger = results.Entities.First();
var registrationCompleted = empfaenger.GetAttributeValue<bool>("nnc_registration_abgeschlossen");
tracingService.Trace($"Registration completed status: {registrationCompleted}");
if (registrationCompleted)
{
tracingService.Trace("Invitation code already registered.");
SetValidationResponse(context, false, "Für diesen Code wurde bereits eine Registration durchgeführt.");
return;
}
tracingService.Trace("Invitation code valid. Allowing registration.");
SetValidationResponse(context, true);
}
catch (Exception ex)
{
tracingService.Trace($"Exception occurred: {ex.Message}");
throw new InvalidPluginExecutionException("An error occurred during registration validation.", ex);
}
}
private void SetValidationResponse(IPluginExecutionContext context, bool isValid, string errorMessage = null)
{
//////// I think this is a critical part ///////////////////////
var resp = new ValidateFormSubmissionResponse()
{
IsValid = isValid,
ValidationOnlyFields = new List<string> { "nnc_event_registration_id" },
ValidationErrorMessage = string.IsNullOrEmpty(errorMessage) ? null : errorMessage
};
context.OutputParameters["msdynmkt_validationresponse"] = Serialize(resp);
}
////////////////////////////////////////////////////////////////
private T Deserialize<T>(string jsonString)
{
var serializer = new DataContractJsonSerializer(typeof(T));
using (var stream = new MemoryStream(Encoding.UTF8.GetBytes(jsonString)))
{
return (T)serializer.ReadObject(stream);
}
}
private string Serialize<T>(T obj)
{
var serializer = new DataContractJsonSerializer(typeof(T));
using (var memoryStream = new MemoryStream())
{
serializer.WriteObject(memoryStream, obj);
return Encoding.UTF8.GetString(memoryStream.ToArray());
}
}
[DataContract]
public class FormSubmissionRequest
{
[DataMember(Name = "Fields")]
public List<FieldEntry> Fields { get; set; }
[DataMember(Name = "recordId")]
public string RecordId { get; set; }
[DataMember(Name = "submissionId")]
public string SubmissionId { get; set; }
[DataMember(Name = "entityName")]
public string EntityName { get; set; }
}
[DataContract]
public class FieldEntry
{
[DataMember(Name = "Key")]
public string Key { get; set; }
[DataMember(Name = "Value")]
public string Value { get; set; }
}
[DataContract]
public class ValidateFormSubmissionResponse
{
[DataMember(Name = "isValid")]
public bool IsValid { get; set; }
[DataMember(Name = "validationOnlyFields")]
public List<string> ValidationOnlyFields { get; set; }
[DataMember(Name = "validationErrorMessage", EmitDefaultValue = false)]
public string ValidationErrorMessage { get; set; }
}
}
}