ServiceStack / Issues

Issue Tracker for the commercial versions of ServiceStack
11 stars 8 forks source link

JsonApiClient exception handler throws unrelated System.FormatException unstead of the original exception #801

Closed quassnoi closed 10 months ago

quassnoi commented 10 months ago

Describe the issue

When the exception message is not a valid argument to String.Format, JsonApiClient can't format it and throws System.FormatException instead

Reproduction

main.csx

#nullable enable
#r "nuget: ServiceStack, 6.11.0"

using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using ServiceStack;
using ServiceStack.Messaging;

public class GoodException : Exception
{
    public GoodException() : base("This is a valid argument to String.Format") { }
}

public class BadException : Exception
{
    public BadException() : base("This is NOT a valid argument to String.Format: {") { }
}

public class GoodMessageHandler : HttpMessageHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        throw new GoodException();
    }
}

public class BadMessageHandler : HttpMessageHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        throw new BadException();
    }
}

try
{
    await new JsonApiClient(new HttpClient(new GoodMessageHandler())).SendAsync<object>("GET", "https://example.com", new { });
}
catch (GoodException ex)
{
    await Error.WriteLineAsync($"The exception is successfully caught: {ex.GetType().ToString()}");
    await Error.WriteLineAsync(ex.ToString());
}
await Error.WriteLineAsync();
try
{
    await new JsonApiClient(new HttpClient(new BadMessageHandler())).SendAsync<object>("GET", "https://example.com", new { });
}
catch (BadException ex)
{
    await Error.WriteLineAsync($"The exception is successfully caught: {ex.GetType().ToString()}");
    await Error.WriteLineAsync(ex.ToString());
}
catch (Exception ex)
{
    await Error.WriteLineAsync($"The exception is NOT caught, this is caught instead: {ex.GetType().ToString()}");
    await Error.WriteLineAsync(ex.ToString());
}

Run it:

dotnet tool -g install dotnet-script
dotnet script main.csx

Output:

The exception is successfully caught: Submission#0+GoodException
Submission#0+GoodException: This is a valid argument to String.Format
   at Submission#0.GoodMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) in ***\service-stack-bug\main.csx:line 24
   at System.Net.Http.HttpClient.<SendAsync>g__Core|83_0(HttpRequestMessage request, HttpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken)
   at ServiceStack.JsonApiClient.SendAsync[TResponse](String httpMethod, String absoluteUrl, Object request, Object dto, CancellationToken token) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Client/JsonApiClient.cs:line 320
   at Submission#0.<<Initialize>>d__0.MoveNext() in ***\service-stack-bug\main.csx:line 38

The exception is NOT caught, this is caught instead: System.FormatException
System.FormatException: Input string was not in a correct format.
   at System.Text.ValueStringBuilder.ThrowFormatInvalidString()
   at System.Text.ValueStringBuilder.AppendFormatHelper(IFormatProvider provider, String format, ReadOnlySpan`1 args)
   at System.String.FormatHelper(IFormatProvider provider, String format, ReadOnlySpan`1 args)
   at System.String.Format(String format, Object[] args)
   at ServiceStack.Logging.ILogWithExceptionExtensions.Error(ILog logger, Exception exception, String format, Object[] args) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Interfaces/Logging/ILogWithException.cs:line 122
   at ServiceStack.JsonApiClient.SendAsync[TResponse](String httpMethod, String absoluteUrl, Object request, Object dto, CancellationToken token) in /home/runner/work/ServiceStack/ServiceStack/ServiceStack/src/ServiceStack.Client/JsonApiClient.cs:line 339
   at Submission#0.<<Initialize>>d__0.MoveNext() in ***\service-stack-bug\main.csx:line 48

Expected behavior

I expected BadException to be caught

System Info

$ uname -a
Linux *** 5.15.90.1-microsoft-standard-WSL2 #1 SMP Fri Jan 27 02:56:13 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
$ dotnet --version
7.0.113

ServiceStack 6.11.0



### Additional context

The problems are here:

* https://github.com/ServiceStack/ServiceStack/blame/main/ServiceStack/src/ServiceStack.Client/JsonApiClient.cs#L339
* https://github.com/ServiceStack/ServiceStack/blame/main/ServiceStack/src/ServiceStack.Interfaces/Logging/ILogWithException.cs#L118

### Validations

- [X] Confirm [Issue is reproducible](https://github.com/ServiceStack/Issues#how-to-create-a-good-bug-report) from the information provided
- [X] Have an active commercial ServiceStack License _(GitHub Username is [registered on Support page](https://account.servicestack.net/account/support))_
mythz commented 10 months ago

This should be resolved in this commit.

You've checked that you have an commercial license but I can't find one associated with your GitHub Username, please ensure your GitHub Username is registered on your Support page before opening priority issues here. If you don't have an active commercial license you can report issues by signing the CLA and submitting a PR with either a failing test or fix.