diff --git a/EdiApi.Client/EdiApi.Client.csproj b/EdiApi.Client/EdiApi.Client.csproj index a1a7d0d..f63e019 100644 --- a/EdiApi.Client/EdiApi.Client.csproj +++ b/EdiApi.Client/EdiApi.Client.csproj @@ -13,11 +13,12 @@ - - - + + + - + + \ No newline at end of file diff --git a/EdiApi.Client/Http/BaseEdiApiHttpClient.cs b/EdiApi.Client/Http/BaseEdiApiHttpClient.cs index b2da0d1..6d6677e 100644 --- a/EdiApi.Client/Http/BaseEdiApiHttpClient.cs +++ b/EdiApi.Client/Http/BaseEdiApiHttpClient.cs @@ -1,6 +1,7 @@ using System; using System.Net; using System.Text; +using System.Threading.Tasks; using SkbKontur.EdiApi.Client.Types.Boxes; using SkbKontur.EdiApi.Client.Types.Logistics; @@ -24,28 +25,58 @@ protected BaseEdiApiHttpClient( string apiClientId, Uri baseUri, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds, IWebProxy? proxy = null) { + if (string.IsNullOrEmpty(apiClientId)) + throw new ArgumentNullException(nameof(apiClientId)); + this.apiClientId = apiClientId; Serializer = serializer; - clusterClient = ClusterClientFactory.Get(baseUri, timeoutInMilliseconds, proxy); + clusterClient = ClusterClientFactory.Get(baseUri, TimeSpan.FromMilliseconds(timeoutInMilliseconds), proxy); } protected BaseEdiApiHttpClient( string apiClientId, string environment, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds, IWebProxy? proxy = null, ITracer? tracer = null) { + if (string.IsNullOrEmpty(apiClientId)) + throw new ArgumentException(nameof(apiClientId)); + this.apiClientId = apiClientId; Serializer = serializer; - clusterClient = ClusterClientFactory.Get(environment, timeoutInMilliseconds, proxy, tracer : tracer); + clusterClient = ClusterClientFactory.Get(environment, TimeSpan.FromMilliseconds(timeoutInMilliseconds), proxy, tracer : tracer); + } + + protected BaseEdiApiHttpClient(Uri baseUri, + IEdiApiTypesSerializer? serializer = null, + TimeSpan? timeout = null, + IWebProxy? proxy = null) + { + Serializer = serializer ?? new JsonEdiApiTypesSerializer(); + clusterClient = ClusterClientFactory.Get(baseUri, timeout ?? DefaultTimeout, proxy); + } + + protected BaseEdiApiHttpClient(string environment, + IEdiApiTypesSerializer? serializer = null, + TimeSpan? timeout = null, + IWebProxy? proxy = null, + ITracer? tracer = null) + { + Serializer = serializer ?? new JsonEdiApiTypesSerializer(); + clusterClient = ClusterClientFactory.Get(environment, timeout ?? DefaultTimeout, proxy, tracer : tracer); } + [Obsolete("Use new OpenId Connect authentication scheme")] public string Authenticate(string portalSid) => DoAuthenticate(new AuthCredentials {PortalSid = portalSid}); + [Obsolete("Use new OpenId Connect authentication scheme")] public string Authenticate(string login, string password) => DoAuthenticate(new AuthCredentials {Login = login, Password = password}); private string DoAuthenticate(AuthCredentials authCredentials) { + if (IsOpenIdConnectEnabled()) + throw new InvalidOperationException("The client is configured with the new OpenId Connect authentication method that is incompatible with the legacy '/V1/Authenticate' endpoint"); + var request = BuildPostRequest("V1/Authenticate", authCredentials); var result = clusterClient.Send(request); @@ -56,93 +87,167 @@ private string DoAuthenticate(AuthCredentials authCredentials) public PartiesInfo GetAccessiblePartiesInfo(string authToken) { - var request = BuildGetRequest("V1/Parties/GetAccessiblePartiesInfo", authToken : authToken); + var request = BuildGetAccessiblePartiesInfoRequest(authToken); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetAccessiblePartiesInfoAsync(string authToken) + { + var request = BuildGetAccessiblePartiesInfoRequest(authToken); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public PartyInfo GetPartyInfo(string authToken, string partyId) { - var request = BuildGetRequest("V1/Parties/GetPartyInfo", authToken : authToken) - .WithAdditionalQueryParameter("partyId", partyId); + var request = BuildGetPartyInfoRequest(authToken, partyId); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetPartyInfoAsync(string authToken, string partyId) + { + var request = BuildGetPartyInfoRequest(authToken, partyId); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public PartyInfo GetPartyInfoByGln(string authToken, string partyGln) { - var request = BuildGetRequest("V1/Parties/GetPartyInfoByGln", authToken : authToken) - .WithAdditionalQueryParameter("partyGln", partyGln); + var request = BuildGetPartyInfoByGlnRequest(authToken, partyGln); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetPartyInfoByGlnAsync(string authToken, string partyGln) + { + var request = BuildGetPartyInfoByGlnRequest(authToken, partyGln); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public PartyInfo GetPartyInfoByDepartmentGln(string authToken, string departmentGln) { - var request = BuildGetRequest("V1/Parties/GetPartyInfoByDepartmentGln", authToken : authToken) - .WithAdditionalQueryParameter("departmentGln", departmentGln); + var request = BuildGetPartyInfoByDepartmentGlnRequest(authToken, departmentGln); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetPartyInfoByDepartmentGlnAsync(string authToken, string departmentGln) + { + var request = BuildGetPartyInfoByDepartmentGlnRequest(authToken, departmentGln); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public BoxesInfo GetBoxesInfo(string authToken) { - var request = BuildGetRequest("V1/Boxes/GetBoxesInfo", authToken : authToken); + var request = BuildGetBoxesInfoRequest(authToken); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetBoxesInfoAsync(string authToken) + { + var request = BuildGetBoxesInfoRequest(authToken); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public BoxInfo GetMainApiBox(string authToken, string partyId) { - var request = BuildGetRequest("V1/Boxes/GetMainApiBox", authToken : authToken) - .WithAdditionalQueryParameter("partyId", partyId); + var request = BuildGetMainApiBoxRequest(authToken, partyId); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetMainApiBoxAsync(string authToken, string partyId) + { + var request = BuildGetMainApiBoxRequest(authToken, partyId); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public OrganizationCatalogueInfo GetOrganizationCatalogueInfo(string authToken, string partyId) { - var request = BuildGetRequest("V1/Organizations/GetOrganizationCatalogueInfo", authToken : authToken) - .WithAdditionalQueryParameter("partyId", partyId); + var request = BuildGetOrganizationCatalogueInfoRequest(authToken, partyId); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetOrganizationCatalogueInfoAsync(string authToken, string partyId) + { + var request = BuildGetOrganizationCatalogueInfoRequest(authToken, partyId); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public TransportationDocumentIdentifier GetTransportationDocumentIdentifier(string authToken, string partyId) { - var request = BuildGetRequest("V1/Logistics/GetTransportationDocumentIdentifier", authToken : authToken) - .WithAdditionalQueryParameter("partyId", partyId); + var request = BuildGetTransportationDocumentIdentifierRequest(authToken, partyId); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetTransportationDocumentIdentifierAsync(string authToken, string partyId) + { + var request = BuildGetTransportationDocumentIdentifierRequest(authToken, partyId); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } protected IEdiApiTypesSerializer Serializer { get; } - protected const int DefaultTimeout = 30 * 1000; + protected const int DefaultTimeoutMs = 30_000; protected virtual Request BuildPostRequest(string relativeUrl, AuthCredentials? authCredentials = null, string? authToken = null) => BuildPostRequest(relativeUrl, authCredentials, authToken, Array.Empty()); @@ -190,7 +295,78 @@ protected virtual void EnsureSuccessResult(ClusterResult result) } } + protected TResult DeserializeResponse(ClusterResult result) + where TResult : class + { + return Serializer.Deserialize(result.Response.Content.ToString()); + } + + private bool IsOpenIdConnectEnabled() => string.IsNullOrEmpty(apiClientId); + + private Request BuildGetAccessiblePartiesInfoRequest(string authToken) + { + return BuildGetRequest("V1/Parties/GetAccessiblePartiesInfo", authToken : authToken); + } + + private Request BuildGetPartyInfoRequest(string authToken, string partyId) + { + return BuildGetRequest("V1/Parties/GetPartyInfo", authToken : authToken) + .WithAdditionalQueryParameter("partyId", partyId); + } + + private Request BuildGetPartyInfoByGlnRequest(string authToken, string partyGln) + { + return BuildGetRequest("V1/Parties/GetPartyInfoByGln", authToken : authToken) + .WithAdditionalQueryParameter("partyGln", partyGln); + } + + private Request BuildGetPartyInfoByDepartmentGlnRequest(string authToken, string departmentGln) + { + return BuildGetRequest("V1/Parties/GetPartyInfoByDepartmentGln", authToken : authToken) + .WithAdditionalQueryParameter("departmentGln", departmentGln); + } + + private Request BuildGetBoxesInfoRequest(string authToken) + { + return BuildGetRequest("V1/Boxes/GetBoxesInfo", authToken : authToken); + } + + private Request BuildGetMainApiBoxRequest(string authToken, string partyId) + { + return BuildGetRequest("V1/Boxes/GetMainApiBox", authToken : authToken) + .WithAdditionalQueryParameter("partyId", partyId); + } + + private Request BuildGetOrganizationCatalogueInfoRequest(string authToken, string partyId) + { + return BuildGetRequest("V1/Organizations/GetOrganizationCatalogueInfo", authToken : authToken) + .WithAdditionalQueryParameter("partyId", partyId); + } + + private Request BuildGetTransportationDocumentIdentifierRequest(string authToken, string partyId) + { + return BuildGetRequest("V1/Logistics/GetTransportationDocumentIdentifier", authToken : authToken) + .WithAdditionalQueryParameter("partyId", partyId); + } + private string BuildAuthorizationHeader(AuthCredentials? authCredentials, string? authToken) + { + if (IsOpenIdConnectEnabled()) + { + if (string.IsNullOrEmpty(authToken)) + throw new ArgumentNullException(nameof(authToken), "AuthToken should not be empty when using the new OpenId Connect authentication scheme."); + return BuildBearerAuthorizationHeader(authToken!); + } + + return BuildKonturEdiAuthorizationHeader(authCredentials, authToken); + } + + private static string BuildBearerAuthorizationHeader(string authToken) + { + return $"Bearer {authToken}"; + } + + private string BuildKonturEdiAuthorizationHeader(AuthCredentials? authCredentials, string? authToken) { var stringBuilder = new StringBuilder(); stringBuilder.Append("KonturEdiAuth "); @@ -211,8 +387,10 @@ private string BuildAuthorizationHeader(AuthCredentials? authCredentials, string return stringBuilder.ToString(); } + private static readonly TimeSpan DefaultTimeout = TimeSpan.FromMilliseconds(DefaultTimeoutMs); + protected readonly IClusterClient clusterClient; - private readonly string apiClientId; + private readonly string? apiClientId; } } \ No newline at end of file diff --git a/EdiApi.Client/Http/ClusterClientFactory.cs b/EdiApi.Client/Http/ClusterClientFactory.cs index d41c8fc..ed89b6f 100644 --- a/EdiApi.Client/Http/ClusterClientFactory.cs +++ b/EdiApi.Client/Http/ClusterClientFactory.cs @@ -2,6 +2,7 @@ using System.Net; using Vostok.Clusterclient.Core; +using Vostok.Clusterclient.Core.Model; using Vostok.Clusterclient.Singular; using Vostok.Clusterclient.Tracing; using Vostok.Clusterclient.Transport; @@ -16,7 +17,7 @@ internal static class ClusterClientFactory { public static IClusterClient Get( Uri externalUri, - int defaultRequestTimeoutMs, + TimeSpan defaultRequestTimeout, IWebProxy? proxy = null, ILog? log = null ) @@ -28,7 +29,7 @@ public static IClusterClient Get( return new ClusterClient(log, configuration => { - configuration.DefaultTimeout = TimeSpan.FromMilliseconds(defaultRequestTimeoutMs); + configuration.DefaultTimeout = defaultRequestTimeout; configuration.SetupExternalUrl(externalUri); configuration.SetupUniversalTransport( new UniversalTransportSettings @@ -36,12 +37,13 @@ public static IClusterClient Get( AllowAutoRedirect = false, Proxy = proxy }); + configuration.AddRequestTransform(request => request.WithUserAgentHeader(UserAgentProvider.GetUserAgent())); }); } public static IClusterClient Get( string environmentName, - int defaultRequestTimeoutMs, + TimeSpan defaultRequestTimeout, IWebProxy? proxy = null, ILog? log = null, ITracer? tracer = null @@ -54,7 +56,7 @@ public static IClusterClient Get( return new ClusterClient(log, configuration => { - configuration.DefaultTimeout = TimeSpan.FromMilliseconds(defaultRequestTimeoutMs); + configuration.DefaultTimeout = defaultRequestTimeout; configuration.SetupSingular(new SingularClientSettings(environmentName, "Catalogue_EDI_API_Front")); configuration.SetupUniversalTransport( new UniversalTransportSettings @@ -62,6 +64,7 @@ public static IClusterClient Get( AllowAutoRedirect = false, Proxy = proxy }); + configuration.AddRequestTransform(request => request.WithUserAgentHeader(UserAgentProvider.GetUserAgent())); if (tracer != null) configuration.SetupDistributedTracing(tracer); diff --git a/EdiApi.Client/Http/Connectors/TransformerConnectorEdiApiClient.cs b/EdiApi.Client/Http/Connectors/TransformerConnectorEdiApiClient.cs index c19b139..acb3523 100644 --- a/EdiApi.Client/Http/Connectors/TransformerConnectorEdiApiClient.cs +++ b/EdiApi.Client/Http/Connectors/TransformerConnectorEdiApiClient.cs @@ -18,22 +18,22 @@ namespace SkbKontur.EdiApi.Client.Http.Connectors { public class TransformerConnectorEdiApiClient : BaseEdiApiHttpClient, ITransformerConnectorEdiApiClient { - public TransformerConnectorEdiApiClient(string apiClientId, Uri baseUri, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null) + public TransformerConnectorEdiApiClient(string apiClientId, Uri baseUri, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null) : this(apiClientId, baseUri, new JsonEdiApiTypesSerializer(), timeoutInMilliseconds, proxy) { } - public TransformerConnectorEdiApiClient(string apiClientId, Uri baseUri, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null) + public TransformerConnectorEdiApiClient(string apiClientId, Uri baseUri, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null) : base(apiClientId, baseUri, serializer, timeoutInMilliseconds, proxy) { } - public TransformerConnectorEdiApiClient(string apiClientId, string environment, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null, ITracer? tracer = null) + public TransformerConnectorEdiApiClient(string apiClientId, string environment, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null, ITracer? tracer = null) : this(apiClientId, environment, new JsonEdiApiTypesSerializer(), timeoutInMilliseconds, proxy, tracer) { } - public TransformerConnectorEdiApiClient(string apiClientId, string environment, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null, ITracer? tracer = null) + public TransformerConnectorEdiApiClient(string apiClientId, string environment, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null, ITracer? tracer = null) : base(apiClientId, environment, serializer, timeoutInMilliseconds, proxy, tracer) { } @@ -115,7 +115,7 @@ public MessageEntity GetMessage(string authToken, string connectorBoxId, string var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); } public ConnectorBoxesInfo GetConnectorBoxesInfo(string authToken) @@ -125,7 +125,7 @@ public ConnectorBoxesInfo GetConnectorBoxesInfo(string authToken) var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); } private TransformerConnectorBoxEventBatch GetEventsInternal(Request request) @@ -133,7 +133,7 @@ private TransformerConnectorBoxEventBatch GetEventsInternal(Request request) var result = clusterClient.Send(request); EnsureSuccessResult(result); - var boxEventBatch = Serializer.Deserialize(result.Response.Content.ToString()); + var boxEventBatch = DeserializeResponse(result); boxEventBatch.Events ??= new TransformerConnectorBoxEvent[0]; foreach (var boxEvent in boxEventBatch.Events) diff --git a/EdiApi.Client/Http/Internal/InternalEdiApiHttpClient.cs b/EdiApi.Client/Http/Internal/InternalEdiApiHttpClient.cs index 44db2c6..ec3d604 100644 --- a/EdiApi.Client/Http/Internal/InternalEdiApiHttpClient.cs +++ b/EdiApi.Client/Http/Internal/InternalEdiApiHttpClient.cs @@ -20,24 +20,25 @@ namespace SkbKontur.EdiApi.Client.Http.Internal { + [Obsolete("Internal integrators should use Internal Api V2")] public class InternalEdiApiHttpClient : BaseEdiApiHttpClient, IInternalEdiApiHttpClient { - public InternalEdiApiHttpClient(string apiClientId, Uri baseUri, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null) + public InternalEdiApiHttpClient(string apiClientId, Uri baseUri, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null) : this(apiClientId, baseUri, new JsonEdiApiTypesSerializer(), timeoutInMilliseconds, proxy) { } - public InternalEdiApiHttpClient(string apiClientId, Uri baseUri, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null) + public InternalEdiApiHttpClient(string apiClientId, Uri baseUri, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null) : base(apiClientId, baseUri, serializer, timeoutInMilliseconds, proxy) { } - public InternalEdiApiHttpClient(string apiClientId, string environment, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null, ITracer? tracer = null) + public InternalEdiApiHttpClient(string apiClientId, string environment, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null, ITracer? tracer = null) : this(apiClientId, environment, new JsonEdiApiTypesSerializer(), timeoutInMilliseconds, proxy, tracer) { } - public InternalEdiApiHttpClient(string apiClientId, string environment, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null, ITracer? tracer = null) + public InternalEdiApiHttpClient(string apiClientId, string environment, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null, ITracer? tracer = null) : base(apiClientId, environment, serializer, timeoutInMilliseconds, proxy, tracer) { } @@ -52,7 +53,7 @@ public InternalEdiApiHttpClient(string apiClientId, string environment, IEdiApiT var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); } public MessageBoxEventBatch GetEvents(string authToken, string? exclusiveEventPointer, int? count = null) @@ -71,7 +72,7 @@ public MessageBoxEventBatch GetEvents(string authToken, string? exclusiveEventPo var result = clusterClient.Send(request); EnsureSuccessResult(result); - var boxEventBatch = Serializer.Deserialize(result.Response.Content.ToString()); + var boxEventBatch = DeserializeResponse(result); foreach (var boxEvent in boxEventBatch.Events) { AdjustEventContent(boxEvent); @@ -88,7 +89,7 @@ public MessageBoxEvent[] GetEventsByDocumentCirculationId(string authToken, stri var result = clusterClient.Send(request); EnsureSuccessResult(result); - var boxEvents = Serializer.Deserialize(result.Response.Content.ToString()); + var boxEvents = DeserializeResponse(result); foreach (var boxEvent in boxEvents) { AdjustEventContent(boxEvent); @@ -115,7 +116,7 @@ public BoxesInfo GetBoxesInfo(string authToken, string partyId) var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); } public InternalPartyInfo GetInternalPartyInfo(string authToken, string partyId) @@ -126,7 +127,7 @@ public InternalPartyInfo GetInternalPartyInfo(string authToken, string partyId) var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); } public PartyInfoWithEmployee[] GetPartiesByUser(string authToken, string userId) @@ -137,7 +138,7 @@ public PartyInfoWithEmployee[] GetPartiesByUser(string authToken, string userId) var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); } public PartyInfoWithEmployees[] GetPartiesInfoByInn(string authToken, string partyInn) @@ -148,7 +149,7 @@ public PartyInfoWithEmployees[] GetPartiesInfoByInn(string authToken, string par var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); } public PartySettings GetPartySettings(string authToken, string partyId) @@ -159,7 +160,7 @@ public PartySettings GetPartySettings(string authToken, string partyId) var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); } public string AddOrUpdateParty(string authToken, string partyId, EditablePartySettings editablePartySettings) @@ -170,7 +171,7 @@ public string AddOrUpdateParty(string authToken, string partyId, EditablePartySe var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); } public void AddEmployee(string authToken, string partyId, string email) diff --git a/EdiApi.Client/Http/Messages/MessagesEdiApiHttpClient.cs b/EdiApi.Client/Http/Messages/MessagesEdiApiHttpClient.cs index 29a2160..0589396 100644 --- a/EdiApi.Client/Http/Messages/MessagesEdiApiHttpClient.cs +++ b/EdiApi.Client/Http/Messages/MessagesEdiApiHttpClient.cs @@ -1,6 +1,7 @@ using System; using System.Globalization; using System.Net; +using System.Threading.Tasks; using SkbKontur.EdiApi.Client.Types.BoxEvents; using SkbKontur.EdiApi.Client.Types.Common; @@ -18,139 +19,290 @@ namespace SkbKontur.EdiApi.Client.Http.Messages { public class MessagesEdiApiHttpClient : BaseEdiApiHttpClient, IMessagesEdiApiClient { - public MessagesEdiApiHttpClient(string apiClientId, Uri baseUri, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null) + public MessagesEdiApiHttpClient(Uri baseUri, + IEdiApiTypesSerializer? serializer = null, + TimeSpan? timeout = null, + IWebProxy? proxy = null) + : base(baseUri, serializer, timeout, proxy) + { + } + + public MessagesEdiApiHttpClient(string environment, + IEdiApiTypesSerializer? serializer = null, + TimeSpan? timeout = null, + IWebProxy? proxy = null, + ITracer? tracer = null) + : base(environment, serializer, timeout, proxy, tracer) + { + } + + [Obsolete("Use the constructor overload without apiClientId for OpenID Connect authentication")] + public MessagesEdiApiHttpClient(string apiClientId, Uri baseUri, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null) : this(apiClientId, baseUri, new JsonEdiApiTypesSerializer(), timeoutInMilliseconds, proxy) { } - public MessagesEdiApiHttpClient(string apiClientId, Uri baseUri, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null) + [Obsolete("Use the constructor overload without apiClientId for OpenID Connect authentication")] + public MessagesEdiApiHttpClient(string apiClientId, Uri baseUri, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null) : base(apiClientId, baseUri, serializer, timeoutInMilliseconds, proxy) { } - public MessagesEdiApiHttpClient(string apiClientId, string environment, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null, ITracer? tracer = null) + [Obsolete("Use the constructor overload without apiClientId for OpenID Connect authentication")] + public MessagesEdiApiHttpClient(string apiClientId, string environment, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null, ITracer? tracer = null) : this(apiClientId, environment, new JsonEdiApiTypesSerializer(), timeoutInMilliseconds, proxy, tracer) { } - public MessagesEdiApiHttpClient(string apiClientId, string environment, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeout, IWebProxy? proxy = null, ITracer? tracer = null) + [Obsolete("Use the constructor overload without apiClientId for OpenID Connect authentication")] + public MessagesEdiApiHttpClient(string apiClientId, string environment, IEdiApiTypesSerializer serializer, int timeoutInMilliseconds = DefaultTimeoutMs, IWebProxy? proxy = null, ITracer? tracer = null) : base(apiClientId, environment, serializer, timeoutInMilliseconds, proxy, tracer) { } public BoxDocumentsSettings GetBoxDocumentsSettings(string authToken, string boxId) { - var request = BuildGetRequest("V1/Messages/GetBoxDocumentsSettings", authToken : authToken) - .WithAdditionalQueryParameter("boxId", boxId); + var request = BuildGetBoxDocumentsSettingsRequest(authToken, boxId); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetBoxDocumentsSettingsAsync(string authToken, string boxId) + { + var request = BuildGetBoxDocumentsSettingsRequest(authToken, boxId); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public MessageData GetMessage(string authToken, string boxId, string messageId) { - var request = BuildGetRequest("V1/Messages/GetMessage", authToken : authToken) - .WithAdditionalQueryParameter("boxId", boxId) - .WithAdditionalQueryParameter("messageId", messageId); + var request = BuildGetMessageRequest(authToken, boxId, messageId); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetMessageAsync(string authToken, string boxId, string messageId) + { + var request = BuildGetMessageRequest(authToken, boxId, messageId); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public InboxMessageMeta GetInboxMessageMeta(string authToken, string boxId, string messageId) { - var request = BuildGetRequest("V1/Messages/GetInboxMessageMeta", authToken : authToken) - .WithAdditionalQueryParameter("boxId", boxId) - .WithAdditionalQueryParameter("messageId", messageId); + var request = BuildGetInboxMessageMetaRequest(authToken, boxId, messageId); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetInboxMessageMetaAsync(string authToken, string boxId, string messageId) + { + var request = BuildGetInboxMessageMetaRequest(authToken, boxId, messageId); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public OutboxMessageMeta GetOutboxMessageMeta(string authToken, string boxId, string messageId) { - var request = BuildGetRequest("V1/Messages/GetOutboxMessageMeta", authToken : authToken) - .WithAdditionalQueryParameter("boxId", boxId) - .WithAdditionalQueryParameter("messageId", messageId); + var request = BuildGetOutboxMessageMetaRequest(authToken, boxId, messageId); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task GetOutboxMessageMetaAsync(string authToken, string boxId, string messageId) + { + var request = BuildGetOutboxMessageMetaRequest(authToken, boxId, messageId); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public OutboxMessageMeta SendMessage(string authToken, string boxId, MessageData messageData) { - var request = BuildPostRequest("V1/Messages/SendMessageExtended", null, authToken, messageData) - .WithAdditionalQueryParameter("boxId", boxId); + var request = BuildSendMessageRequest(authToken, boxId, messageData); var result = clusterClient.Send(request); EnsureSuccessResult(result); - return Serializer.Deserialize(result.Response.Content.ToString()); + return DeserializeResponse(result); + } + + public async Task SendMessageAsync(string authToken, string boxId, MessageData messageData) + { + var request = BuildSendMessageRequest(authToken, boxId, messageData); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponse(result); } public void MessageDeliveryStarted(string authToken, string boxId, string messageId) { - var request = BuildPostRequest("V1/Messages/MessageDeliveryStarted", authToken : authToken) - .WithAdditionalQueryParameter("boxId", boxId) - .WithAdditionalQueryParameter("messageId", messageId); + var request = BuildMessageDeliveryStartedRequest(authToken, boxId, messageId); var result = clusterClient.Send(request); EnsureSuccessResult(result); } + public async Task MessageDeliveryStartedAsync(string authToken, string boxId, string messageId) + { + var request = BuildMessageDeliveryStartedRequest(authToken, boxId, messageId); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + } + public void MessageDeliveryFinished(string authToken, string boxId, string messageId, MessageDeliveryResult messageDeliveryResult) { - var request = BuildPostRequest("V1/Messages/MessageDeliveryFinished", null, authToken, messageDeliveryResult) - .WithAdditionalQueryParameter("boxId", boxId) - .WithAdditionalQueryParameter("messageId", messageId); + var request = BuildMessageDeliveryFinishedRequest(authToken, boxId, messageId, messageDeliveryResult); var result = clusterClient.Send(request); EnsureSuccessResult(result); } + public async Task MessageDeliveryFinishedAsync(string authToken, string boxId, string messageId, MessageDeliveryResult messageDeliveryResult) + { + var request = BuildMessageDeliveryFinishedRequest(authToken, boxId, messageId, messageDeliveryResult); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + } + public MessageBoxEventBatch GetEvents(string authToken, string boxId, string? exclusiveEventId, uint? count = null) { - var request = BuildGetRequest("V1/Messages/GetEvents", authToken : authToken) - .WithAdditionalQueryParameter("boxId", boxId) - .WithAdditionalQueryParameter("exclusiveEventId", exclusiveEventId); + var request = BuildGetEventsFromExclusiveEventIdRequest(authToken, boxId, exclusiveEventId, count); - if (count.HasValue) - { - request = request.WithAdditionalQueryParameter("count", count.Value.ToString(CultureInfo.InvariantCulture)); - } + var result = clusterClient.Send(request); + EnsureSuccessResult(result); - return GetEventsInternal(request); + return DeserializeResponseEvents(result); } - public MessageBoxEventBatch GetEvents(string authToken, string boxId, DateTime fromDateTime, uint? count = null) + public async Task GetEventsAsync(string authToken, string boxId, string? exclusiveEventId, uint? count = null) { - var request = BuildGetRequest("V1/Messages/GetEventsFrom", authToken : authToken) - .WithAdditionalQueryParameter("boxId", boxId) - .WithAdditionalQueryParameter("fromDateTime", DateTimeUtils.ToString(fromDateTime)); + var request = BuildGetEventsFromExclusiveEventIdRequest(authToken, boxId, exclusiveEventId, count); - if (count.HasValue) - { - request = request.WithAdditionalQueryParameter("count", count.Value.ToString(CultureInfo.InvariantCulture)); - } + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); - return GetEventsInternal(request); + return DeserializeResponseEvents(result); } - private MessageBoxEventBatch GetEventsInternal(Request request) + public MessageBoxEventBatch GetEvents(string authToken, string boxId, DateTime fromDateTime, uint? count = null) { + var request = BuildGetEventsFromDateTimeRequest(authToken, boxId, fromDateTime, count); + var result = clusterClient.Send(request); EnsureSuccessResult(result); - var boxEventBatch = Serializer.Deserialize(result.Response.Content.ToString()); - boxEventBatch.Events ??= new MessageBoxEvent[0]; + return DeserializeResponseEvents(result); + } + + public async Task GetEventsAsync(string authToken, string boxId, DateTime fromDateTime, uint? count = null) + { + var request = BuildGetEventsFromDateTimeRequest(authToken, boxId, fromDateTime, count); + + var result = await clusterClient.SendAsync(request).ConfigureAwait(false); + EnsureSuccessResult(result); + + return DeserializeResponseEvents(result); + } + + private Request BuildGetBoxDocumentsSettingsRequest(string authToken, string boxId) + { + return BuildGetRequest("V1/Messages/GetBoxDocumentsSettings", authToken : authToken) + .WithAdditionalQueryParameter("boxId", boxId); + } + + private Request BuildGetMessageRequest(string authToken, string boxId, string messageId) + { + return BuildGetRequest("V1/Messages/GetMessage", authToken : authToken) + .WithAdditionalQueryParameter("boxId", boxId) + .WithAdditionalQueryParameter("messageId", messageId); + } + + private Request BuildGetInboxMessageMetaRequest(string authToken, string boxId, string messageId) + { + return BuildGetRequest("V1/Messages/GetInboxMessageMeta", authToken : authToken) + .WithAdditionalQueryParameter("boxId", boxId) + .WithAdditionalQueryParameter("messageId", messageId); + } + + private Request BuildGetOutboxMessageMetaRequest(string authToken, string boxId, string messageId) + { + return BuildGetRequest("V1/Messages/GetOutboxMessageMeta", authToken : authToken) + .WithAdditionalQueryParameter("boxId", boxId) + .WithAdditionalQueryParameter("messageId", messageId); + } + + private Request BuildSendMessageRequest(string authToken, string boxId, MessageData messageData) + { + return BuildPostRequest("V1/Messages/SendMessageExtended", null, authToken, messageData) + .WithAdditionalQueryParameter("boxId", boxId); + } + + private Request BuildMessageDeliveryStartedRequest(string authToken, string boxId, string messageId) + { + return BuildPostRequest("V1/Messages/MessageDeliveryStarted", authToken : authToken) + .WithAdditionalQueryParameter("boxId", boxId) + .WithAdditionalQueryParameter("messageId", messageId); + } + + private Request BuildMessageDeliveryFinishedRequest(string authToken, string boxId, string messageId, MessageDeliveryResult messageDeliveryResult) + { + return BuildPostRequest("V1/Messages/MessageDeliveryFinished", null, authToken, messageDeliveryResult) + .WithAdditionalQueryParameter("boxId", boxId) + .WithAdditionalQueryParameter("messageId", messageId); + } + + private Request BuildGetEventsFromExclusiveEventIdRequest(string authToken, string boxId, string? exclusiveEventId, uint? count) + { + var request = BuildGetRequest("V1/Messages/GetEvents", authToken : authToken) + .WithAdditionalQueryParameter("boxId", boxId) + .WithAdditionalQueryParameter("exclusiveEventId", exclusiveEventId); + return count != null + ? request.WithAdditionalQueryParameter("count", count.Value.ToString(CultureInfo.InvariantCulture)) + : request; + } + + private Request BuildGetEventsFromDateTimeRequest(string authToken, string boxId, DateTime fromDateTime, uint? count) + { + var request = BuildGetRequest("V1/Messages/GetEventsFrom", authToken : authToken) + .WithAdditionalQueryParameter("boxId", boxId) + .WithAdditionalQueryParameter("fromDateTime", DateTimeUtils.ToString(fromDateTime)); + return count != null + ? request.WithAdditionalQueryParameter("count", count.Value.ToString(CultureInfo.InvariantCulture)) + : request; + } + + private MessageBoxEventBatch DeserializeResponseEvents(ClusterResult result) + { + var boxEventBatch = DeserializeResponse(result); + boxEventBatch.Events ??= Array.Empty(); foreach (var boxEvent in boxEventBatch.Events) { boxEvent.EventContent = diff --git a/EdiApi.Client/Http/UserAgentProvider.cs b/EdiApi.Client/Http/UserAgentProvider.cs new file mode 100644 index 0000000..a95deac --- /dev/null +++ b/EdiApi.Client/Http/UserAgentProvider.cs @@ -0,0 +1,20 @@ +#nullable enable +using System.Runtime.InteropServices; + +namespace SkbKontur.EdiApi.Client.Http +{ + internal static class UserAgentProvider + { + static UserAgentProvider() + { + var sdkVersion = typeof(ClusterClientFactory).Assembly.GetName().Version.ToString(); + var dotnetDescription = RuntimeInformation.FrameworkDescription.Trim(); + var osDescription = RuntimeInformation.OSDescription.Trim(); + userAgentString = $"Kontur.EDI API SDK={sdkVersion};OS={osDescription};DOTNET={dotnetDescription}"; + } + + public static string GetUserAgent() => userAgentString; + + private static readonly string userAgentString; + } +} \ No newline at end of file diff --git a/EdiApi.Client/IBaseEdiApiClient.cs b/EdiApi.Client/IBaseEdiApiClient.cs index 1d1ba53..7ed5d58 100644 --- a/EdiApi.Client/IBaseEdiApiClient.cs +++ b/EdiApi.Client/IBaseEdiApiClient.cs @@ -1,3 +1,6 @@ +using System; +using System.Threading.Tasks; + using SkbKontur.EdiApi.Client.Types.Boxes; using SkbKontur.EdiApi.Client.Types.Logistics; using SkbKontur.EdiApi.Client.Types.Organization; @@ -11,24 +14,34 @@ namespace SkbKontur.EdiApi.Client { public interface IBaseEdiApiClient { + [Obsolete("Use new OpenId Connect authentication scheme")] string Authenticate(string portalSid); + [Obsolete("Use new OpenId Connect authentication scheme")] string Authenticate(string login, string password); PartiesInfo GetAccessiblePartiesInfo(string authToken); + Task GetAccessiblePartiesInfoAsync(string authToken); PartyInfo GetPartyInfo(string authToken, string partyId); + Task GetPartyInfoAsync(string authToken, string partyId); PartyInfo GetPartyInfoByGln(string authToken, string partyGln); + Task GetPartyInfoByGlnAsync(string authToken, string partyGln); BoxesInfo GetBoxesInfo(string authToken); + Task GetBoxesInfoAsync(string authToken); BoxInfo GetMainApiBox(string authToken, string partyId); + Task GetMainApiBoxAsync(string authToken, string partyId); OrganizationCatalogueInfo GetOrganizationCatalogueInfo(string authToken, string partyId); + Task GetOrganizationCatalogueInfoAsync(string authToken, string partyId); PartyInfo GetPartyInfoByDepartmentGln(string authToken, string departmentGln); + Task GetPartyInfoByDepartmentGlnAsync(string authToken, string departmentGln); TransportationDocumentIdentifier GetTransportationDocumentIdentifier(string authToken, string partyId); + Task GetTransportationDocumentIdentifierAsync(string authToken, string partyId); } } \ No newline at end of file diff --git a/EdiApi.Client/IInternalEdiApiHttpClient.cs b/EdiApi.Client/IInternalEdiApiHttpClient.cs index 322cf93..f4fc29e 100644 --- a/EdiApi.Client/IInternalEdiApiHttpClient.cs +++ b/EdiApi.Client/IInternalEdiApiHttpClient.cs @@ -12,6 +12,7 @@ namespace SkbKontur.EdiApi.Client { + [Obsolete("Internal integrators should use Internal Api V2")] public interface IInternalEdiApiHttpClient { Document? GetDocument(string authToken, DocumentId documentId, bool includeRelatedDocuments = true); diff --git a/EdiApi.Client/IMessagesEdiApiClient.cs b/EdiApi.Client/IMessagesEdiApiClient.cs index d8b5118..37daa5a 100644 --- a/EdiApi.Client/IMessagesEdiApiClient.cs +++ b/EdiApi.Client/IMessagesEdiApiClient.cs @@ -1,4 +1,5 @@ using System; +using System.Threading.Tasks; using SkbKontur.EdiApi.Client.Types.Common; using SkbKontur.EdiApi.Client.Types.Messages; @@ -11,21 +12,30 @@ namespace SkbKontur.EdiApi.Client public interface IMessagesEdiApiClient : IBaseEdiApiClient { BoxDocumentsSettings GetBoxDocumentsSettings(string authToken, string boxId); + Task GetBoxDocumentsSettingsAsync(string authToken, string boxId); MessageData GetMessage(string authToken, string boxId, string messageId); + Task GetMessageAsync(string authToken, string boxId, string messageId); InboxMessageMeta GetInboxMessageMeta(string authToken, string boxId, string messageId); + Task GetInboxMessageMetaAsync(string authToken, string boxId, string messageId); OutboxMessageMeta GetOutboxMessageMeta(string authToken, string boxId, string messageId); + Task GetOutboxMessageMetaAsync(string authToken, string boxId, string messageId); OutboxMessageMeta SendMessage(string authToken, string boxId, MessageData messageData); + Task SendMessageAsync(string authToken, string boxId, MessageData messageData); MessageBoxEventBatch GetEvents(string authToken, string boxId, string? exclusiveEventId, uint? count = null); + Task GetEventsAsync(string authToken, string boxId, string? exclusiveEventId, uint? count = null); MessageBoxEventBatch GetEvents(string authToken, string boxId, DateTime fromDateTime, uint? count = null); + Task GetEventsAsync(string authToken, string boxId, DateTime fromDateTime, uint? count = null); void MessageDeliveryStarted(string authToken, string boxId, string documentCirculationId); + Task MessageDeliveryStartedAsync(string authToken, string boxId, string documentCirculationId); void MessageDeliveryFinished(string authToken, string boxId, string documentCirculationId, MessageDeliveryResult messageDeliveryResult); + Task MessageDeliveryFinishedAsync(string authToken, string boxId, string documentCirculationId, MessageDeliveryResult messageDeliveryResult); } } \ No newline at end of file diff --git a/EdiApi.Client/Types/Internal/Document.cs b/EdiApi.Client/Types/Internal/Document.cs index 46265fd..c8e9d77 100644 --- a/EdiApi.Client/Types/Internal/Document.cs +++ b/EdiApi.Client/Types/Internal/Document.cs @@ -17,6 +17,8 @@ public class Document public string Number { get; set; } public DateTime? Date { get; set; } public LinkedDocumentInfo[] LinkedDocuments { get; set; } + public string MessageSendInterface { get; set; } + public string OrderChainDcId { get; set; } public OrdersFields OrdersFields { get; set; } public DesadvFields DesadvFields { get; set; } diff --git a/version.json b/version.json index 9e61cea..80d0ea1 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "2.20", + "version": "2.23-pre.4", "assemblyVersion": { "precision": "build" },