Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to write a value of type StrongGrid.Models.MailPersonalization => The IJsonTypeInfoResolver returned a JsonTypeInfo instance whose JsonSerializerOptions setting does not match the provided argument #476

Closed
ken-swyfft opened this issue Nov 11, 2022 · 7 comments
Labels
Bug This change resolves a defect
Milestone

Comments

@ken-swyfft
Copy link

After upgrading from .NET 6 to .NET 7, we're getting the following error message(s) when trying to call client.Mail.SendAsync():

System.Exception: Unable to write a value of type StrongGrid.Models.MailPersonalization

System.Exception
Unable to write a value of type StrongGrid.Models.MailPersonalization
   at StrongGrid.Json.StrongGridJsonObjectConverter.WriteValue(Utf8JsonWriter writer, Object value, JsonSerializerOptions options)
   at StrongGrid.Json.StrongGridJsonObjectConverter.WriteValue(Utf8JsonWriter writer, Object value, JsonSerializerOptions options)
   at StrongGrid.Json.StrongGridJsonObjectConverter.Write(Utf8JsonWriter writer, StrongGridJsonObject value, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.WriteCoreAsObject(Utf8JsonWriter writer, Object value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.JsonSerializer.WriteCoreAsObject(Utf8JsonWriter writer, Object value, JsonTypeInfo jsonTypeInfo)
   at System.Text.Json.JsonSerializer.WriteStringAsObject(Object value, JsonTypeInfo jsonTypeInfo)
   at StrongGrid.Json.JsonFormatter.Serialize(Type type, Object value, Stream stream, HttpContent content, TransportContext transportContext)
   at Pathoschild.Http.Client.Formatters.MediaTypeFormatterBase.WriteToStreamAsync(Type type, Object value, Stream stream, HttpContent content, TransportContext transportContext)
--- End of stack trace from previous location ---
   at System.Net.Http.HttpContent.LoadIntoBufferAsyncCore(Task serializeToStreamTask, MemoryStream tempBuffer)
   at System.Net.Http.HttpContent.WaitAndReturnAsync[TState,TResult](Task waitTask, TState state, Func`2 returnFunc)
   at StrongGrid.Utilities.MaxRequestSizeFilter.OnRequest(IRequest request)
   at Pathoschild.Http.Client.Internal.Request.Execute()
   at StrongGrid.Resources.Mail.SendAsync(IEnumerable`1 personalizations, String subject, IEnumerable`1 contents, MailAddress from, IEnumerable`1 replyTo, IEnumerable`1 attachments, String templateId, IEnumerable`1 headers, IEnumerable`1 categories, IEnumerable`1 customArgs, Nullable`1 sendAt, String batchId, UnsubscribeOptions unsubscribeOptions, String ipPoolName, MailSettings mailSettings, TrackingSettings trackingSettings, MailPriority priority, CancellationToken cancellationToken)
   at Swyfft.Services.SendGrid.SendGridProxy.<>c__DisplayClass8_0.<<SendEmail>b__0>d.MoveNext() in C:\source\swyfft\Swyfft.Services\SendGrid\SendGridProxy.cs:line 152
--- End of stack trace from previous location ---
   at Swyfft.Common.Helpers.NumberHelpers.RetriesAsync[T](Int32 times, Func`2 action, Int32 pauseInMilliseconds, Func`2 retryIf) in C:\source\swyfft\Swyfft.Common\Helpers\NumberHelpers.cs:line 696
   at Swyfft.Services.SendGrid.SendGridProxy.SendEmail(MailMessage message, PolicyNumber policyNumber, String agentEmail) in C:\source\swyfft\Swyfft.Services\SendGrid\SendGridProxy.cs:line 149
   at Swyfft.Services.SendGrid.SendGridService.SendEmail(SwyfftMailMessage smm) in C:\source\swyfft\Swyfft.Services\SendGrid\SendGridService.cs:line 293
   at Swyfft.Services.SendGrid.SendGridService.SendAndSaveEmail(SwyfftMailMessage message) in C:\source\swyfft\Swyfft.Services\SendGrid\SendGridService.cs:line 154
   at Swyfft.Services.AcceptanceTests.Homeowner.EmailTests.SendGridServiceTests.SendEmail_VerifyAddAttachment() in C:\source\swyfft\Swyfft.Services.AcceptanceTests\Homeowner\EmailTests\SendGridServiceTests.cs:line 34
   at Xunit.Sdk.TestInvoker`1.<>c__DisplayClass48_0.<<InvokeTestMethodAsync>b__1>d.MoveNext() in /_/src/xunit.execution/Sdk/Frameworks/Runners/TestInvoker.cs:line 264
--- End of stack trace from previous location ---
   at Xunit.Sdk.ExecutionTimer.AggregateAsync(Func`1 asyncAction) in /_/src/xunit.execution/Sdk/Frameworks/ExecutionTimer.cs:line 48
   at Xunit.Sdk.ExceptionAggregator.RunAsync(Func`1 code) in /_/src/xunit.core/Sdk/ExceptionAggregator.cs:line 90

System.InvalidOperationException
The IJsonTypeInfoResolver returned a JsonTypeInfo instance whose JsonSerializerOptions setting does not match the provided argument.
   at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_ResolverTypeInfoOptionsNotCompatible()
   at System.Text.Json.Serialization.JsonSerializerContext.System.Text.Json.Serialization.Metadata.IJsonTypeInfoResolver.GetTypeInfo(Type type, JsonSerializerOptions options)
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoNoCaching(Type type)
   at System.Collections.Concurrent.ConcurrentDictionary`2.GetOrAdd(TKey key, Func`2 valueFactory)
   at System.Text.Json.JsonSerializerOptions.GetTypeInfoInternal(Type type, Boolean ensureConfigured, Boolean resolveIfMutable)
   at System.Text.Json.JsonSerializer.GetTypeInfo(JsonSerializerOptions options, Type inputType)
   at System.Text.Json.JsonSerializer.Serialize(Utf8JsonWriter writer, Object value, Type inputType, JsonSerializerOptions options)
   at StrongGrid.Json.BaseJsonConverter`1.WriteJsonProperty(Utf8JsonWriter writer, String propertyName, Object propertyValue, Type propertyType, JsonSerializerOptions options, JsonConverterAttribute propertyConverterAttribute)
   at StrongGrid.Json.MailPersonalizationConverter.<>c__DisplayClass1_0.<Write>b__0(String propertyName, Object propertyValue, Type propertyType, JsonSerializerOptions options, JsonConverterAttribute propertyConverterAttribute)
   at StrongGrid.Json.BaseJsonConverter`1.Serialize(Utf8JsonWriter writer, T value, JsonSerializerOptions options, Action`5 propertySerializer)
   at StrongGrid.Json.MailPersonalizationConverter.Write(Utf8JsonWriter writer, MailPersonalization value, JsonSerializerOptions options)
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.WriteCore(Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.Serialization.JsonConverter`1.WriteCoreAsObject(Utf8JsonWriter writer, Object value, JsonSerializerOptions options, WriteStack& state)
   at System.Text.Json.JsonSerializer.WriteCore[TValue](Utf8JsonWriter writer, TValue& value, JsonTypeInfo`1 jsonTypeInfo)
   at System.Text.Json.JsonSerializer.Serialize[TValue](Utf8JsonWriter writer, TValue value, JsonSerializerOptions options)
   at StrongGrid.Json.StrongGridJsonObjectConverter.WriteValue(Utf8JsonWriter writer, Object value, JsonSerializerOptions options)

I haven't yet put together a shareable repro, but this is the code we're using to make the call:

    public async Task SendEmail(MailMessage message, PolicyNumber? policyNumber = null, string agentEmail = "")
    {
        CheckPermission();

        var client = new Client(_sendGridKey);
        var sendGridMessage = new SendGridMessage(message, policyNumber, agentEmail);
        var from = FixEnding(sendGridMessage.From);
        var replyTo = new List<MailAddress>();
        if (sendGridMessage.ReplyTo is not null)
        {
            replyTo.Add(sendGridMessage.ReplyTo);
        }

        await 5.RetriesAsync(
            async x =>
            {
                var unused = await client.Mail.SendAsync(
                    sendGridMessage.Personalizations,
                    message.Subject,
                    sendGridMessage.Contents,
                    from,
                    replyTo,
                    sendGridMessage.Attachments,
                    categories: sendGridMessage.Categories);
                return 0;
            },
            // ks 4/13/19 - The message here seems to vary. But effectively, we want to retry only if there was an error MAKING the HTTP request,
            // not in the post-processing - because if we retry due to an error in the latter, we can send the same email 5 times, which nobody likes.
            retryIf: ex => ex is HttpRequestException or WebException || ex.Message.ContainsNoCase("589"));
    }
@ken-swyfft
Copy link
Author

ken-swyfft commented Nov 11, 2022

FWIW, this little bit in Program.cs reproduces the problem. It seems to be the MailPersonalization.CustomArguments that is the issue - comment that stuff out and it'll work without an error:

using StrongGrid;
using StrongGrid.Models;
using MailAddress = StrongGrid.Models.MailAddress;

const string sendGridKey = "your sendgrid key";

Console.WriteLine("Sending email...");

var client = new Client(sendGridKey);
var personalization = new MailPersonalization
{
    To = new[] { new MailAddress("smithkl42@gmail.com", "Ken Smith") },
    CustomArguments = new KeyValuePair<string, string>[]
    {
        new ("PolicyNumber", "some policy number"),
        new ("PolicyHolder", "some email address"),
    },
};

var contents = new List<MailContent>
{
    new("text/plain", "Hello plain world!"),
};

var result = await client.Mail.SendAsync(new List<MailPersonalization> { personalization },
    "Test Subject",
    contents,
    new MailAddress("ken@swyfft.com", "Ken Smith"),
    new List<MailAddress> { new("ken@swyfft.com", "Ken Smith") }
);

Console.WriteLine($"Sent email: {result}");
Console.ReadLine();

@Jericho
Copy link
Owner

Jericho commented Nov 11, 2022

Thanks for reporting this and for the additional information. I'll look into it this weekend and report back what I find.

@Jericho
Copy link
Owner

Jericho commented Nov 12, 2022

I still can't explain why this problem is occurring, but I can confirm that I am able to reproduce it when I create a new .net7 console app and reference the latest StrongGrid package from NuGet (which, by the way, targets .net5 and .net6). Is the problem related to some quirk when referencing a .net6 library from a .net7 project?

Maybe this is an argument in favor of expediting #463?

So far, I already faced (and fixed) one serialization problem caused by a change introduced in .net7 (explanation here, I fixed it here). This might be another similar situation.

I'm continuing my research...

@Jericho
Copy link
Owner

Jericho commented Nov 13, 2022

I found the culprit and I know how to fix the issue, but I still can't explain why this problem occurs only when our library targets .net6 and it's used in a .net7 application.

An update should be available on NuGet tomorrow.

@Jericho
Copy link
Owner

Jericho commented Nov 13, 2022

🎉 This issue has been resolved in version 0.95.1 🎉

The release is available on:

Your GitReleaseManager bot 📦🚀

@ken-swyfft
Copy link
Author

ken-swyfft commented Nov 14, 2022

I found the culprit and I know how to fix the issue, but I still can't explain why this problem occurs only when our library targets .net6 and it's used in a .net7 application.

An update should be available on NuGet tomorrow.

Thank you so much! I tested out the update in our solution, and it's resolved the problem.

@Jericho
Copy link
Owner

Jericho commented Nov 14, 2022

Excellent! Thank you for confirming.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug This change resolves a defect
Projects
None yet
Development

No branches or pull requests

2 participants