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

GetObject not working with NativeAOT #58

Open
1 task
ivanjx opened this issue Aug 5, 2023 · 3 comments
Open
1 task

GetObject not working with NativeAOT #58

ivanjx opened this issue Aug 5, 2023 · 3 comments
Labels
bug Something isn't working

Comments

@ivanjx
Copy link

ivanjx commented Aug 5, 2023

  • I hereby verify that I am a sponsor.

Description of the bug
PutObject works fine under NativeAOT but when i tried to get the file back with GetObject it gives me an empty stream instead. I manually verified that the PutObject works fine on both normal and AOT mode by downloading and checking the file myself.

How to reproduce?

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <PublishAot>true</PublishAot>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Genbox.SimpleS3.AmazonS3" Version="3.0.0" />
  </ItemGroup>

</Project>
using System.Text;
using Genbox.SimpleS3.AmazonS3;
using Genbox.SimpleS3.Core.Abstracts.Enums;
using Genbox.SimpleS3.Core.Common.Authentication;
using Genbox.SimpleS3.Core.Extensions;
using Genbox.SimpleS3.Core.Network.Responses.Objects;
using Genbox.SimpleS3.Extensions.AmazonS3;

AmazonS3Config config = new AmazonS3Config();
config.EndpointTemplate = "{Scheme}://play.min.io/{Bucket}";
config.Region = AmazonS3Region.UsEast1;
config.Credentials = new StringAccessKey("1nM2dy8VWatJ7EJ4nEBg", "CPeDvsHZA12kvcMXc6GJzdb6bIKo5FScCsYKKdgL");
config.NamingMode = NamingMode.PathStyle;

using AmazonS3Client client = new AmazonS3Client(config);
using MemoryStream dataStream = new MemoryStream(
    Encoding.ASCII.GetBytes("Hello World!! + " + DateTime.UtcNow.ToString("o")));
PutObjectResponse resp = await client.PutObjectAsync(
    "testbucket",
    "objectname22",
    dataStream);

GetObjectResponse resp2 = await client.GetObjectAsync("testbucket", "objectname22");
using StreamReader reader = new StreamReader(resp2.Content);
Console.WriteLine("Content: [{0}]", await reader.ReadToEndAsync());


Console.WriteLine("Success: " + resp.IsSuccess);

compile with: dotnet publish -c Release

normal output:

Content: [Hello World!! + 2023-08-05T04:00:19.6423971Z]
Success: True

NativeAOT output:

Content: []
Success: True

Expected behavior
GetObject's Content has data in it.

@ivanjx ivanjx added the bug Something isn't working label Aug 5, 2023
@ivanjx
Copy link
Author

ivanjx commented Aug 5, 2023

there is a workaround though by using the SignObject method:

...
string url = client.SignGetObject("testbucket", "objectname22", TimeSpan.FromMinutes(1));
Console.WriteLine("Url: {0}", url);
using HttpClient http = new HttpClient();
using Stream resp2Data = await http.GetStreamAsync(url);
using StreamReader reader2 = new StreamReader(resp2Data);
Console.WriteLine("Content Stream: [{0}]", await reader2.ReadToEndAsync());
...
Content: []
Url: https://play.min.io/testbucket/objectname22?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=1nM2dy8VWatJ7EJ4nEBg%2F20230805%2Fus-east-1%2Fs3%2Faws4_request&X-Amz-Date=20230805T041311Z&X-Amz-Expires=60&X-Amz-SignedHeaders=host&X-Amz-Signature=e1f575228ce0bcb0aae4d713bc620ad2ecc2f926f8221ed7955dc7382cd94298
Content Stream: [Hello World!! + 2023-08-05T04:13:10.2145266Z]
Success: True

@Genbox
Copy link
Owner

Genbox commented Aug 5, 2023

Interesting. I'll try and debug it once I get the time for it.

@Genbox
Copy link
Owner

Genbox commented Aug 13, 2023

I've taken a look at it now. There are several issues:

  1. RequestMarshal, ResponseMarshal, and PostMappers are matched via reflection. AOT removes all the unused types, so the marshallers are not registered.
  2. Profiles are serialized via JSON. AOT removes unused public constructors from types, so serialization does not work.
  3. Dependency injection uses dynamic code emitting. Currently, I'm using DI internally to ease the setup of clients.

Other potential problems:

  • Enums are handled via reflection and cached.
  • ObjectPool requires calling public ctors that gets removed

I've tried to root all assemblies, which should remove the trimming issues, but the application still crash - likely due to RequestMarshal being setup via DI.

So for the moment, NativeAOT is not supported by SimpleS3.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants