Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,13 @@ var result = amazonConnection.Notification.CreateSubscription(

> **Tip:** if your subscriptions include `APPLICATION_OAUTH_CLIENT_NEW_SECRET`, wrap your `IMessageReceiver` with [`RotationApplyingMessageReceiver`](#application-management-v2023-11-30--rotate-the-lwa-client-secret) so a rotated client secret is applied to `amazonConnection.Credentials.ClientSecret` automatically before your receiver sees the message.

How the receive loop behaves:

- **Long polling is on by default** (20 seconds). Leave `WaitTimeSeconds` unset unless you have a reason to change it; passing `0` forces short polling, which returns fewer messages per call and adds a 5 second pause between empty receives.
- **Up to 10 messages are received per call**, handed to your receiver one by one, then deleted with a single batch call.
- **Deletion** is controlled by `isDeleteNotificationAfterRead` (default `true` for `IMessageReceiver`). Implement `IMessageReceiverWithResult` instead and pass `false` if you want to decide per message - return `true` to delete, `false` to leave the message for redelivery after its visibility timeout.
- **One loop per call.** To drain a queue that has built up a backlog, start several `StartReceivingNotificationMessagesAsync` tasks against the same queue - SQS hands each receive call a different set of messages.

```CSharp

var SQS_URL = Environment.GetEnvironmentVariable("SQS_URL");
Expand All @@ -506,7 +513,7 @@ var param = new ParameterMessageReceiver(
Environment.GetEnvironmentVariable("SecretKey"),
SQS_URL,
Amazon.RegionEndpoint.USEast2,
WaitTimeSeconds: 20); // Enable SQS long polling to reduce empty receives and cost
WaitTimeSeconds: 20); // Optional - long polling (20s) is the default; pass 0 for short polling

var messageReceiver = new CustomMessageReceiver();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,13 @@ public Task StartReceivingWithRotationApplyAsync(
string awsAccessKeyId,
string awsSecretAccessKey,
RegionEndpoint region,
IClientSecretStore store = null)
IClientSecretStore? store = null)
{
// The onRotated callback fires AFTER the secret has been applied to the live
// AmazonCredential, so the running connection already uses the new secret by
// the time we persist. Wrap the IO call so a DB outage doesn't kill the SQS
// consumer loop — the SDK has already kept the in-memory credential current.
Action<ApplicationOAuthClientNewSecretNotification> persist = null;
Action<ApplicationOAuthClientNewSecretNotification>? persist = null;
if (store != null)
{
persist = payload =>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@
</ItemGroup>

<ItemGroup>
<PackageReference Include="AWSSDK.SecurityToken" Version="4.0.6.2" />
<PackageReference Include="AWSSDK.SQS" Version="4.0.2.27" />
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="10.0.7" />
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="10.0.7" />
Expand Down
10 changes: 5 additions & 5 deletions Source/FikaAmazonAPI.SampleCode/LoggingExamples.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,11 @@ public LoggingExamples(IConfigurationRoot config)
//AccessKey = config.GetSection("FikaAmazonAPI:AccessKey").Value,
//SecretKey = config.GetSection("FikaAmazonAPI:SecretKey").Value,
//RoleArn = config.GetSection("FikaAmazonAPI:RoleArn").Value,
ClientId = config.GetSection("FikaAmazonAPI:ClientId").Value,
ClientSecret = config.GetSection("FikaAmazonAPI:ClientSecret").Value,
RefreshToken = config.GetSection("FikaAmazonAPI:RefreshToken").Value,
MarketPlaceID = config.GetSection("FikaAmazonAPI:MarketPlaceID").Value,
SellerID = config.GetSection("FikaAmazonAPI:SellerId").Value,
ClientId = config.Required("FikaAmazonAPI:ClientId"),
ClientSecret = config.Required("FikaAmazonAPI:ClientSecret"),
RefreshToken = config.Required("FikaAmazonAPI:RefreshToken"),
MarketPlaceID = config.Required("FikaAmazonAPI:MarketPlaceID"),
SellerID = config.Required("FikaAmazonAPI:SellerId"),
IsDebugMode = true,
Environment = Constants.Environments.Sandbox
}, loggerFactory: factory);
Expand Down
10 changes: 4 additions & 6 deletions Source/FikaAmazonAPI.SampleCode/NotificationsSample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -175,21 +175,19 @@ public void SetUpSqsNotifications()
public async Task StartReceivingNotificationMessagesAsync(CancellationToken cancellationToken)
{
// Prevent unobserved task exceptions from crashing the process.
// The library fires off ProcessAnyOfferChangedMessage without await,
// so any exception in that path becomes an unobserved task exception.
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
Console.WriteLine($"Unobserved task exception caught: {e.Exception?.Message}");
e.SetObserved();
};

var SQS_URL = Environment.GetEnvironmentVariable("SQS_URL");
var SQS_URL = SampleConfiguration.RequiredEnv("SQS_URL");
var param = new ParameterMessageReceiver(
Environment.GetEnvironmentVariable("AccessKey"),
Environment.GetEnvironmentVariable("SecretKey"),
SampleConfiguration.RequiredEnv("AccessKey"),
SampleConfiguration.RequiredEnv("SecretKey"),
SQS_URL,
Amazon.RegionEndpoint.USEast2,
WaitTimeSeconds: 20); // Enable SQS long polling to reduce empty receives and cost
WaitTimeSeconds: 20); // Optional - long polling (20s) is the default; pass 0 for short polling

var messageReceiver = new CustomMessageReceiver();

Expand Down
10 changes: 5 additions & 5 deletions Source/FikaAmazonAPI.SampleCode/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@ static async Task Main(string[] args)

AmazonConnection amazonConnection = new AmazonConnection(new AmazonCredential()
{
ClientId = config.GetSection("FikaAmazonAPI:ClientId").Value,
ClientSecret = config.GetSection("FikaAmazonAPI:ClientSecret").Value,
RefreshToken = config.GetSection("FikaAmazonAPI:RefreshToken").Value,
MarketPlaceID = config.GetSection("FikaAmazonAPI:MarketPlaceID").Value,
SellerID = config.GetSection("FikaAmazonAPI:SellerId").Value,
ClientId = config.Required("FikaAmazonAPI:ClientId"),
ClientSecret = config.Required("FikaAmazonAPI:ClientSecret"),
RefreshToken = config.Required("FikaAmazonAPI:RefreshToken"),
MarketPlaceID = config.Required("FikaAmazonAPI:MarketPlaceID"),
SellerID = config.Required("FikaAmazonAPI:SellerId"),
IsDebugMode = true,
});

Expand Down
2 changes: 1 addition & 1 deletion Source/FikaAmazonAPI.SampleCode/ReportsSample.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public string CreateReport_GET_FLAT_FILE_RETURNS_DATA_BY_RETURN_DATE()
}


public string CreateReportAndDawnload(ReportTypes reportTypes, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions reportOptions = null)
public string CreateReportAndDawnload(ReportTypes reportTypes, DateTime? dataStartTime = null, DateTime? dataEndTime = null, ReportOptions? reportOptions = null)
{
return amazonConnection.Reports.CreateReportAndDownloadFile(reportTypes, dataStartTime, dataEndTime, reportOptions);
}
Expand Down
27 changes: 27 additions & 0 deletions Source/FikaAmazonAPI.SampleCode/SampleConfiguration.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Microsoft.Extensions.Configuration;

namespace FikaAmazonAPI.SampleCode
{
/// <summary>
/// Helpers for reading the credentials the samples need.
///
/// <see cref="AmazonCredential"/> requires ClientId, ClientSecret and RefreshToken —
/// <c>AmazonConnection.ValidateCredentials</c> throws when any of them is missing.
/// Reading them through these helpers fails at the point of the missing setting and
/// names the key, instead of letting a null travel into the SDK.
/// </summary>
public static class SampleConfiguration
{
/// <summary>Reads a required setting from configuration (appsettings.json / user secrets).</summary>
public static string Required(this IConfiguration config, string key) =>
config.GetSection(key).Value
?? throw new InvalidOperationException(
$"Missing configuration value '{key}'. Add it to appsettings.json or user secrets.");

/// <summary>Reads a required environment variable.</summary>
public static string RequiredEnv(string name) =>
Environment.GetEnvironmentVariable(name)
?? throw new InvalidOperationException(
$"Missing environment variable '{name}'.");
}
}
10 changes: 5 additions & 5 deletions Source/FikaAmazonAPI.SampleCode/SerilogLoggingExamples.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,11 @@ public SerilogLoggingExamples(IConfigurationRoot config)
//AccessKey = config.GetSection("FikaAmazonAPI:AccessKey").Value,
//SecretKey = config.GetSection("FikaAmazonAPI:SecretKey").Value,
//RoleArn = config.GetSection("FikaAmazonAPI:RoleArn").Value,
ClientId = config.GetSection("FikaAmazonAPI:ClientId").Value,
ClientSecret = config.GetSection("FikaAmazonAPI:ClientSecret").Value,
RefreshToken = config.GetSection("FikaAmazonAPI:RefreshToken").Value,
MarketPlaceID = config.GetSection("FikaAmazonAPI:MarketPlaceID").Value,
SellerID = config.GetSection("FikaAmazonAPI:SellerId").Value,
ClientId = config.Required("FikaAmazonAPI:ClientId"),
ClientSecret = config.Required("FikaAmazonAPI:ClientSecret"),
RefreshToken = config.Required("FikaAmazonAPI:RefreshToken"),
MarketPlaceID = config.Required("FikaAmazonAPI:MarketPlaceID"),
SellerID = config.Required("FikaAmazonAPI:SellerId"),
IsDebugMode = true,
Environment = Constants.Environments.Sandbox
}, loggerFactory: factory);
Expand Down
24 changes: 24 additions & 0 deletions Source/FikaAmazonAPI/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# EditorConfig for the FikaAmazonAPI library.
# https://editorconfig.org

root = false

# AmazonSpApiSDK/Models/** is swagger-generated from Amazon's OpenAPI specs
# (https://github.com/amzn/selling-partner-api-models) and is overwritten whenever
# the specs are regenerated. The generator emits required-property null guards and
# generated Equals/GetHashCode bodies that test non-nullable value types (enums,
# decimal, int) against null:
#
# if (unit == null) throw new InvalidDataException("unit is a required property...");
#
# That produces ~400 CS0472 "expression is always true/false" warnings which are
# harmless, cannot be fixed without hand-editing generated code, and would come
# straight back on the next regeneration. Silence CS0472 for the generated models
# only, so the warning stays live for hand-written code under Services/, Parameter/
# and ReportGeneration/.
# CS0109 comes from the same source: generated collection wrappers declare
# "public new string ToJson()" on a class deriving from List<T>, which has no ToJson
# to hide. Also generator noise, also regenerated on every refresh.
[AmazonSpApiSDK/Models/**.cs]
dotnet_diagnostic.CS0472.severity = none
dotnet_diagnostic.CS0109.severity = none
2 changes: 1 addition & 1 deletion Source/FikaAmazonAPI/AmazonConnection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ public class AmazonConnection
private UnauthorizedAccessException _NoCredentials = new UnauthorizedAccessException($"Error, you cannot make calls to Amazon without credentials!");

public string RefNumber { get; set; }
public AmazonConnection(AmazonCredential Credentials, string RefNumber = null, CultureInfo? cultureInfo = null, ILoggerFactory? loggerFactory = null)
public AmazonConnection(AmazonCredential Credentials, string? RefNumber = null, CultureInfo? cultureInfo = null, ILoggerFactory? loggerFactory = null)
{
_loggerFactory = loggerFactory;
this.Authenticate(Credentials);
Expand Down
2 changes: 1 addition & 1 deletion Source/FikaAmazonAPI/AmazonCredential.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public AmazonCredential()
}

public AmazonCredential(string AccessKey, string SecretKey, string RoleArn, string ClientId,
string ClientSecret, string RefreshToken, string ProxyAddress = null)
string ClientSecret, string RefreshToken, string? ProxyAddress = null)
{
this.AccessKey = AccessKey;
this.SecretKey = SecretKey;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ protected ItemContributor() { }
/// <param name="itemContributorRole">The role of the contributor</param>
public ItemContributor(string value = default(string), ItemContributorRole itemContributorRole = default)
{
Role = new ItemContributorRole();
this.Value = value;
this.Role = itemContributorRole;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public virtual string ToJson()
/// <returns>Boolean</returns>
public override bool Equals(object input)
{
return this.Equals(input as ItemImage);
return this.Equals(input as ItemContributorRole);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public override string ToString()
/// <returns>Boolean</returns>
public override bool Equals(object input)
{
return this.Equals(input as ItemImages);
return this.Equals(input as ItemContributors);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ public class AmazonException : Exception
{
public ExceptionResponse Response { get; set; }

public AmazonException(string msg, RestResponse response = null) : base(msg)
public AmazonException(string msg, RestResponse? response = null) : base(msg)
{
if (response != null)
{
Expand All @@ -22,15 +22,15 @@ public AmazonException(string msg, RestResponse response = null) : base(msg)

public class AmazonNotFoundException : AmazonException
{
public AmazonNotFoundException(string msg, RestResponse response = null) : base(msg, response)
public AmazonNotFoundException(string msg, RestResponse? response = null) : base(msg, response)
{

}
}

public class AmazonUnauthorizedException : AmazonException
{
public AmazonUnauthorizedException(string msg, RestResponse response = null) : base(msg, response)
public AmazonUnauthorizedException(string msg, RestResponse? response = null) : base(msg, response)
{

}
Expand All @@ -40,7 +40,7 @@ public class AmazonInvalidInputException : AmazonException
{
public string Details { get; set; }

public AmazonInvalidInputException(string msg, string details = null, RestResponse response = null) : base(msg, response)
public AmazonInvalidInputException(string msg, string? details = null, RestResponse? response = null) : base(msg, response)
{
this.Details = details;
//this.Data["Details"] = details;
Expand All @@ -49,31 +49,31 @@ public AmazonInvalidInputException(string msg, string details = null, RestRespon

public class AmazonQuotaExceededException : AmazonException
{
public AmazonQuotaExceededException(string msg, RestResponse response = null) : base(msg, response)
public AmazonQuotaExceededException(string msg, RestResponse? response = null) : base(msg, response)
{

}
}

public class AmazonInvalidSignatureException : AmazonException
{
public AmazonInvalidSignatureException(string msg, RestResponse response = null) : base(msg, response)
public AmazonInvalidSignatureException(string msg, RestResponse? response = null) : base(msg, response)
{

}
}

public class AmazonInternalErrorException : AmazonException
{
public AmazonInternalErrorException(string msg, RestResponse response = null) : base(msg, response)
public AmazonInternalErrorException(string msg, RestResponse? response = null) : base(msg, response)
{

}
}

public class AmazonBadRequestException : AmazonException
{
public AmazonBadRequestException(string msg, RestResponse response = null) : base(msg, response)
public AmazonBadRequestException(string msg, RestResponse? response = null) : base(msg, response)
{

}
Expand All @@ -82,7 +82,7 @@ public AmazonBadRequestException(string msg, RestResponse response = null) : bas
public class AmazonProcessingReportDeserializeException : AmazonException
{
public string ReportContent { get; set; }
public AmazonProcessingReportDeserializeException(string msg, string reportContent, RestResponse response = null) : base(msg, response)
public AmazonProcessingReportDeserializeException(string msg, string reportContent, RestResponse? response = null) : base(msg, response)
{
ReportContent = reportContent;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ public string ToJson()
/// <returns>Boolean</returns>
public override bool Equals(object input)
{
return this.Equals(input as GetFeedsResponse);
return this.Equals(input as GetFeedsResponseV00);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ public class AmazonFilter
public int Limit { get; set; }
public string NextPage { get; set; }

public AmazonFilter(int limit, string href = null)
public AmazonFilter(int limit, string? href = null)
{
Limit = limit;
NextPage = href;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,13 @@ public enum RelatedIdentifierNameEnum
[EnumMember(Value = "SETTLEMENT_ID")]
SETTLEMENTID = 11,
[EnumMember(Value = "SAFET_CLAIM_ID")]
SAFETCLAIMID = 12
SAFETCLAIMID = 12,

/// <summary>
/// Enum OBFUSCATEDSHIPMENTID for value: OBFUSCATED_SHIPMENT_ID
/// </summary>
[EnumMember(Value = "OBFUSCATED_SHIPMENT_ID")]
OBFUSCATEDSHIPMENTID = 13
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -217,14 +217,10 @@ public override int GetHashCode()
unchecked // Overflow is fine, just wrap
{
int hashCode = 41;
if (this.EarliestShipDate != null)
hashCode = hashCode * 59 + this.EarliestShipDate.GetHashCode();
if (this.LatestShipDate != null)
hashCode = hashCode * 59 + this.LatestShipDate.GetHashCode();
if (this.EarliestArrivalDate != null)
hashCode = hashCode * 59 + this.EarliestArrivalDate.GetHashCode();
if (this.LatestArrivalDate != null)
hashCode = hashCode * 59 + this.LatestArrivalDate.GetHashCode();
hashCode = hashCode * 59 + this.EarliestShipDateTime.GetHashCode();
hashCode = hashCode * 59 + this.LatestShipDateTime.GetHashCode();
hashCode = hashCode * 59 + this.EarliestArrivalDateTime.GetHashCode();
hashCode = hashCode * 59 + this.LatestArrivalDateTime.GetHashCode();
if (this.FulfillmentPreviewItems != null)
hashCode = hashCode * 59 + this.FulfillmentPreviewItems.GetHashCode();
return hashCode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public AsinIdentifier() { }
/// <param name="asin">Amazon Standard Identification Number (ASIN) of the listings item.</param>
public AsinIdentifier(string marketplaceId = default(string), string asin = default(string))
{

this.MarketplaceId = marketplaceId;
this.Asin = asin;
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ protected Audience() { }
/// <param name="displayName">Localized display name for the audience.</param>
public Audience(OfferAudienceEnum? value = default(OfferAudienceEnum?), string displayName = default(string))
{

this.Value = value;
this.DisplayName = displayName;
}

/// <summary>
Expand Down
Loading