Uniphar.Sap.Odata.Client
1.0.6
See the version list below for details.
dotnet add package Uniphar.Sap.Odata.Client --version 1.0.6
NuGet\Install-Package Uniphar.Sap.Odata.Client -Version 1.0.6
<PackageReference Include="Uniphar.Sap.Odata.Client" Version="1.0.6" />
<PackageVersion Include="Uniphar.Sap.Odata.Client" Version="1.0.6" />
<PackageReference Include="Uniphar.Sap.Odata.Client" />
paket add Uniphar.Sap.Odata.Client --version 1.0.6
#r "nuget: Uniphar.Sap.Odata.Client, 1.0.6"
#addin nuget:?package=Uniphar.Sap.Odata.Client&version=1.0.6
#tool nuget:?package=Uniphar.Sap.Odata.Client&version=1.0.6
sap-odata-client
NuGet package repository for Sap OData Client connection
Purpose
This library is for making calls to SAP (running in AZ). Calls to SAP require a base url. Full path will be decorated with the namespace of the service we call.
Calls to the SAP instance requires authentication with Basic auth
- (username
and password
). These are stored in a secret storage and you do not need to define these. The secret storage can be AZ Keyvault
, AWS Secrets Manager
or others. Any token
expiry is automatically handled by the SAP client and is not something to be concerned with either.
Custom Events
The library also publishes some custom telemetry events. This is because there has been several issues with the SAP Rise environments. We publich the following events
Event | Description | Remarks |
---|---|---|
SapTokenExpiredEvent | When x-csrf-token has expired, and we get a 403 back when calling the SAP Rise instance. |
|
SapTokenUnauthorizedFetchEvent | When requesting a new x-csrf-token SAP returns a 401 instead of the expected 403 |
The system will throw an UnauthorizedAccessException |
SapTokenRefreshedFetchEvent | When requesting a new x-csrf-token , and SAP returns anything but 401 , we notify it was part of the Response headers |
|
SapTokenNotFoundEvent | When requesting a new x-csrf-token , and SAP returns anything but 401 . However, response headers do not contain x-csrf-token |
Setup your project to use SapClient package
When using this NuGet package you need to setup a few things in your project
appsettings.json
Add this to appsettings.json
"SapClientOptions": {
"BaseUrl": "https://<sap-baseurl>",
"PooledConnectionLifetime": "00:00:15",
"UseHttpClientHandler": false,
"FetchTokenStatusCodeTriggers": [
401,
403
]
}
NOTE: The baseUrl value is currently IP based, but should be DNS based. UseHttpClientHandler tells whether to use
HttpClientHandler
(true
) when instantiatingHttpClient
orSocketsHttpHandler
(false
), for which we use thePooledConnectionLifetime
. FetchTokenStatusCodeTriggers is a list of HttpCodes we test against to trigger fetching a new token. Normally it should just be 403, but we have to apply a hack to support 401 as well.
Program.cs
Add the following to Program.cs
- Add this to bind the above configuration section to class
SapClientOptions
. That will ensure we can DI it into the SapClient class.
builder.Services.Configure<SapClientOptions>(
builder.Configuration.GetSection(nameof(SapClientOptions)));
- Register a singleton instance of HttpClient, as SapClient makes calls to SAP RISE over HTTP.
// Register Http client
builder.Services.AddSingleton(new HttpClient
(
bool.Parse(builder.Configuration["SapClientOptions:UseHttpClientHandler"]) ?
new HttpClientHandler
{
ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator
}
: new SocketsHttpHandler
{
PooledConnectionLifetime = TimeSpan.Parse(builder.Configuration["SapClientOptions:PooledConnectionLifetime"])
}
)
{
BaseAddress = new Uri(builder.Configuration["SapClientOptions:BaseUrl"])
});
// Register SAP client
builder.Services.AddSingleton<ISapClient, SapClient>();
When running locally
Add this in appsettings.Development.json
. That means we bypass any Cert logic when running locally (see above in registering the Http client)
"SapClientOptions": {
"UseHttpClientHandler": true
}
Using SapClient library
We have a couple of predefined (and custom) JsonSerialisers
we need to use when calling SAP. This is handled by class SapJsonSerializer
. It exposes a static method:
public static JsonSerializerOptions GetJsonSerializerOptions()
{
// preliminary code logic
jsonSerializerOptions.Converters.Add(new SapDateTimeConverter());
jsonSerializerOptions.Converters.Add(new SapDateTimeOffsetConverter());
jsonSerializerOptions.Converters.Add(new SapDecimalConverter());
return jsonSerializerOptions;
}
The SAP client package exposes two methods
Task<ContentResult> GetAsync<T>(string path, CancellationToken cancellationToken)
Task<ContentResult> PostAsync<T>(string path, T message, CancellationToken cancellationToken)
Both methods return a ContentResult
, which means we can handle based on the Http status code in the response.
Example usage:
public async Task<ActionResult<SalesOrderResponse>> CreateToDoList([FromBody] CreateToDoList createToDoList, CancellationToken cancellationToken)
{
// Call SAP Client to get Serializer Options
var serializerOptions = SapJsonSerializer.GetJsonSerializerOptions();
// Make call to SAP Client POST method
var createdTodoListContentResult = await _sapClient.PostAsync("TO_DO_LIST_API", createToDoList.MapToSapToDoListRequest(), cancellationToken);
switch(createdTodoListContentResult.StatusCode)
{
case 201:
var createdSapTodoListResult = JsonSerializer.Deserialize<OData<ToDoList>>(createdTodoListContentResult.Content!, serializerOptions);
// Make call to SAP Client GET method
var sapToDoListWithItems = await _sapClient.GetAsync<OData<ToDoList>>(
$"TO_DO_LIST_API/TO_DO_LIST_ITEM('{createdSapTodoListResult!.Data!.Id}')?$expand=to_Item", cancellationToken);
var sapToDoList = JsonSerializer.Deserialize<OData<ToDoList>>(sapToDoListWithItems.Content!, serializerOptions);
var newSapToDoList = sapToDoList!.Data!.MapToSapToDoListResponse();
return CreatedAtAction(nameof(CreateToDoList), new { id = newSalesOrder.Id }, newSalesOrder);
case 400:
var sapErrorResponse = JsonSerializer.Deserialize<SapErrorResponse>(createdTodoListContentResult.Content!, options);
return BadRequest(sapErrorResponse!.MapToProblemDetails());
default:
return new StatusCodeResult((int)createdTodoListContentResult.StatusCode!);
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net7.0 is compatible. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. 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. |
-
net7.0
- Microsoft.ApplicationInsights (>= 2.22.0)
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 | |
---|---|---|---|
7.0.0 | 1,482 | 2/19/2025 | |
6.0.0 | 382 | 1/28/2025 | |
5.0.3 | 264 | 12/10/2024 | |
5.0.2 | 110 | 12/10/2024 | |
5.0.1 | 156 | 12/2/2024 | |
5.0.0 | 145 | 11/26/2024 | |
4.1.0 | 185 | 11/14/2024 | |
4.0.3 | 151 | 11/1/2024 | |
4.0.2 | 121 | 10/31/2024 | |
4.0.1 | 116 | 10/31/2024 | |
4.0.0 | 121 | 10/30/2024 | |
3.1.0 | 121 | 10/29/2024 | |
3.0.0 | 121 | 10/25/2024 | |
2.0.4 | 398 | 10/1/2024 | |
2.0.3 | 156 | 9/25/2024 | |
2.0.2 | 149 | 9/24/2024 | |
2.0.1 | 509 | 5/16/2024 | |
2.0.0 | 134 | 5/14/2024 | |
1.0.6 | 616 | 4/8/2024 | |
1.0.5 | 133 | 4/5/2024 | |
1.0.4 | 190 | 4/2/2024 | |
1.0.3 | 150 | 4/2/2024 | |
1.0.2 | 133 | 3/29/2024 | |
1.0.0 | 870 | 12/15/2023 | |
0.4.1 | 159 | 12/15/2023 | |
0.3.0 | 167 | 12/14/2023 | |
0.1.1 | 141 | 12/14/2023 | |
0.1.0 | 151 | 12/14/2023 |