Closed perason closed 4 years ago
Hi,
It would be good to know which version of SmartFormat
and which SmartSettings
you are using. Assuming the latest v2.5.0 with default SmartSettings
, your snippets compiled to a working sample do their job as expected. So I couldn't preproduce the described behavior.
See the working sample below.
namespace Play
{
/// <summary>
/// Using DotNet Core 3.1 console application and SmartFormat 2.5.0
/// </summary>
public static class PerasonIssue127
{
public static void Test()
{
var bidJson = @"{
'Auction': 'Skogen min',
'ItemProductId': 'BF-snartvårkjenning',
'ItemId': 1250,
'Date': '2020-04-03T22:44:36.9333205+02:00',
'Value': '8000',
'Comment': 'Hej Nina. Testar att epostbekräftelse fungerar.',
'AcceptTerms': true,
'Firstname': 'Per',
'Lastname': 'Bykom',
'Company': 'Bykom',
'Phone': '123456',
'Email': 'per.andersson@email.no',
'Id': 0,
'CreateDate': '0001-01-01T00:00:00',
'EditDate': '0001-01-01T00:00:00',
'EditBy': null,
'Owner': null,
'Deleted': false,
'Deactivated': false,
'PublishedState': 0,
'Published': false,
'PublishSite': null,
'PublishStartDate': '0001-01-01T00:00:00',
'PublishStopDate': '0001-01-01T00:00:00',
'Category': null,
'SubCategory': null
}";
var bid = JsonConvert.DeserializeObject<Bid>(bidJson);
Console.WriteLine(SmartFormat.Smart.Format("Navn: {Firstname} {Lastname} {Company:({Company})|}\nTlf/Epost: {Phone} / {Email}\nVerk/Bud: {ItemProductId} / {Value}\nVeldedig formål: {Comment}", bid));
/*
* Output as expected is:
Navn: Per Bykom (Bykom)
Tlf/Epost: 123456 / per.andersson@email.no
Verk/Bud: BF-snartvårkjenning / 8000
Veldedig formål: Hej Nina. Testar att epostbekräftelse fungerar.
*/
}
}
public class MyModels
{
public int Id { get; set; }
public DateTime CreateDate { get; set; }
public DateTime EditDate { get; set; }
public string EditBy { get; set; }
public string Owner { get; set; }
public bool Deleted { get; set; }
public bool Deactivated { get; set; }
public int PublishedState { get; set; }
public bool Published { get; set; }
public string PublishSite { get; set; }
public DateTime PublishStartDate { get; set; }
public DateTime PublishStopDate { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
}
public class Bid : MyModels
{
public string Auction { get; set; }
public string ItemProductId { get; set; }
public int ItemId { get; set; }
public DateTime Date { get; set; }
public string Value { get; set; }
public string Comment { get; set; }
public bool AcceptTerms { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Company { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
}
}
Hi, and thanks for reply.
I use the latest version, 2.5.0, and default settings.
One thing though, I wrapped it in a "fire-and-forget", where it emails the output, like this:
Task.Run(async () =>
{
await Emailer.SendSimpleAsync(RequestSettings, AppSettings, HttpContext, "Auction",
"Bud gitt",
Smart.Format("Navn: {Firstname} {Lastname} {Company:({Company})|}\nTlf/Epost: {Phone} / {Email}\nVerk/Bud: {ItemProductId} / {Value}\nVeldedig formål: {Comment}", bid)
);
}).Forget();
And here's the Forget
extension method:
public static void Forget(this Task task)
{
if (!task.IsCompleted || task.IsFaulted)
{
_ = ForgetAwaited(task);
}
async static Task ForgetAwaited(Task task)
{
try
{
await task.ConfigureAwait(false);
}
catch
{
// Nothing to do here
}
}
}
Running our sample async
will not make a difference. Give it a try.
My best guest for further investigations is to have a look at your catch
block, which is discarding all exceptions. Are you sure there's no exception thrown?
No, I added a logging to that catch
and no exceptions is thrown.
I did some more testing and when not using Task.Run
it works properly every time, so something appears to go on when it is pushed to another thread.
Please run the following sync
and async
code on your machine in an dotnet core 3.1 console application and let us know whether you still experience the problem. As long as we can't reproduce, it's hard to help.
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace Play
{
/// <summary>
/// Using DotNet Core 3.1 console application and SmartFormat 2.5.0
/// </summary>
public static class PerasonIssue127
{
public async static Task Test()
{
var bidJson = @"{
'Auction': 'Skogen min',
'ItemProductId': 'BF-snartvårkjenning',
'ItemId': 1250,
'Date': '2020-04-03T22:44:36.9333205+02:00',
'Value': '8000',
'Comment': 'Hej Nina. Testar att epostbekräftelse fungerar.',
'AcceptTerms': true,
'Firstname': 'Per',
'Lastname': 'Bykom',
'Company': 'Bykom',
'Phone': '123456',
'Email': 'per.andersson@email.no',
'Id': 0,
'CreateDate': '0001-01-01T00:00:00',
'EditDate': '0001-01-01T00:00:00',
'EditBy': null,
'Owner': null,
'Deleted': false,
'Deactivated': false,
'PublishedState': 0,
'Published': false,
'PublishSite': null,
'PublishStartDate': '0001-01-01T00:00:00',
'PublishStopDate': '0001-01-01T00:00:00',
'Category': null,
'SubCategory': null
}";
var bid = JsonConvert.DeserializeObject<Bid>(bidJson);
Console.WriteLine("SYNC:\n");
Console.WriteLine(SmartFormat.Smart.Format("Navn: {Firstname} {Lastname} {Company:({Company})|}\nTlf/Epost: {Phone} / {Email}\nVerk/Bud: {ItemProductId} / {Value}\nVeldedig formål: {Comment}", bid));
/*
* Output:
Navn: Per Bykom (Bykom)
Tlf/Epost: 123456 / per.andersson@email.no
Verk/Bud: BF-snartvårkjenning / 8000
Veldedig formål: Hej Nina. Testar att epostbekräftelse fungerar.
*/
Console.WriteLine("ASYNC:\n");
var result = await Task.Run(async () =>
{
var bid2 = JsonConvert.DeserializeObject<Bid>(bidJson);
await Task.Delay(1000).ConfigureAwait(false);
return SmartFormat.Smart.Format("Navn: {Firstname} {Lastname} {Company:({Company})|}\nTlf/Epost: {Phone} / {Email}\nVerk/Bud: {ItemProductId} / {Value}\nVeldedig formål: {Comment}", bid2);
}).ConfigureAwait(false);
Console.WriteLine(result);
/*
* Output:
Navn: Per Bykom (Bykom)
Tlf/Epost: 123456 / per.andersson@email.no
Verk/Bud: BF-snartvårkjenning / 8000
Veldedig formål: Hej Nina. Testar att epostbekräftelse fungerar.
*/
}
}
public class MyModels
{
public int Id { get; set; }
public DateTime CreateDate { get; set; }
public DateTime EditDate { get; set; }
public string EditBy { get; set; }
public string Owner { get; set; }
public bool Deleted { get; set; }
public bool Deactivated { get; set; }
public int PublishedState { get; set; }
public bool Published { get; set; }
public string PublishSite { get; set; }
public DateTime PublishStartDate { get; set; }
public DateTime PublishStopDate { get; set; }
public string Category { get; set; }
public string SubCategory { get; set; }
}
public class Bid : MyModels
{
public string Auction { get; set; }
public string ItemProductId { get; set; }
public int ItemId { get; set; }
public DateTime Date { get; set; }
public string Value { get; set; }
public string Comment { get; set; }
public bool AcceptTerms { get; set; }
public string Firstname { get; set; }
public string Lastname { get; set; }
public string Company { get; set; }
public string Phone { get; set; }
public string Email { get; set; }
}
}
Could you verify the result of the code above?
The above code works, just as mine does, when not using Task.Run
.
The big difference is how we call Task.Run
, where I don't await mine. I want mine to be a "fire-and-forget", so I don't have to wait the email method to finish.
After some further tests, I got mine to fail for the built-in "string interpolation" as well, but not when storing the result in a variable prior to calling Task:Run
(using either Smart.Format or the built-in) and then use the variable inside the Task.Run
block.
So I guess that when my Task.Run
finally runs, the bid
object partially lost some of its property values.
For now I use the workaround adding the formatted result to a variable, and when I get som time I will test your way, using an awaited Task.Run
.
Okay, now it's clear. Your Forget
method might not be finished when the calling task will terminate. I could simulate this in a console application.
Task.Run(async () =>
{
await Task.Delay(20).ConfigureAwait(false); // send email
var bid = JsonConvert.DeserializeObject<Bid>(bidJson);
var result = SmartFormat.Smart.Format("Navn: {Firstname} {Lastname} {Company:({Company})|}\nTlf/Epost: {Phone} / {Email}\nVerk/Bud: {ItemProductId} / {Value}\nVeldedig formål: {Comment}", bid);
Console.WriteLine("FROM FORGET");
Console.WriteLine(result);
}).Forget();
If there is a Task.Delay(x)
after calling the Forget
Method, the output is complete, when x > 300 (on my machine). If it is shorter, all or part of the output will be missing.
I'm afraid this is all I can contribute here.
Is there something new to reproduce the described behavior or should we close the issue?
Given that I now know the issue has nothing to do with SmartFormat, please feel free to delete this complete post.
And again, thanks a lot for both your help and a great library.
Hi.
I am posting a form and resolve its fields to an object of type
Bid
(see classes at the end).When I run the following code snippet:
At line 3 and 4 the
{Value}
and{Comment}
values are missing.When I use built-in string interpolation it works just fine:
When serializing the
bid
object, one can see they both existsMy project is a ASP.NET Core 3.1 (v. 3.1.3/SDK 3.1.201) web application and this is how the classes looks like