Forge.OData.Client
0.1.0
See the version list below for details.
dotnet add package Forge.OData.Client --version 0.1.0
NuGet\Install-Package Forge.OData.Client -Version 0.1.0
<PackageReference Include="Forge.OData.Client" Version="0.1.0" />
<PackageVersion Include="Forge.OData.Client" Version="0.1.0" />
<PackageReference Include="Forge.OData.Client" />
paket add Forge.OData.Client --version 0.1.0
#r "nuget: Forge.OData.Client, 0.1.0"
#:package Forge.OData.Client@0.1.0
#addin nuget:?package=Forge.OData.Client&version=0.1.0
#tool nuget:?package=Forge.OData.Client&version=0.1.0
Forge.OData.Client
Your project needs to connect to an OData service? Just point our CLI at the endpoint, and everything gets generated for youβmodels, client, type-safe queries. No manual work. No boilerplate. Just instant OData integration.
β‘ Quick Start
1. Install the CLI Tool
dotnet tool install --global Forge.OData.CLI
2. Add an OData Client to Your Project
Navigate to your project and run:
dotnet odata add --endpoint https://services.odata.org/V4/TripPinServiceRW
3. Build and Code
dotnet build
That's it! You now have a fully functional, type-safe OData client ready to use:
using var httpClient = new HttpClient();
var client = new TripPinServiceRWClient(httpClient);
// Query with LINQ - it just works!
var people = await client.People
.Where(p => p.FirstName.StartsWith("R"))
.OrderBy(p => p.LastName)
.Take(10)
.ToListAsync();
foreach (var person in people)
{
Console.WriteLine($"{person.FirstName} {person.LastName}");
}
π― Why Forge.OData.Client?
Stop writing boilerplate. Stop manually creating DTOs. Stop fighting with HTTP requests and JSON parsing.
You have an OData API. You want to use it. The OData CLI does the heavy lifting:
- β Downloads the metadata from your OData service
- β Generates all model classes with proper types and attributes
- β Creates a type-safe client with IntelliSense support
- β Translates LINQ to OData queries automatically
- β Handles JSON serialization with optimized converters
All this happens during your normal dotnet build. No runtime reflection. No performance overhead.
π¦ Installation
Install the Forge OData CLI as a global tool:
dotnet tool install --global Forge.OData.CLI
Or install it locally in your project for team consistency:
dotnet new tool-manifest # if you don't have one already
dotnet tool install --local Forge.OData.CLI
π Usage Examples
Basic Usage: Connect to Any OData Service
# Simple: Just provide the endpoint
dotnet odata add --endpoint https://services.odata.org/V4/Northwind/Northwind.svc
The CLI will:
- Download the
$metadatafrom the endpoint - Generate a client class named
NorthwindClient(derived from URL) - Create all model classes for entities (Products, Orders, Customers, etc.)
- Configure your project automatically
Custom Client Name
# Give your client a meaningful name
dotnet odata add \
--endpoint https://api.example.com/odata \
--client-name CompanyDataService
Now you'll have a CompanyDataService class instead of a generic name.
Organize Clients in Subdirectories
# Keep your OData clients organized
dotnet odata add \
--endpoint https://api.example.com/odata \
--client-name InventoryService \
--output-path Services/OData
This creates:
- File:
Services/OData/InventoryService.cs - Namespace:
YourProject.Services.OData
Custom Namespace
# Control the namespace for better organization
dotnet odata add \
--endpoint https://api.example.com/odata \
--client-name ProductCatalog \
--namespace MyCompany.External.Services
Multiple OData Services in One Project
# Add multiple services - they all work together
dotnet odata add --endpoint https://api.products.com/odata --client-name ProductService
dotnet odata add --endpoint https://api.orders.com/odata --client-name OrderService
dotnet odata add --endpoint https://api.customers.com/odata --client-name CustomerService
Each client is independent, and you can use them side by side in your application.
π Keeping Metadata Up to Date
When the OData service changes (new entities, modified properties), just update:
dotnet odata update
This command:
- Finds all OData clients in your project
- Re-downloads metadata from their endpoints
- Updates the metadata files
- Rebuild to regenerate clients with the latest schema
Workflow example:
# Initial setup
dotnet odata add --endpoint https://api.example.com/odata --client-name ApiClient
dotnet build
# ... time passes, API changes ...
# Update to latest schema
dotnet odata update
dotnet build # Regenerates with new metadata
π‘ Real-World Example
Let's say you're building an app that needs to fetch data from the TripPin OData service:
# Step 1: Add the client
cd MyTravelApp
dotnet odata add \
--endpoint https://services.odata.org/V4/TripPinServiceRW \
--client-name TripPinService \
--output-path Services
# Step 2: Build
dotnet build
Now use it in your code:
using MyTravelApp.Services;
public class TravelService
{
private readonly HttpClient _httpClient;
public TravelService(IHttpClientFactory httpClientFactory)
{
_httpClient = httpClientFactory.CreateClient();
}
public async Task<List<Person>> GetTravelersAsync(string firstNamePrefix)
{
var client = new TripPinService(_httpClient);
// Type-safe LINQ queries
return await client.People
.Where(p => p.FirstName.StartsWith(firstNamePrefix))
.OrderBy(p => p.LastName)
.ToListAsync();
}
public async Task<Person> GetPersonWithTripsAsync(string username)
{
var client = new TripPinService(_httpClient);
// Expand navigation properties
var people = await client.People
.Where(p => p.UserName == username)
.Expand(p => p.Trips)
.ToListAsync();
return people.FirstOrDefault();
}
}
That's it. No manual DTOs. No string-based queries. Just clean, type-safe code with full IntelliSense.
π What You Get
When you run dotnet odata add, the tool generates:
1. Model Classes
public class Product
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public bool InStock { get; set; }
// ... all properties from metadata
}
2. Optimized JSON Converters
Custom converters for each model that:
- Deserialize JSON without reflection (faster!)
- Handle nullable types correctly
- Support all OData types
3. Type-Safe Client
public partial class YourServiceClient
{
public ODataQueryable<Product> Products { get; }
public ODataQueryable<Order> Orders { get; }
public ODataQueryable<Customer> Customers { get; }
// ... all entity sets from metadata
}
4. LINQ Support
Write normal C# LINQ queries:
// This LINQ expression...
var query = client.Products
.Where(p => p.Price > 10 && p.InStock)
.OrderBy(p => p.Name)
.Skip(20)
.Take(10);
// ...becomes this OData query automatically:
// /Products?$filter=Price gt 10 and InStock eq true&$orderby=Name asc&$skip=20&$top=10
π¨ Supported LINQ Operations
| LINQ Expression | OData Query |
|---|---|
.Where(p => p.Price > 10) |
$filter=Price gt 10 |
.Where(p => p.Name == "Test") |
$filter=Name eq 'Test' |
.Where(p => p.InStock && p.Price < 100) |
$filter=InStock eq true and Price lt 100 |
.OrderBy(p => p.Name) |
$orderby=Name asc |
.OrderByDescending(p => p.Price) |
$orderby=Price desc |
.Skip(10) |
$skip=10 |
.Take(20) |
$top=20 |
.Select(p => new { p.Name, p.Price }) |
$select=Name,Price |
.Expand(o => o.Product) |
$expand=Product |
String methods work too:
.Where(p => p.Name.StartsWith("A"))βstartswith(Name, 'A').Where(p => p.Name.EndsWith("Z"))βendswith(Name, 'Z').Where(p => p.Name.Contains("mid"))βcontains(Name, 'mid')
π οΈ Advanced Features
Need more control? The tool supports advanced scenarios:
Attribute-Based Customization
After generating the initial client, you can customize it:
using Forge.OData.Attributes;
namespace MyApp.Services
{
[ODataClient(
MetadataFile = "ApiMetadata.xml",
Endpoint = "https://api.example.com/odata"
)]
public partial class ApiClient
{
// Add your custom methods
public async Task<Product?> GetFeaturedProductAsync()
{
var results = await Products
.Where(p => p.Featured)
.OrderByDescending(p => p.Rating)
.Take(1)
.ToListAsync();
return results.FirstOrDefault();
}
// Add custom properties
public string ServiceVersion => "v2.0";
}
}
Working with Multiple Environments
// Development
var devClient = new ApiClient(
httpClient,
"https://dev-api.example.com/odata"
);
// Production
var prodClient = new ApiClient(
httpClient,
"https://api.example.com/odata"
);
π More Information
- Technical documentation: See CONTRIBUTE.md for detailed architecture, project structure, and contribution guidelines
- Examples: Check the
sample/directory for working examples - Changelog: See CHANGELOG.md for version history
π€ Contributing
We welcome contributions! Please see CONTRIBUTE.md for detailed information on:
- Project architecture and structure
- Development setup
- Building and testing
- Code generation workflow
- Contribution guidelines
π License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net9.0
- No dependencies.
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.2.0-beta.2 | 184 | 11/6/2025 |
| 0.2.0-beta.1 | 173 | 11/6/2025 |
| 0.1.0 | 232 | 11/6/2025 |
| 0.1.0-beta.6 | 185 | 11/6/2025 |
| 0.1.0-beta.5 | 179 | 11/6/2025 |
| 0.1.0-beta.4 | 182 | 11/6/2025 |
| 0.1.0-beta.3 | 176 | 11/6/2025 |
| 0.1.0-beta.2 | 172 | 11/6/2025 |
| 0.1.0-beta.1 | 178 | 11/6/2025 |
| 0.0.2 | 233 | 11/5/2025 |
Initial release with OData client generation from metadata, LINQ to OData support, and source generators.