Skip to content

Commit ff188d5

Browse files
committed
AOT wans sample
1 parent 3662a0b commit ff188d5

4 files changed

Lines changed: 405 additions & 2 deletions

File tree

AOT-Sample/AOT-Sample.csproj

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
9+
<!-- Enable AOT compilation -->
10+
<PublishAot>true</PublishAot>
11+
12+
<!-- Enable trimming -->
13+
<PublishTrimmed>true</PublishTrimmed>
14+
<TrimMode>full</TrimMode>
15+
16+
<!-- Enable all AOT and trim warnings -->
17+
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
18+
<EnableAotAnalyzer>true</EnableAotAnalyzer>
19+
<TreatWarningsAsErrors>false</TreatWarningsAsErrors>
20+
21+
<!-- Additional AOT and trim settings -->
22+
<SuppressTrimAnalysisWarnings>false</SuppressTrimAnalysisWarnings>
23+
<EnableSingleFileAnalyzer>true</EnableSingleFileAnalyzer>
24+
<IsAotCompatible>true</IsAotCompatible>
25+
26+
<!-- More detailed trim warnings -->
27+
<TrimmerSingleWarn>false</TrimmerSingleWarn>
28+
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
29+
30+
<!-- ILC flags for more detailed output -->
31+
<IlcInstructionSet></IlcInstructionSet>
32+
<IlcFoldIdenticalMethodBodies>false</IlcFoldIdenticalMethodBodies>
33+
34+
<!-- Enable detailed ILC diagnostic output -->
35+
<IlcDiagnosticFile>$(OutputPath)IlcDiagnostics.txt</IlcDiagnosticFile>
36+
<IlcDisableReflection>false</IlcDisableReflection>
37+
38+
<!-- Detailed AOT warnings -->
39+
<_SuppressIlcGeneratedFileMessage>false</_SuppressIlcGeneratedFileMessage>
40+
</PropertyGroup>
41+
42+
<ItemGroup>
43+
<PackageReference Include="Microsoft.Azure.Cosmos" Version="3.44.0" />
44+
</ItemGroup>
45+
46+
<!-- Enable this to see the entire AOT warns from Microsoft.Azure.Cosmos.Client, not just the apis used by the sample -->
47+
<!--
48+
<ItemGroup>
49+
<TrimmerRootAssembly Include="Microsoft.Azure.Cosmos.Client" />
50+
</ItemGroup>
51+
-->
52+
53+
</Project>

