How to resolve "InvalidOperationException: Cannot resolve 'ProjectName.SendEmailCustomUmbracoWorkflow' from root provider because it requires scoped service 'ProjectName.ICustomServiceName'"
When you access a custom service from within your Custom Umbraco Workflow or a similar environment, you may encounter an "Invalid Operation Exception." This error typically occurs because you are attempting to use a scoped service within a singleton context.
Solution
If you need to use a scoped service within a singleton, inject IServiceScopeFactory into the singleton. Then, create a scope to pull out your context when needed.
using ProjectName.Microsites.Cms.DataAccess.Constants;
using ProjectName.Web.Services.Interfaces;
using Newtonsoft.Json.Linq;
using Umbraco.Forms.Core;
using Umbraco.Forms.Core.Attributes;
using Umbraco.Forms.Core.Enums;
using Umbraco.Forms.Core.Persistence.Dtos;
namespace ProjectName.Web.UI.Workflows
{
public class CrmFieldMapper : WorkflowType
{
private readonly ILogger<CrmFieldMapper> _logger;
private readonly IServiceScopeFactory _serviceScopeFactory;
public CrmFieldMapper(ILogger<CrmFieldMapper> logger,
IServiceScopeFactory serviceScopeFactory) //IFormDataService formDataService)
{
Id = new Guid("b8167f85-0ca4-4d63-80e1-069eef772dca");
Name = "Crm Field Mapper";
Description = "Custom workflow to map form fields to CRM fields";
Icon = "icon-trafic";
_logger = logger;
// Inject IServiceScopeFactory into the singleton
_serviceScopeFactory = serviceScopeFactory;
//_formDataService = formDataService;
}
[Setting("Field Mappings",
Description = "Map fields from the form to CRM",
View = $"~/App_Plugins/CrmFieldMapper/crmfieldmapper.html",
PreValues = "")]
public string MappingsField { get; set; } = string.Empty;
public override async Task<WorkflowExecutionStatus> ExecuteAsync(
WorkflowExecutionContext context)
{
try
{
// Create a scope for your service and then use it
using var scope = _serviceScopeFactory.CreateScope();
var formDataService = scope.ServiceProvider
.GetRequiredService<IFormDataService>();
var mappableCRMFields = formDataService
.GetAllActiveMappableCRMFieldsCached();
if (mappableCRMFields != null)
{
var record = context.Record;
var formGuid = record.Form;
var fieldMappings = new Dictionary<string, int>();
foreach (var mappableCRMField in mappableCRMFields)
{
var formAlias = GetFormAlias(record,
mappableCRMField.CRMFieldFriendlyName);
if (!string.IsNullOrEmpty(formAlias))
{
// Mapping is done for this form value,
// add it to the fieldMappings dictionary
fieldMappings.Add(formAlias,
mappableCRMField.Id);
}
}
if (fieldMappings.Any())
{
formDataService.SaveFormFieldMappings(formGuid,
fieldMappings,
FormMappingConstants.FieldMappingNotSetOptionId);
}
}
return WorkflowExecutionStatus.Completed;
}
catch (Exception ex)
{
_logger.LogError($"CrmFieldMapper Execute exception,
ex.Message: {ex.Message},
ex.StackTrace: {ex.StackTrace}");
}
return WorkflowExecutionStatus.Failed;
}
public override List<Exception> ValidateSettings()
{
List<Exception> exceptions = new List<Exception>();
// Validation errors can be added
// to make sure certain mappings have been set
//var settings = JArray.Parse(MappingsField)
// as IEnumerable<dynamic>;
//if (!settings.Any(x => x.alias.ToString().ToLower() == "name") ||
// !settings.Any(x => x.alias.ToString().ToLower() == "email") ||
// !settings.Any(x => x.alias.ToString().ToLower() == "message"))
//{
// exceptions.Add(new Exception("Mappings for name,
// email and message must be set."));
//}
return exceptions;
}
private string GetFormAlias(Record record, string alias)
{
// parse the mappings JSON string
var settings = JArray.Parse(MappingsField) as IEnumerable<dynamic>;
if (settings != null)
{
var mappedValue = settings
.FirstOrDefault(x => x.alias.ToString().ToLower() ==
alias.ToLower())?.value;
if (mappedValue != null)
{
// dynamic mappedValue is always a guid if it is not null
// get the field guid for the given alias and
// return the corresponding alias from the record
return record.GetRecordField((Guid)mappedValue).Alias;
}
}
return string.Empty;
}
}
}
Comments
Post a Comment