Posted on 25/03/2025 10:16:07
Hi Pedro
You create an update provider. They are made for being applied once to the database. There are 5 kind
- FileUpdate
- InitializeDatabaseUpdate
- MethodUpdate
- SettingUpdate
- SqlUpdate
And if you want, you can create your own.
In your case you might want to create one or more MethodUpdate providers
public sealed class SmartSearchUpdateProvider : UpdateProvider
{
public override IEnumerable<Update> GetUpdates() => new List<Update>()
{
new MethodUpdate("ebcf6257-ae85-4248-ba9b-3842a66f21b9", this, UpdateRulesForSmartSearches),
/*
* IMPORTANT!
* Use a generated GUID string as id for an update
* - Execute command in C# interactive window: Guid.NewGuid().ToString()
*/
};
private static void UpdateRulesForSmartSearches(UpdateContext context)
{
var integerIdPattern = "\"id\":(\"|\")?(\\d+)";
var userFields = new List<string>(["CreatedBy", "UpdatedBy"]);
var emailFields = new List<string>(["_pseudo_email_sent", "_pseudo_email_opened", "_pseudo_email_clicked_link"]);
// US #20207
// TODO:
// var emailLinkFields = new List<string>(["_pseudo_email_clicked_specific_link"]);
var allSmartSearches = SmartSearchManager.GetAllSmartSearches();
foreach (var smartSearch in allSmartSearches)
{
var smartSearchChanged = false;
foreach (var ruleGroup in smartSearch.RuleGroups)
{
foreach (var rule in ruleGroup)
{
var isUserField = userFields.Contains(rule.Field.ID, StringComparer.OrdinalIgnoreCase);
var isEmailField = !isUserField && emailFields.Contains(rule.Field.ID, StringComparer.OrdinalIgnoreCase);
if (isUserField || isEmailField)
{
var match = Regex.Match(rule.Value, integerIdPattern);
if (match.Success && int.TryParse(match.Groups[2].Value, out var newValue))
{
rule.Value = newValue.ToString(CultureInfo.InvariantCulture);
rule.Field.TypeName = typeof(int).FullName!;
rule.Field.ControlType = isUserField
? SmartSearchRuleControlType.UserCtrl
: SmartSearchRuleControlType.EmailCtrl;
smartSearchChanged = true;
}
}
}
}
if (smartSearchChanged)
smartSearch.Save();
}
}
}
Another example is to use fileproviders that can take a file that is embedded in your nuget package and can then be copied to the file system when the package is installed the first time:
new FileUpdate("47c228ac-fd96-4683-a12a-33e11ea94375", this, "/Files/Templates/DataIntegration/Notifications/ActivityNotificationTemplate.cshtml", DataIntegrationFileStreams.GetActivityNotificationTemplate)
The file is read as a ressource from the nuget package:
internal static class DataIntegrationFileStreams
{
public static Stream GetActivityNotificationTemplate() => GetResourceStream("Templates.DataIntegration.Notifications.ActivityNotificationTemplate.cshtml");
/// <summary>
/// Gets the file stream.
/// </summary>
/// <param name="name">Part of the resource name, except "Dynamicweb.Updates.Files."</param>
private static Stream GetResourceStream(string name)
{
string resourceName = $"Dynamicweb.DataIntegration.Updates.Files.{name}";
return Assembly.GetAssembly(typeof(DataIntegrationFileStreams))?.GetManifestResourceStream(resourceName) ?? throw new InvalidOperationException($"Resource '{resourceName}' not found.");
}
}
And the file is just embedded in the dll using embeddedressource:
