ODataToClass 1.5.0
dotnet tool install --global ODataToClass --version 1.5.0
dotnet new tool-manifest
dotnet tool install --local ODataToClass --version 1.5.0
#tool dotnet:?package=ODataToClass&version=1.5.0
nuke :add-package ODataToClass --version 1.5.0
ODataToClass
A .NET CLI tool that generates C# classes from OData metadata. Supports both SAP OData (v2/v4) and Microsoft Dynamics 365 metadata.
Installation
# Install globally
dotnet tool install --global ODataToClass
# Or install locally in a project
dotnet tool install ODataToClass
Quick Start
# Generate from a local metadata file
odatatoclass -i metadata.xml -o MyEntities.cs
# Generate from an OData service URL
odatatoclass -u https://myserver.com/sap/opu/odata/sap/API_COSTCENTER/$metadata -o CostCenter.cs
# Generate from a URL with authentication
odatatoclass -u https://myserver.com/odata/$metadata --user myuser -p mypassword -o Entities.cs
Input Options
You must provide either --input (file) or --url (remote endpoint) as the metadata source.
From Local File (--input / -i)
Use this when you have already downloaded the metadata XML file:
odatatoclass -i metadata.xml -o Output.cs
From URL (--url / -u)
Fetch metadata directly from an OData service endpoint. The tool automatically appends $metadata if not present.
# Basic URL (no authentication)
odatatoclass -u https://services.odata.org/V4/Northwind/Northwind.svc/$metadata -o Northwind.cs
# With Basic Authentication
odatatoclass -u https://myserver.com/sap/opu/odata/sap/API_PROFITCENTER/$metadata --user USERNAME -p PASSWORD -o ProfitCenter.cs
Output Options
Output File (--output / -o)
Specify the output C# file path. If omitted, defaults to the input filename with .cs extension.
odatatoclass -i metadata.xml -o src/Models/Entities.cs
Namespace (--namespace / -n)
Set the C# namespace for generated classes. Default is SAP.
# SAP OData - uses SAP.{EntityName} structure
odatatoclass -i metadata.xml -n SAP -o Entities.cs
# Generates: namespace SAP.ProfitCenter { ... }
# Dynamics 365 - uses Dynamics.{ServiceName} structure
odatatoclass -i dynamics.xml -n Dynamics.Finance -o Finance.cs
# Generates: namespace Dynamics.Finance { ... }
Filtering Options
Entity Filter (--entity / -e)
Filter which entities to generate. Useful for large metadata files (Dynamics 365 can have 4000+ entities).
Supports wildcards (*) for pattern matching:
# Generate only SalesOrder entities
odatatoclass -i dynamics.xml -e "SalesOrder*" -o SalesOrders.cs
# Generate only entities starting with "Customer"
odatatoclass -i metadata.xml -e "Customer*" -o Customers.cs
# Generate a single specific entity
odatatoclass -i metadata.xml -e "ProfitCenter" -o ProfitCenter.cs
Advanced Options
Skip OData Wrappers (--no-wrappers)
By default, the tool generates OData response wrapper classes for deserializing API responses. Use --no-wrappers when:
- You already have wrapper classes in your project
- You're generating multiple files and want to share one set of wrappers
# Generate without wrapper classes
odatatoclass -i metadata.xml -o Entities.cs --no-wrappers
# Generate shared wrappers separately
odatatoclass wrappers -o ODataWrappers.cs -n SAP
Generate Only Wrappers (wrappers subcommand)
Generate only the OData wrapper classes without any entity classes:
odatatoclass wrappers -o ODataWrappers.cs -n MyNamespace
Complete Options Reference
| Option | Alias | Description | Default |
|---|---|---|---|
--input |
-i |
Local OData metadata XML file | - |
--url |
-u |
URL to OData $metadata endpoint | - |
--user |
- | Username for Basic authentication | - |
--password |
-p |
Password for Basic authentication | - |
--output |
-o |
Output C# file path | {input}.cs |
--namespace |
-n |
C# namespace prefix | SAP |
--entity |
-e |
Entity name filter (supports * wildcard) |
- |
--no-wrappers |
- | Skip generating OData wrapper classes | false |
Supported Metadata Formats
SAP OData v2
SAP's legacy OData format. Response structure uses nested d.results:
{ "d": { "results": [...] } }
Generated wrapper: OData.RootArray<T>, OData.Results<T>
SAP OData v4
Modern OData standard. Response structure uses value array:
{ "@odata.context": "...", "value": [...] }
Generated wrapper: ODataV4.RootArray<T> with List<T>
Microsoft Dynamics 365
Large enterprise metadata with extensive enum types. Auto-detected by namespace containing "Dynamics" or "Microsoft.Dynamics".
Generated Code Structure
Entity Classes
namespace SAP.ProfitCenter
{
public class ProfitCenter
{
public string? ControllingArea { get; set; }
[JsonProperty("ProfitCenter")]
public string? _ProfitCenter { get; set; }
public DateTimeOffset ValidityEndDate { get; set; }
// Navigation property with OData v2 wrapper
[JsonProperty("to_Text")]
public OData.Results<ProfitCenterText>? Texts { get; set; }
// Nested related entity
public class ProfitCenterText
{
public string? Language { get; set; }
public string? ProfitCenterName { get; set; }
}
}
}
Enum Types (Dynamics 365)
namespace Dynamics.Finance
{
public enum FiscalQuarter
{
Q1 = 0,
Q2 = 1,
Q3 = 2,
Q4 = 3
}
[Flags]
public enum TransactionFlags : long
{
None = 0,
Posted = 1,
Reversed = 2
}
}
OData Wrapper Classes
namespace SAP.OData
{
// OData v2 response wrapper
public class RootArray<T>
{
public Results<T> d { get; set; }
}
public class Results<T>
{
public List<T> results { get; set; }
}
}
namespace SAP.ODataV4
{
// OData v4 response wrapper
public class RootArray<T>
{
[JsonProperty("@odata.context")]
public string? Context { get; set; }
[JsonProperty("value")]
public List<T> Value { get; set; }
}
}
Usage Examples
Deserializing OData v2 Response
using SAP.OData;
using SAP.ProfitCenter;
using Newtonsoft.Json;
var json = await httpClient.GetStringAsync("https://server/sap/opu/odata/sap/API_PROFITCENTER/A_ProfitCenter");
var response = JsonConvert.DeserializeObject<RootArray<ProfitCenter>>(json);
foreach (var pc in response.d.results)
{
Console.WriteLine($"Profit Center: {pc._ProfitCenter}");
}
Deserializing OData v4 Response
using SAP.ODataV4;
using SAP.CostCenter;
using Newtonsoft.Json;
var json = await httpClient.GetStringAsync("https://server/odata/v4/CostCenters");
var response = JsonConvert.DeserializeObject<RootArray<CostCenter>>(json);
foreach (var cc in response.Value)
{
Console.WriteLine($"Cost Center: {cc.CostCenterId}");
}
Generating Multiple Files (Dynamics 365)
When working with large Dynamics 365 metadata, generate separate files per module:
# Generate shared wrappers first
odatatoclass wrappers -o Shared/ODataWrappers.cs -n Dynamics
# Generate Sales module entities
odatatoclass -i dynamics.xml -e "SalesOrder*" -n Dynamics.Sales -o Sales/SalesOrders.cs --no-wrappers
# Generate Finance module entities
odatatoclass -i dynamics.xml -e "Ledger*" -n Dynamics.Finance -o Finance/Ledger.cs --no-wrappers
# Generate Customer entities
odatatoclass -i dynamics.xml -e "Cust*" -n Dynamics.Customers -o Customers/Customers.cs --no-wrappers
Type Mappings
| EDM Type | C# Type |
|---|---|
Edm.String |
string? |
Edm.Int32 |
int |
Edm.Int64 |
long |
Edm.Int16 |
short |
Edm.Decimal |
decimal |
Edm.Double |
double |
Edm.Single |
float |
Edm.Boolean |
bool |
Edm.Guid |
Guid |
Edm.DateTime |
DateTimeOffset |
Edm.DateTimeOffset |
DateTimeOffset |
Edm.Date |
DateTimeOffset |
Edm.Time |
TimeSpan |
Edm.Binary |
byte[]? |
Edm.Byte |
byte |
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. 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. |
This package has no dependencies.