AOT-Sample/Program.cs

Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
namespace AOTSample
2+
{
3+
using System;
4+
using System.Text.Json;
5+
using Microsoft.Azure.Cosmos;
6+
7+
public class Program
8+
{
9+
public static async Task Main(string[] args)
10+
{
11+
const string CosmosBaseUri = "https://{0}.documents.azure.com:443/";
12+
string accountName = "cosmosaot2";
13+
string? primaryKey = Environment.GetEnvironmentVariable("KEY");
14+
Console.WriteLine($"COSMOS_PRIMARY_KEY: {primaryKey}");
15+
16+
if (string.IsNullOrEmpty(primaryKey))
17+
{
18+
Console.WriteLine("ERROR: KEY environment variable is not set");
19+
return;
20+
}
21+
22+
CosmosClientOptions clientOptions = new CosmosClientOptions { AllowBulkExecution = true };
23+
clientOptions.CosmosClientTelemetryOptions.DisableDistributedTracing = false;
24+
25+
CosmosClient client = new CosmosClient(
26+
string.Format(CosmosBaseUri, accountName),
27+
primaryKey,
28+
clientOptions);
29+
30+
FeedIterator<DatabaseProperties> db_feed_itr = client.GetDatabaseQueryIterator<DatabaseProperties>();
31+
while (db_feed_itr.HasMoreResults)
32+
{
33+
FeedResponse<DatabaseProperties> db_response = await db_feed_itr.ReadNextAsync();
34+
foreach (DatabaseProperties db_properties in db_response)
35+
{
36+
Console.WriteLine($"Database: {db_properties.Id}");
37+
38+
Database database = client.GetDatabase(db_properties.Id);
39+
FeedIterator<ContainerProperties> container_feed_itr = database.GetContainerQueryIterator<ContainerProperties>();
40+
41+
while (container_feed_itr.HasMoreResults)
42+
{
43+
FeedResponse<ContainerProperties> container_response = await container_feed_itr.ReadNextAsync();
44+
foreach (ContainerProperties container_properties in container_response)
45+
{
46+
Console.WriteLine($"Container: {container_properties.Id}");
47+
48+
Console.WriteLine($"Container PartitionKeyPath: {container_properties.PartitionKeyPath}");
49+
if (container_properties.PartitionKeyPaths != null && container_properties.PartitionKeyPaths.Count > 0)
50+
{
51+
Console.WriteLine($"Container PartitionKeyPaths: [{string.Join(", ", container_properties.PartitionKeyPaths)}]");
52+
}
53+
54+
Container container = client.GetContainer(db_properties.Id, container_properties.Id);
55+
56+
String itemsQuery = "SELECT * FROM c";
57+
QueryDefinition itemsQueryDef = new QueryDefinition(itemsQuery);
58+
59+
FeedIterator queryIterator = container.GetItemQueryStreamIterator(
60+
itemsQueryDef,
61+
requestOptions: new QueryRequestOptions { MaxItemCount = -1 }
62+
);
63+
64+
while (queryIterator.HasMoreResults)
65+
{
66+
ResponseMessage response = await queryIterator.ReadNextAsync();
67+
68+
if (response.Content == null)
69+
{
70+
Console.WriteLine("QueryResponse.Content is null");
71+
continue;
72+
}
73+
if (response.Content.CanSeek && response.Content.Length == 0)
74+
{
75+
Console.WriteLine("QueryResponse.Content stream is empty");
76+
continue;
77+
}
78+
79+
try
80+
{
81+
using JsonDocument itemsQueryResultDoc = JsonDocument.Parse(response.Content);
82+
Console.WriteLine($"Raw JSON (Query result): {itemsQueryResultDoc.RootElement.GetRawText()}");
83+
84+
if (itemsQueryResultDoc.RootElement.TryGetProperty("Documents", out JsonElement documentsElement))
85+
{
86+
foreach (JsonElement item in documentsElement.EnumerateArray())
87+
{
88+
string itemId = ExtractItemId(item);
89+
PartitionKey itemPartitionKey = CreatePartitionKey(item, container_properties.PartitionKeyPath);
90+
Console.WriteLine($"Item PartitionKey: {itemPartitionKey}");
91+
92+
try
93+
{
94+
ItemResponse<JsonElement> itemResponse = await container.ReadItemAsync<JsonElement>(
95+
id: itemId,
96+
partitionKey: itemPartitionKey,
97+
requestOptions: new ItemRequestOptions
98+
{
99+
// EnableContentResponseOnWrite = false,
100+
}
101+
);
102+
103+
Console.WriteLine($"Raw JSON (Read item result): {itemResponse.Resource.GetRawText()}");
104+
}
105+
catch (CosmosException ex) when (ex.StatusCode == System.Net.HttpStatusCode.NotFound)
106+
{
107+
Console.WriteLine("ReadItemAsync: Item not found");
108+
}
109+
catch (CosmosException ex)
110+
{
111+
Console.WriteLine($"ReadItemAsync: Error reading. {ex.Message}");
112+
}
113+
}
114+
}
115+
else
116+
{
117+
Console.WriteLine($"Raw JSON: {itemsQueryResultDoc.RootElement.GetRawText()}");
118+
}
119+
}
120+
catch (JsonException ex)
121+
{
122+
Console.WriteLine($"JsonException: {ex.Message}");
123+
}
124+
}
125+
}
126+
}
127+
}
128+
}
129+
}
130+
131+
private static string ExtractItemId(JsonElement item)
132+
{
133+
return item.TryGetProperty("id", out JsonElement idElement)
134+
? idElement.GetString() ?? "unknown"
135+
: "unknown";
136+
}
137+
138+
private static PartitionKey CreatePartitionKey(JsonElement jsonElement, string? partitionKeyPath)
139+
{
140+
if (string.IsNullOrEmpty(partitionKeyPath))
141+
{
142+
return PartitionKey.Null;
143+
}
144+
145+
string[] pathParts = partitionKeyPath.TrimStart('/').Split('/');
146+
147+
JsonElement currentElement = jsonElement;
148+
foreach (string part in pathParts)
149+
{
150+
if (currentElement.TryGetProperty(part, out JsonElement nextElement))
151+
{
152+
currentElement = nextElement;
153+
}
154+
else
155+
{
156+
// Property not found, return null partition key
157+
return PartitionKey.Null;
158+
}
159+
}
160+
161+
return currentElement.ValueKind switch
162+
{
163+
JsonValueKind.String => new PartitionKey(currentElement.GetString() ?? string.Empty),
164+
JsonValueKind.Number => currentElement.TryGetInt32(out int intValue)
165+
? new PartitionKey((double)intValue)
166+
: new PartitionKey(currentElement.GetDouble()),
167+
JsonValueKind.True => new PartitionKey(true),
168+
JsonValueKind.False => new PartitionKey(false),
169+
JsonValueKind.Null => PartitionKey.Null,
170+
_ => new PartitionKey(currentElement.GetRawText())
171+
};
172+
}
173+
}
174+
}

