First email goes out and then the consecutive email fails with the error:
System.InvalidOperationException: Context flow is already suppressed.
at System.Threading.ExecutionContext.SuppressFlow() at
NewsletterStudio.Core.Public.NewsletterStudioService.SendTransactional(SendTransactionalEmailRequest
request)
Option 2
If we try to execute it in async mode then the first email gets sent tout and the consecutive email hits the campaign service instead of the transactional.
var customersToEmail = await GetCustomers();
foreach (var customer in customersToEmail)
{
await _transactionalEmailService.SendReminderEmail(customer);
}
Are you running this in a background job in some way?
I need to look closer at why you're getting the "Context flow is already suppressed."-error but a potential workaround for you is to force the sending to be sequential by chaining on the .NotAsync() call when building up the SendTransactionalEmailRequest.
Update your "Option 1" so look something like this:
If I add .NotAsync() I am getting the following on the first send (no matter within async or sync method):
System.InvalidOperationException
HResult=0x80131509
Message=Cannot resolve scoped service 'Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers.IViewBufferScope' from root provider.
Source=Microsoft.Extensions.DependencyInjection
StackTrace:
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
at Microsoft.AspNetCore.Mvc.Razor.RazorView.<RenderAsync>d__18.MoveNext()
at NewsletterStudio.Web.Rendering.RazorHostViewRenderer.<RenderToStringAsync>d__6.MoveNext()
at NewsletterStudio.Web.Rendering.RazorHostViewRenderer.RenderPartialViewToString(String viewName, Object model)
at NewsletterStudio.Core.Rendering.EmailRenderer.Render(IRecipientDataModel recipient)
at NewsletterStudio.Core.Sending.Transactional.TransactionalEmailSender.Send(SendTransactionalEmailRequest request)
I need to understand the exact details around this, what do you mean with "API call"?
Where exactly are you hosting this code?
var customersToEmail = await GetCustomers();
foreach (var customer in customersToEmail)
{
_transactionalEmailService.SendReminderEmail(customer);
}
Is it a "regular" API Controller like this:
[ApiController]
public class MyController : Controller
{
public ActionResult Something()
{
var customersToEmail = await GetCustomers();
foreach (var customer in customersToEmail)
{
_transactionalEmailService.SendReminderEmail(customer);
}
}
}
Could you provide some more exact details around how/where you are calling the service?
Are you using anything "special" framework? Minimal API, API Controllers? Fast Endpoints? Please provide as much details as possible so that I can replicate the issue.
The thing is that it looks like the INewsletterStudioService is used in context where the dependency injection container does not have a scope and the rendering engine is dependent on e.g. IViewBufferScope which is a scoped dependency. The fact that the error says "....from root provider." indicates that there is something about the context is which the service is used that is causing the issue - that's why I need as much details as possible.
Hi Markus,
It is UmbracoApiController.
It's a pretty basic call atm because we just started developing it.
The controller action gets customer emails and then processes them in foreach loop that calls the ITransactionalEmailService and its SendReminderEmail() action, the one that I pasted initially. That's it.
We have a scheduled task that runs the following action:
public class ReminderApiController : UmbracoApiController
{
private readonly ITransactionalEmailService _transactionalEmailService;
public ReminderApiController(ITransactionalEmailService transactionalEmailService)
{
_transactionalEmailService = transactionalEmailService;
}
[HttpGet]
public async Task<IActionResult> SendReminder(string subjectTemplate)
{
var customersToEmail = await GetCustomers();
foreach (var customer in customersToEmail)
{
_transactionalEmailService.SendReminderEmail(customer);
}
...
}
}
It happens locally. We only started developing this feature to try NS' transactional emails.
Thank you very much for a informative message with lot of details!
I managed to replicate the issue when using a async controller like in your example, I also managed to get around it by not sending the emails using a new thread by adding a NotAsync() call when creating the request.
By default the service will fire of a new thread to send a email (kind of like fire and forget). This behavior might introduce problems if you send emails in a tight loop, but adding NotAsync() will send the email in a sequential way.
This code should work:
var res = _newsletterStudioService.SendTransactional(
SendTransactionalEmailRequest.Create(customer)
.SendTo(customer.Email)
.WithSubject(customer.Subject)
.NotAsync()
.Build());
I've uploaded my demo-project here so that you can verify that it works for you as well:
I've done everything in the same way as you are showing here (using MediatR etc) but also added .NotAsync(). Can you spot any difference between what you are doing and how this project works?
A couple of questions:
1.
I'm starting to wonder if this could be related to something about the project setup? Is this a "regular" Umbraco website? Do you have MVC referenced in the project? (It's a dependency to render the e-mails razor views). The error about IViewBufferScope that you posted indicates that the rendering pipeline can't access this dependency which is needed to render the e-mail.
2.
Do you have anything "special" inside the email content? Macros that does something fancy etc? If yes, let me know more details.
3.
Just to be sure, I'm assuming that the rendering works in the backoffice?
4.
You mention a "scheduled task" that calls this controller. What kind of scheduled task is this? The old Umbraco-concept of a scheduled task was removed in v9, do you use a background job, Hangfire or a Scheduled Task in Windows that call this endpoint, or how does it work?
EDIT:
I've also published a new version v10.0.14 where there is a check before trying to SuppressFlow on the ExecutionContext, this should mean that the call without NotAsync() should work as well.
Adding NotAsync() as per our instruction above still throws the error I mentioned earlier:
System.InvalidOperationException HResult=0x80131509 Message=Cannot
resolve scoped service
'Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers.IViewBufferScope' from
root provider. Source=Microsoft.Extensions.DependencyInjection
StackTrace: at
Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type
serviceType, IServiceScope scope, IServiceScope rootScope) at
Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type
serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
at
Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type
serviceType) at
Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider
provider, Type serviceType) at
Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider
provider) at
Microsoft.AspNetCore.Mvc.Razor.RazorView.
However, the upgrade to 10.0.14 fixed the issue and we can now send transactional emails in the loop.
I can't replicate the problem with the IOC not being able to resolve the IViewBufferScope dependency.
Did you try the solution that I provided?
Would be very helpful if you could take a minute or two and answer the numbered questions that might give me some insights into what is different/wrong here.
It's probably some kind of difference between a "vanilla umbraco project" and the project that you're running.
I'm happy to hear that the fixes in 10.0.14 made the synchronous approach work for you, since your sending as a background job this is probably acceptable since no user needs to wait for it.
I'll address your other issues in the other thread.
Transactional email in a loop not working
Can the transactional service handle sending transactional emails in a loop?
We are trying to send a transactional email to multiple customers:
Option 1
and then:
First email goes out and then the consecutive email fails with the error:
Option 2
If we try to execute it in async mode then the first email gets sent tout and the consecutive email hits the campaign service instead of the transactional.
and then:
Umbraco 10.8.3 NS 10.0.8
Hi!
Are you running this in a background job in some way?
I need to look closer at why you're getting the "Context flow is already suppressed."-error but a potential workaround for you is to force the sending to be sequential by chaining on the
.NotAsync()
call when building up theSendTransactionalEmailRequest
.Update your "Option 1" so look something like this:
Let me know if this works as a workaround for your problem?
Cheers!
Hi, No, it didn't help.
If I add
.NotAsync()
I am getting the following on the first send (no matter within async or sync method):Hi!
Can you explain more about your use case please?
Are you sending from inside a HTTP-request or are you doing this in some kind of background job? If not, are you using a async method to send?
Please explain the process so that I understand the context.
If you don't feel comfortable sharing inner details here, please reach out over email markus {at sign goes here} enkelmedia.se.
Hi Markus, It is an API call that calls the service where is the loop I quoted in my first post.
I tried both with async and without it.
Hi!
I need to understand the exact details around this, what do you mean with "API call"?
Where exactly are you hosting this code?
Is it a "regular" API Controller like this:
Could you provide some more exact details around how/where you are calling the service?
Are you using anything "special" framework? Minimal API, API Controllers? Fast Endpoints? Please provide as much details as possible so that I can replicate the issue.
The thing is that it looks like the
INewsletterStudioService
is used in context where the dependency injection container does not have a scope and the rendering engine is dependent on e.g.IViewBufferScope
which is a scoped dependency. The fact that the error says "....from root provider." indicates that there is something about the context is which the service is used that is causing the issue - that's why I need as much details as possible.Cheers!
Hi Markus, It is
UmbracoApiController
. It's a pretty basic call atm because we just started developing it.The controller action gets customer emails and then processes them in
foreach
loop that calls theITransactionalEmailService
and itsSendReminderEmail()
action, the one that I pasted initially. That's it.We have a scheduled task that runs the following action:
It happens locally. We only started developing this feature to try NS' transactional emails.
Not sure what else you wanna know?
I have simplified it for you so hopefully you'll be able to replicate it:
Controller:
Handler:
Model:
Service:
The transactional template exists in the BO with the
reminder
model selected.The above code hits the mentioned error on returning
SendTransactional
.The first email gets through and gets logged, but the following ones don't due to the error.
We now use NS version 10.0.13. The same error as in the version 10.0.8 persists.
Hi!
Thank you very much for a informative message with lot of details!
I managed to replicate the issue when using a async controller like in your example, I also managed to get around it by not sending the emails using a new thread by adding a
NotAsync()
call when creating the request.By default the service will fire of a new thread to send a email (kind of like fire and forget). This behavior might introduce problems if you send emails in a tight loop, but adding
NotAsync()
will send the email in a sequential way.This code should work:
I've uploaded my demo-project here so that you can verify that it works for you as well:
https://www.dropbox.com/scl/fi/hivl4d2fibvse5vorssk2/Umbraco-Newsletter-Studio-Transactional-Loop.zip?rlkey=w0icx4sanvk59k0o6mjzuxcy1&dl=0
I've done everything in the same way as you are showing here (using MediatR etc) but also added .NotAsync(). Can you spot any difference between what you are doing and how this project works?
A couple of questions:
1. I'm starting to wonder if this could be related to something about the project setup? Is this a "regular" Umbraco website? Do you have MVC referenced in the project? (It's a dependency to render the e-mails razor views). The error about
IViewBufferScope
that you posted indicates that the rendering pipeline can't access this dependency which is needed to render the e-mail.2. Do you have anything "special" inside the email content? Macros that does something fancy etc? If yes, let me know more details.
3. Just to be sure, I'm assuming that the rendering works in the backoffice?
4. You mention a "scheduled task" that calls this controller. What kind of scheduled task is this? The old Umbraco-concept of a scheduled task was removed in v9, do you use a background job, Hangfire or a Scheduled Task in Windows that call this endpoint, or how does it work?
EDIT:
I've also published a new version v10.0.14 where there is a check before trying to
SuppressFlow
on the ExecutionContext, this should mean that the call withoutNotAsync()
should work as well.https://www.nuget.org/packages/NewsletterStudio/10.0.14
Adding NotAsync() as per our instruction above still throws the error I mentioned earlier:
However, the upgrade to 10.0.14 fixed the issue and we can now send transactional emails in the loop.
We've detected other issues though, related to inserting a content link that I described here: https://our.umbraco.com/packages/backoffice-extensions/newsletter-studio-the-email-studio/comments//114081-issues-inserting-a-content-link-with-params-in-email-template
Hi!
I can't replicate the problem with the IOC not being able to resolve the
IViewBufferScope
dependency.Did you try the solution that I provided?
Would be very helpful if you could take a minute or two and answer the numbered questions that might give me some insights into what is different/wrong here.
It's probably some kind of difference between a "vanilla umbraco project" and the project that you're running.
I'm happy to hear that the fixes in 10.0.14 made the synchronous approach work for you, since your sending as a background job this is probably acceptable since no user needs to wait for it.
I'll address your other issues in the other thread.
/ Markus
is working on a reply...