MFR client: align with interface doc; remove VB-era files
Per MFR_RESTClient/Docs/mfr_interface_description.md (added): - MFRClientConfig: configurable TimeoutMs (default 30000), UserAgent, MaxRetries, and a derived RestRoot (/mfr) alongside the OData BaseUrl. - MFRClient: apply request Timeout + UserAgent, send Accept: application/json, and retry idempotent GETs on transient failures (HTTP 429/5xx and network/timeout) with exponential backoff + jitter, honouring Retry-After. - Added ReadODataAllPages to follow @odata.nextLink pagination. Cleanup: removed legacy VB project files (MFR_RESTClient.vbproj, .vbproj.user, app.config My.MySettings) and stopped tracking the generated MFR_RESTClient.xml (now git-ignored). The active project is MFR_RESTClient.csproj. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,7 @@ using System.Text.RegularExpressions;
|
||||
using System.Web;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using RestSharp;
|
||||
using RestSharp.Authenticators;
|
||||
|
||||
@@ -34,7 +35,9 @@ public class MFRClient : IDisposable
|
||||
_clientCredentials = credentials;
|
||||
_clientOptions = new RestClientOptions
|
||||
{
|
||||
Authenticator = new HttpBasicAuthenticator(_clientCredentials.Username, _clientCredentials.Password)
|
||||
Authenticator = new HttpBasicAuthenticator(_clientCredentials.Username, _clientCredentials.Password),
|
||||
Timeout = TimeSpan.FromMilliseconds(config.TimeoutMs),
|
||||
UserAgent = config.UserAgent
|
||||
};
|
||||
_client = new RestClient(_clientOptions);
|
||||
}
|
||||
@@ -42,6 +45,7 @@ public class MFRClient : IDisposable
|
||||
public async Task<string> ReadAnything(string address, bool throwErrorIfNotOk = true)
|
||||
{
|
||||
var request = new RestRequest(resource: address, method: Method.Get);
|
||||
request.AddHeader("Accept", "application/json");
|
||||
var response = await Execute(request, "ReadAnything", throwErrorIfNotOk);
|
||||
return response.Content ?? "";
|
||||
}
|
||||
@@ -49,10 +53,37 @@ public class MFRClient : IDisposable
|
||||
public async Task<ODataEnvelope> ReadOData(string address, bool throwErrorIfNotOk = true)
|
||||
{
|
||||
var request = new RestRequest(resource: address, method: Method.Get);
|
||||
request.AddHeader("Accept", "application/json");
|
||||
var response = await Execute(request, "ReadOData", throwErrorIfNotOk);
|
||||
return new ODataEnvelope(response.Content, url: address);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads an OData collection and follows <c>@odata.nextLink</c> pages, aggregating
|
||||
/// all <c>value</c> items into a single envelope (see interface doc §6.4 pagination).
|
||||
/// </summary>
|
||||
public async Task<ODataEnvelope> ReadODataAllPages(string address, int maxPages = 100, bool throwErrorIfNotOk = true)
|
||||
{
|
||||
var first = await ReadOData(address, throwErrorIfNotOk);
|
||||
first.ConvertToArray();
|
||||
var all = first.Value as JArray ?? new JArray();
|
||||
var next = first.NextLink;
|
||||
int pages = 1;
|
||||
while (next != null && pages < maxPages)
|
||||
{
|
||||
var page = await ReadOData(next.ToString(), throwErrorIfNotOk);
|
||||
page.ConvertToArray();
|
||||
if (page.Value is JArray arr)
|
||||
foreach (var item in arr) all.Add(item);
|
||||
next = page.NextLink;
|
||||
pages++;
|
||||
}
|
||||
first.Value = all;
|
||||
first.NextLink = null;
|
||||
_logger.LogDebug("ReadODataAllPages aggregated {Count} items over {Pages} page(s) — {Address}", all.Count, pages, address);
|
||||
return first;
|
||||
}
|
||||
|
||||
public byte[]? GetFile(string address, bool throwErrorIfNotOk = true)
|
||||
{
|
||||
byte[]? data = null;
|
||||
@@ -84,19 +115,34 @@ public class MFRClient : IDisposable
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes a query against MFR.
|
||||
/// Executes a request against MFR. Idempotent GET requests are retried on
|
||||
/// transient failures (HTTP 429 / 5xx and network/timeout errors) using
|
||||
/// exponential backoff with jitter, honouring <c>Retry-After</c> when present
|
||||
/// (see interface doc §12.3). Non-GET requests are never auto-retried.
|
||||
/// </summary>
|
||||
private async Task<RestResponse> Execute(RestRequest request, string message, bool throwErrorIfNotOk)
|
||||
{
|
||||
var response = await _client.ExecuteAsync(request);
|
||||
bool retryable = request.Method == Method.Get;
|
||||
int maxAttempts = retryable ? Math.Max(1, ClientConfig.MaxRetries + 1) : 1;
|
||||
RestResponse response = null!;
|
||||
|
||||
bool notFound = response.StatusCode == HttpStatusCode.InternalServerError
|
||||
&& (response.Content?.IndexOf("Sequence contains no elements", 0, StringComparison.InvariantCultureIgnoreCase) ?? -1) > -1;
|
||||
for (int attempt = 1; attempt <= maxAttempts; attempt++)
|
||||
{
|
||||
response = await _client.ExecuteAsync(request);
|
||||
|
||||
if (throwErrorIfNotOk
|
||||
&& response.StatusCode != HttpStatusCode.OK
|
||||
&& response.StatusCode != HttpStatusCode.Created
|
||||
&& !notFound)
|
||||
bool notFound = IsNotFound(response);
|
||||
bool transient = !notFound && IsTransient(response);
|
||||
|
||||
if (!transient || attempt == maxAttempts) break;
|
||||
|
||||
var delay = BackoffDelay(attempt, response);
|
||||
_logger.LogWarning("MFR transient failure: {Message} — status={Status}/{ResponseStatus}, retry {Attempt}/{Max} in {DelayMs}ms",
|
||||
message, (int)response.StatusCode, response.ResponseStatus, attempt, maxAttempts - 1, (int)delay.TotalMilliseconds);
|
||||
await Task.Delay(delay);
|
||||
}
|
||||
|
||||
bool ok = response.StatusCode is HttpStatusCode.OK or HttpStatusCode.Created or HttpStatusCode.NoContent;
|
||||
if (throwErrorIfNotOk && !ok && !IsNotFound(response))
|
||||
{
|
||||
_logger.LogWarning("Execute rest issue: {Message} — status={Status}, resource={Resource}",
|
||||
message, response.StatusDescription, request.Resource);
|
||||
@@ -106,6 +152,32 @@ public class MFRClient : IDisposable
|
||||
return response;
|
||||
}
|
||||
|
||||
/// <summary>MFR returns HTTP 500 "Sequence contains no elements" for empty single-entity reads; treat as not-found, not an error.</summary>
|
||||
private static bool IsNotFound(RestResponse response) =>
|
||||
response.StatusCode == HttpStatusCode.InternalServerError
|
||||
&& (response.Content?.IndexOf("Sequence contains no elements", 0, StringComparison.InvariantCultureIgnoreCase) ?? -1) > -1;
|
||||
|
||||
private static bool IsTransient(RestResponse response)
|
||||
{
|
||||
if (response.ResponseStatus is ResponseStatus.TimedOut or ResponseStatus.Error) return true;
|
||||
int code = (int)response.StatusCode;
|
||||
return code == 429 || (code >= 500 && code <= 599);
|
||||
}
|
||||
|
||||
private static TimeSpan BackoffDelay(int attempt, RestResponse response)
|
||||
{
|
||||
// Honour Retry-After (seconds) when the server provides it.
|
||||
var retryAfter = response.Headers?
|
||||
.FirstOrDefault(h => string.Equals(h.Name, "Retry-After", StringComparison.OrdinalIgnoreCase))?.Value?.ToString();
|
||||
if (int.TryParse(retryAfter, out var seconds) && seconds is > 0 and <= 120)
|
||||
return TimeSpan.FromSeconds(seconds);
|
||||
|
||||
// Exponential backoff (0.5s, 1s, 2s, …) capped at 10s, plus jitter.
|
||||
double baseMs = Math.Min(10000, 500 * Math.Pow(2, attempt - 1));
|
||||
double jitter = Random.Shared.Next(0, 250);
|
||||
return TimeSpan.FromMilliseconds(baseMs + jitter);
|
||||
}
|
||||
|
||||
private void ThrowExceptionIfNecessary(RestResponse response, string location, string? customMessage = null)
|
||||
{
|
||||
if (!HideCustomExceptions)
|
||||
|
||||
@@ -4,12 +4,32 @@ namespace MFR_RESTClient;
|
||||
|
||||
public class MFRClientConfig
|
||||
{
|
||||
/// <summary>Default mfr host (see MFR_RESTClient/Docs/mfr_interface_description.md §4).</summary>
|
||||
public const string DefaultHost = "https://portal.mobilefieldreport.com";
|
||||
|
||||
/// <summary>OData resource root (e.g. https://host/odata/). Kept for backward compatibility.</summary>
|
||||
public string BaseUrl { get; } = "";
|
||||
|
||||
/// <summary>REST operation root (e.g. https://host/mfr/) for mfr-specific operations
|
||||
/// such as deep-create and document upload (see interface doc §8, §9).</summary>
|
||||
public string RestRoot { get; } = "";
|
||||
|
||||
/// <summary>HTTP timeout in milliseconds (interface doc §4.3 default: 30000).</summary>
|
||||
public int TimeoutMs { get; set; } = 30000;
|
||||
|
||||
/// <summary>User-Agent sent with requests.</summary>
|
||||
public string UserAgent { get; set; } = "FuchsIntranet-MFRClient";
|
||||
|
||||
/// <summary>Transient-retry attempts for idempotent GET requests (429 / 5xx). 1 = no retry.</summary>
|
||||
public int MaxRetries { get; set; } = 3;
|
||||
|
||||
public MFRClientConfig(string url)
|
||||
{
|
||||
BaseUrl = url.StartsWith("http") ? url : $"https://{url.Trim()}/odata/";
|
||||
if (!BaseUrl.EndsWith("/")) BaseUrl += "/";
|
||||
// Derive the REST root (/mfr/) from the same scheme+host as the OData root.
|
||||
try { var u = new Uri(BaseUrl); RestRoot = $"{u.Scheme}://{u.Authority}/mfr/"; }
|
||||
catch { RestRoot = DefaultHost + "/mfr/"; }
|
||||
}
|
||||
|
||||
public bool IsLogoutRequired { get; set; } = false;
|
||||
|
||||
@@ -1,79 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<OutputType>Library</OutputType>
|
||||
<MyType>Empty</MyType>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<Configurations>db-dev.processweb.de;Debug;Release;server02.processweb.de</Configurations>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<DocumentationFile>MFR_RESTClient.xml</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DefineDebug>false</DefineDebug>
|
||||
<DocumentationFile>MFR_RESTClient.xml</DocumentationFile>
|
||||
<NoWarn>42016,41999,42017,42018,42019,42032,42036,42020,42021,42022</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="My Project\Application.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Application.myapp</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="My Project\Resources.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DesignTime>True</DesignTime>
|
||||
<DependentUpon>Resources.resx</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Update="My Project\Settings.Designer.vb">
|
||||
<AutoGen>True</AutoGen>
|
||||
<DependentUpon>Settings.settings</DependentUpon>
|
||||
<DesignTimeSharedInput>True</DesignTimeSharedInput>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="My Project\Application.myapp">
|
||||
<Generator>MyApplicationCodeGenerator</Generator>
|
||||
<LastGenOutput>Application.Designer.vb</LastGenOutput>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup Label="Compile items now included by globbing that were not in the original project file">
|
||||
<Compile Remove="MFRClientSessionManagement.vb" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="MFR_RESTClient.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<!-- Compatible packages (kept) -->
|
||||
<PackageReference Include="Microsoft.AspNet.SignalR.Client" Version="2.4.3" />
|
||||
<PackageReference Include="Microsoft.AspNet.WebApi.Client" Version="5.2.9" />
|
||||
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" Version="1.6.2" />
|
||||
<PackageReference Include="Microsoft.Data.Edm" Version="5.8.5" />
|
||||
<PackageReference Include="Microsoft.Data.OData" Version="5.8.5" />
|
||||
<PackageReference Include="Microsoft.Data.Services.Client" Version="5.8.5" />
|
||||
<PackageReference Include="Microsoft.NETCore.Targets" Version="5.0.0" />
|
||||
<PackageReference Include="Microsoft.Rest.ClientRuntime" Version="2.3.24" />
|
||||
<PackageReference Include="System.Private.Uri" Version="4.3.2" />
|
||||
<PackageReference Include="System.Spatial" Version="5.8.5" />
|
||||
<!-- Updated packages -->
|
||||
<PackageReference Include="Microsoft.Bcl.AsyncInterfaces" Version="10.0.5" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="8.17.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||
<PackageReference Include="RestSharp" Version="114.0.0" />
|
||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="8.17.0" />
|
||||
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.1.2" />
|
||||
<PackageReference Include="System.Text.Encodings.Web" Version="10.0.5" />
|
||||
<PackageReference Include="System.Text.Json" Version="10.0.5" />
|
||||
<!-- New packages (replacements) -->
|
||||
<PackageReference Include="Azure.Messaging.ServiceBus" Version="7.20.1" />
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="7.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.0-preview.5.25277.114" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="10.0.0-preview.5.25277.114" />
|
||||
<PackageReference Include="System.Configuration.ConfigurationManager" Version="10.0.5" />
|
||||
<!-- Deprecated but kept for compatibility (review in follow-up) -->
|
||||
<PackageReference Include="Microsoft.IdentityModel.Abstractions" Version="8.17.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Clients.ActiveDirectory" Version="5.3.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Logging" Version="8.17.0" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.Tokens" Version="8.17.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<ProjectView>ShowAllFiles</ProjectView>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<doc>
|
||||
<assembly>
|
||||
<name>MFR_RESTClient</name>
|
||||
</assembly>
|
||||
<members>
|
||||
<member name="P:MFR_RESTClient.MFRClient.HideCustomExceptions">
|
||||
<summary>
|
||||
Get or set a value indicating the exceptions thrown by the client should be hidden.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:MFR_RESTClient.MFRClient.#ctor(MFR_RESTClient.MFRClientConfig,MFR_RESTClient.MFRClientCredentials,Microsoft.Extensions.Logging.ILogger{MFR_RESTClient.MFRClient})">
|
||||
<summary>
|
||||
Construct with typed config and credentials.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:MFR_RESTClient.MFRClient.Execute(RestSharp.RestRequest,System.String,System.Boolean)">
|
||||
<summary>
|
||||
Executes a query against MFR.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:MFR_RESTClient.HtmlCleanUp.Clean(System.String)">
|
||||
<summary>
|
||||
Cleanse HTML tags and other detritus from the string to make it plaintext.
|
||||
</summary>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
@@ -1,121 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<configSections>
|
||||
<sectionGroup name="userSettings" type="System.Configuration.UserSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
|
||||
<section name="MFR_RESTClient.My.MySettings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" allowExeDefinition="MachineToLocalUser" requirePermission="false" />
|
||||
</sectionGroup>
|
||||
</configSections>
|
||||
<appSettings>
|
||||
<add key="ClientSettingsProvider.ServiceUri" value="" />
|
||||
</appSettings>
|
||||
<system.web>
|
||||
<membership defaultProvider="ClientAuthenticationMembershipProvider">
|
||||
<providers>
|
||||
<add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" />
|
||||
</providers>
|
||||
</membership>
|
||||
<roleManager defaultProvider="ClientRoleProvider" enabled="true">
|
||||
<providers>
|
||||
<add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" />
|
||||
</providers>
|
||||
</roleManager>
|
||||
</system.web>
|
||||
<userSettings>
|
||||
<MFR_RESTClient.My.MySettings>
|
||||
</MFR_RESTClient.My.MySettings>
|
||||
</userSettings>
|
||||
<system.serviceModel>
|
||||
<extensions>
|
||||
<!-- In this extension section we are introducing all known service bus extensions. User can remove the ones they don't need. -->
|
||||
<behaviorExtensions>
|
||||
<add name="connectionStatusBehavior" type="Microsoft.ServiceBus.Configuration.ConnectionStatusElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="transportClientEndpointBehavior" type="Microsoft.ServiceBus.Configuration.TransportClientEndpointBehaviorElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="serviceRegistrySettings" type="Microsoft.ServiceBus.Configuration.ServiceRegistrySettingsElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
</behaviorExtensions>
|
||||
<bindingElementExtensions>
|
||||
<add name="netMessagingTransport" type="Microsoft.ServiceBus.Messaging.Configuration.NetMessagingTransportExtensionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="tcpRelayTransport" type="Microsoft.ServiceBus.Configuration.TcpRelayTransportElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="httpRelayTransport" type="Microsoft.ServiceBus.Configuration.HttpRelayTransportElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="httpsRelayTransport" type="Microsoft.ServiceBus.Configuration.HttpsRelayTransportElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="onewayRelayTransport" type="Microsoft.ServiceBus.Configuration.RelayedOnewayTransportElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
</bindingElementExtensions>
|
||||
<bindingExtensions>
|
||||
<add name="basicHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.BasicHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="webHttpRelayBinding" type="Microsoft.ServiceBus.Configuration.WebHttpRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="ws2007HttpRelayBinding" type="Microsoft.ServiceBus.Configuration.WS2007HttpRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="netTcpRelayBinding" type="Microsoft.ServiceBus.Configuration.NetTcpRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="netOnewayRelayBinding" type="Microsoft.ServiceBus.Configuration.NetOnewayRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="netEventRelayBinding" type="Microsoft.ServiceBus.Configuration.NetEventRelayBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
<add name="netMessagingBinding" type="Microsoft.ServiceBus.Messaging.Configuration.NetMessagingBindingCollectionElement, Microsoft.ServiceBus, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
|
||||
</bindingExtensions>
|
||||
</extensions>
|
||||
</system.serviceModel>
|
||||
<runtime>
|
||||
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Net.Http.Formatting" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.2.7.0" newVersion="5.2.7.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Azure.Services.AppAuthentication" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-1.6.2.0" newVersion="1.6.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-7.0.2.0" newVersion="7.0.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.IdentityModel.Clients.ActiveDirectory" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-5.3.0.0" newVersion="5.3.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="6.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.IdentityModel.Tokens" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-7.0.2.0" newVersion="7.0.2.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.IdentityModel.Logging" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.11.0.0" newVersion="6.11.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.IdentityModel.JsonWebTokens" publicKeyToken="31bf3856ad364e35" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-6.11.0.0" newVersion="6.11.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Text.Json" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-7.0.0.3" newVersion="7.0.0.3" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="Microsoft.Bcl.AsyncInterfaces" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-4.0.1.2" newVersion="4.0.1.2" />
|
||||
</dependentAssembly>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity name="System.Text.Encodings.Web" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
|
||||
<bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
|
||||
</dependentAssembly>
|
||||
</assemblyBinding>
|
||||
</runtime>
|
||||
</configuration>
|
||||
Reference in New Issue
Block a user