AOT-Sample/README.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Azure Cosmos DB .NET AOT Sample
2+
3+
This is a sample console application demonstrating how to use the Microsoft.Azure.Cosmos SDK with Native AOT compilation in .NET 9.
4+
5+
## Features
6+
7+
- ? **Native AOT Compilation** - Compiles to a self-contained native executable
8+
- ? **Full Trimming** - Uses aggressive IL trimming for smaller size
9+
- ? **AOT & Trim Analysis** - All AOT and trim analyzers enabled
10+
- ? **Azure Cosmos DB Integration** - Uses Microsoft.Azure.Cosmos NuGet package
11+
- ?? **Dependency Warnings Suppressed** - Known AOT warnings from dependencies are suppressed
12+
13+
## Project Configuration
14+
15+
Key settings for AOT compatibility:
16+
17+
```xml
18+
<PublishAot>true</PublishAot>
19+
<PublishTrimmed>true</PublishTrimmed>
20+
<TrimMode>full</TrimMode>
21+
<EnableTrimAnalyzer>true</EnableTrimAnalyzer>
22+
<EnableAotAnalyzer>true</EnableAotAnalyzer>
23+
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
24+
<IsAotCompatible>true</IsAotCompatible>
25+
```
26+
27+
## Build & Run
28+
29+
### Debug Build
30+
```bash
31+
dotnet build
32+
dotnet run
33+
```
34+
35+
### AOT Release Build
36+
```bash
37+
dotnet publish -c Release
38+
# Run the native executable
39+
./bin/Release/net9.0/win-arm64/publish/AOT-Sample.exe
40+
```
41+
42+
## Known Limitations
43+
44+
The current Microsoft.Azure.Cosmos SDK (3.44.0) has some AOT/trim warnings that are suppressed:
45+
46+
- **IL2104**: Trim warnings from dependencies
47+
- **IL3000**: Single-file app compatibility issues
48+
- **IL3053**: AOT analysis warnings
49+
50+
These warnings are from dependencies (Newtonsoft.Json, System.Configuration.ConfigurationManager, etc.) and don't affect the basic functionality.
51+
52+
## File Size
53+
54+
The compiled native executable is approximately **26.76 MB** and includes the entire .NET runtime and Cosmos SDK.
55+
56+
## Next Steps
57+
58+
To build a production-ready AOT application with Cosmos DB:
59+
60+
1. Use real connection strings and endpoints
61+
2. Implement proper error handling
62+
3. Consider using System.Text.Json instead of Newtonsoft.Json for better AOT compatibility
63+
4. Test thoroughly with your specific Cosmos DB operations

0 commit comments

Comments
 (0)