diff --git a/docs/en/framework/infrastructure/operation-rate-limiting.md b/docs/en/framework/infrastructure/operation-rate-limiting.md index 89e808d121..736152444f 100644 --- a/docs/en/framework/infrastructure/operation-rate-limiting.md +++ b/docs/en/framework/infrastructure/operation-rate-limiting.md @@ -274,6 +274,15 @@ When a rate limit is exceeded, `CheckAsync` throws `AbpOperationRateLimitingExce * Extends `BusinessException` and implements `IHasHttpStatusCode` with status code **429** (Too Many Requests). * Is automatically handled by ABP's exception handling pipeline and serialized into the HTTP response. +The exception uses one of two error codes depending on the policy type: + +| Error Code | Constant | When Used | +|---|---|---| +| `Volo.Abp.OperationRateLimiting:010001` | `AbpOperationRateLimitingErrorCodes.ExceedLimit` | Regular rate limit exceeded (has a retry-after window) | +| `Volo.Abp.OperationRateLimiting:010002` | `AbpOperationRateLimitingErrorCodes.ExceedLimitPermanently` | Ban policy (`maxCount: 0`, permanently denied) | + +You can override the error code per policy using `WithErrorCode()`. When a custom code is set, it is always used regardless of the policy type. + The exception includes the following data properties: | Key | Type | Description | @@ -282,9 +291,9 @@ The exception includes the following data properties: | `MaxCount` | int | Maximum allowed count | | `CurrentCount` | int | Current usage count | | `RemainingCount` | int | Remaining allowed count | -| `RetryAfterSeconds` | int | Seconds until the window resets | -| `RetryAfterMinutes` | int | Minutes until the window resets (rounded down) | -| `RetryAfter` | string | Localized retry-after description (e.g., "5 minutes") | +| `RetryAfterSeconds` | int | Seconds until the window resets (`0` for ban policies) | +| `RetryAfterMinutes` | int | Minutes until the window resets, rounded down (`0` for ban policies) | +| `RetryAfter` | string | Localized retry-after description (e.g., "5 minutes"); absent for ban policies | | `WindowDurationSeconds` | int | Total window duration in seconds | | `WindowDescription` | string | Localized window description | | `RuleDetails` | List | Per-rule details (for multi-rule policies) | @@ -329,7 +338,7 @@ public override void ConfigureServices(ServiceConfigurationContext context) ### Ban Policy (maxCount: 0) -Setting `maxCount` to `0` creates a ban policy that permanently denies all requests regardless of the window duration. The `RetryAfter` value will be `null` since there is no window to wait for: +Setting `maxCount` to `0` creates a ban policy that permanently denies all requests regardless of the window duration. The `RetryAfter` value will be `null` since there is no window to wait for. The exception uses the error code `Volo.Abp.OperationRateLimiting:010002` (`AbpOperationRateLimitingErrorCodes.ExceedLimitPermanently`) with the message "Operation rate limit exceeded. This request is permanently denied.": ````csharp options.AddPolicy("BlockedUser", policy => diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingErrorCodes.cs b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingErrorCodes.cs index 5ff8d88b5a..ba2bb5c189 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingErrorCodes.cs +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingErrorCodes.cs @@ -3,7 +3,12 @@ namespace Volo.Abp.OperationRateLimiting; public static class AbpOperationRateLimitingErrorCodes { /// - /// Default error code for rate limit exceeded. + /// Default error code for rate limit exceeded (with a retry-after window). /// public const string ExceedLimit = "Volo.Abp.OperationRateLimiting:010001"; + + /// + /// Error code for ban policy (maxCount: 0) where requests are permanently denied. + /// + public const string ExceedLimitPermanently = "Volo.Abp.OperationRateLimiting:010002"; } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Exceptions/AbpOperationRateLimitingException.cs b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Exceptions/AbpOperationRateLimitingException.cs index 9872d26e76..88cfb2c6ff 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Exceptions/AbpOperationRateLimitingException.cs +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Exceptions/AbpOperationRateLimitingException.cs @@ -15,7 +15,7 @@ public class AbpOperationRateLimitingException : BusinessException, IHasHttpStat string policyName, OperationRateLimitingResult result, string? errorCode = null) - : base(code: errorCode ?? AbpOperationRateLimitingErrorCodes.ExceedLimit) + : base(code: errorCode ?? ResolveDefaultErrorCode(result)) { PolicyName = policyName; Result = result; @@ -38,4 +38,11 @@ public class AbpOperationRateLimitingException : BusinessException, IHasHttpStat { WithData("WindowDescription", formattedWindowDescription); } + + private static string ResolveDefaultErrorCode(OperationRateLimitingResult result) + { + return result.RetryAfter.HasValue + ? AbpOperationRateLimitingErrorCodes.ExceedLimit + : AbpOperationRateLimitingErrorCodes.ExceedLimitPermanently; + } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ar.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ar.json index 46b937bb99..3ca1c8f042 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ar.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ar.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} ساعة/ساعات و {1} دقيقة/دقائق", "RetryAfter:Minutes": "{0} دقيقة/دقائق", "RetryAfter:MinutesAndSeconds": "{0} دقيقة/دقائق و {1} ثانية/ثوان", - "RetryAfter:Seconds": "{0} ثانية/ثوان" + "RetryAfter:Seconds": "{0} ثانية/ثوان", + "Volo.Abp.OperationRateLimiting:010002": "تم تجاوز حد معدل العملية. هذا الطلب مرفوض بشكل دائم." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/cs.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/cs.json index 205d229c10..44cfb86437 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/cs.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/cs.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} hodina/hodiny/hodin a {1} minuta/minuty/minut", "RetryAfter:Minutes": "{0} minuta/minuty/minut", "RetryAfter:MinutesAndSeconds": "{0} minuta/minuty/minut a {1} sekunda/sekundy/sekund", - "RetryAfter:Seconds": "{0} sekunda/sekundy/sekund" + "RetryAfter:Seconds": "{0} sekunda/sekundy/sekund", + "Volo.Abp.OperationRateLimiting:010002": "Byl překročen limit četnosti operace. Tento požadavek je trvale zamítnut." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/de.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/de.json index 3313e0156d..44286d68a8 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/de.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/de.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} Stunde(n) und {1} Minute(n)", "RetryAfter:Minutes": "{0} Minute(n)", "RetryAfter:MinutesAndSeconds": "{0} Minute(n) und {1} Sekunde(n)", - "RetryAfter:Seconds": "{0} Sekunde(n)" + "RetryAfter:Seconds": "{0} Sekunde(n)", + "Volo.Abp.OperationRateLimiting:010002": "Das Vorgangshäufigkeitslimit wurde überschritten. Diese Anfrage wird dauerhaft abgelehnt." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/el.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/el.json index 53359d6fa8..a688778eb5 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/el.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/el.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} ώρα/ες και {1} λεπτό/ά", "RetryAfter:Minutes": "{0} λεπτό/ά", "RetryAfter:MinutesAndSeconds": "{0} λεπτό/ά και {1} δευτερόλεπτο/α", - "RetryAfter:Seconds": "{0} δευτερόλεπτο/α" + "RetryAfter:Seconds": "{0} δευτερόλεπτο/α", + "Volo.Abp.OperationRateLimiting:010002": "Υπερβλήθηκε το όριο συχνότητας λειτουργίας. Αυτό το αίτημα απορρίπτεται μόνιμα." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/en-GB.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/en-GB.json index de3b1de3a3..4eab97f134 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/en-GB.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/en-GB.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} hour(s) and {1} minute(s)", "RetryAfter:Minutes": "{0} minute(s)", "RetryAfter:MinutesAndSeconds": "{0} minute(s) and {1} second(s)", - "RetryAfter:Seconds": "{0} second(s)" + "RetryAfter:Seconds": "{0} second(s)", + "Volo.Abp.OperationRateLimiting:010002": "Operation rate limit exceeded. This request is permanently denied." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/en.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/en.json index 0abcff4386..fc41cabc2f 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/en.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/en.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} hour(s) and {1} minute(s)", "RetryAfter:Minutes": "{0} minute(s)", "RetryAfter:MinutesAndSeconds": "{0} minute(s) and {1} second(s)", - "RetryAfter:Seconds": "{0} second(s)" + "RetryAfter:Seconds": "{0} second(s)", + "Volo.Abp.OperationRateLimiting:010002": "Operation rate limit exceeded. This request is permanently denied." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/es.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/es.json index 299ccd0fa2..ce13a9bceb 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/es.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/es.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} hora(s) y {1} minuto(s)", "RetryAfter:Minutes": "{0} minuto(s)", "RetryAfter:MinutesAndSeconds": "{0} minuto(s) y {1} segundo(s)", - "RetryAfter:Seconds": "{0} segundo(s)" + "RetryAfter:Seconds": "{0} segundo(s)", + "Volo.Abp.OperationRateLimiting:010002": "Se superó el límite de frecuencia de operación. Esta solicitud está permanentemente denegada." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fa.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fa.json index 09c7f21376..0f200b5472 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fa.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fa.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} ساعت و {1} دقیقه", "RetryAfter:Minutes": "{0} دقیقه", "RetryAfter:MinutesAndSeconds": "{0} دقیقه و {1} ثانیه", - "RetryAfter:Seconds": "{0} ثانیه" + "RetryAfter:Seconds": "{0} ثانیه", + "Volo.Abp.OperationRateLimiting:010002": "محدودیت نرخ عملیات از حد مجاز فراتر رفت. این درخواست به طور دائمی رد شده است." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fi.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fi.json index de379d5989..bcb88bf9ed 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fi.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fi.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} tunti/tuntia ja {1} minuutti/minuuttia", "RetryAfter:Minutes": "{0} minuutti/minuuttia", "RetryAfter:MinutesAndSeconds": "{0} minuutti/minuuttia ja {1} sekunti/sekuntia", - "RetryAfter:Seconds": "{0} sekunti/sekuntia" + "RetryAfter:Seconds": "{0} sekunti/sekuntia", + "Volo.Abp.OperationRateLimiting:010002": "Toiminnan nopeusraja ylitettiin. Tämä pyyntö on pysyvästi hylätty." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fr.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fr.json index b531b036f0..dca23d7a80 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fr.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fr.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} heure(s) et {1} minute(s)", "RetryAfter:Minutes": "{0} minute(s)", "RetryAfter:MinutesAndSeconds": "{0} minute(s) et {1} seconde(s)", - "RetryAfter:Seconds": "{0} seconde(s)" + "RetryAfter:Seconds": "{0} seconde(s)", + "Volo.Abp.OperationRateLimiting:010002": "La limite de fréquence d'opération a été dépassée. Cette demande est définitivement refusée." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hi.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hi.json index 6a53a5106e..a84a1e44a8 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hi.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hi.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} घंटा/घंटे और {1} मिनट", "RetryAfter:Minutes": "{0} मिनट", "RetryAfter:MinutesAndSeconds": "{0} मिनट और {1} सेकंड", - "RetryAfter:Seconds": "{0} सेकंड" + "RetryAfter:Seconds": "{0} सेकंड", + "Volo.Abp.OperationRateLimiting:010002": "ऑपरेशन दर सीमा पार हो गई। यह अनुरोध स्थायी रूप से अस्वीकृत है।" } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hr.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hr.json index d8a0ce4a18..c6597be78e 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hr.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hr.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} sat/i i {1} minuta/e", "RetryAfter:Minutes": "{0} minuta/e", "RetryAfter:MinutesAndSeconds": "{0} minuta/e i {1} sekunda/e", - "RetryAfter:Seconds": "{0} sekunda/e" + "RetryAfter:Seconds": "{0} sekunda/e", + "Volo.Abp.OperationRateLimiting:010002": "Prekoračeno je ograničenje brzine operacije. Ovaj zahtjev je trajno odbijen." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hu.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hu.json index b1ece6246a..f72dfea397 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hu.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hu.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} óra és {1} perc", "RetryAfter:Minutes": "{0} perc", "RetryAfter:MinutesAndSeconds": "{0} perc és {1} másodperc", - "RetryAfter:Seconds": "{0} másodperc" + "RetryAfter:Seconds": "{0} másodperc", + "Volo.Abp.OperationRateLimiting:010002": "A műveleti ráta korlátja túllépve. Ez a kérés véglegesen elutasítva." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/is.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/is.json index 45c6255ee1..cce36e42cd 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/is.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/is.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} klukkustund(ir) og {1} mínúta/úr", "RetryAfter:Minutes": "{0} mínúta/úr", "RetryAfter:MinutesAndSeconds": "{0} mínúta/úr og {1} sekúnda/úr", - "RetryAfter:Seconds": "{0} sekúnda/úr" + "RetryAfter:Seconds": "{0} sekúnda/úr", + "Volo.Abp.OperationRateLimiting:010002": "Farið var yfir takmörk á rekstrartíðni. Þessari beiðni er varanlega hafnað." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/it.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/it.json index f93fb278bf..f602fd1a66 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/it.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/it.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} ora/e e {1} minuto/i", "RetryAfter:Minutes": "{0} minuto/i", "RetryAfter:MinutesAndSeconds": "{0} minuto/i e {1} secondo/i", - "RetryAfter:Seconds": "{0} secondo/i" + "RetryAfter:Seconds": "{0} secondo/i", + "Volo.Abp.OperationRateLimiting:010002": "Limite di frequenza operazione superato. Questa richiesta è permanentemente negata." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/nl.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/nl.json index a733537123..bb21e7f313 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/nl.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/nl.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} uur en {1} minuut/minuten", "RetryAfter:Minutes": "{0} minuut/minuten", "RetryAfter:MinutesAndSeconds": "{0} minuut/minuten en {1} seconde(n)", - "RetryAfter:Seconds": "{0} seconde(n)" + "RetryAfter:Seconds": "{0} seconde(n)", + "Volo.Abp.OperationRateLimiting:010002": "Het bewerkingsfrequentielimiet is overschreden. Dit verzoek wordt permanent geweigerd." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/pl-PL.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/pl-PL.json index 72d6c905a5..e4503f6aa7 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/pl-PL.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/pl-PL.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} godzina/godzin i {1} minuta/minut", "RetryAfter:Minutes": "{0} minuta/minut", "RetryAfter:MinutesAndSeconds": "{0} minuta/minut i {1} sekunda/sekund", - "RetryAfter:Seconds": "{0} sekunda/sekund" + "RetryAfter:Seconds": "{0} sekunda/sekund", + "Volo.Abp.OperationRateLimiting:010002": "Przekroczono limit częstotliwości operacji. To żądanie jest trwale odrzucone." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/pt-BR.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/pt-BR.json index 412f7f2389..fb6f873805 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/pt-BR.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/pt-BR.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} hora(s) e {1} minuto(s)", "RetryAfter:Minutes": "{0} minuto(s)", "RetryAfter:MinutesAndSeconds": "{0} minuto(s) e {1} segundo(s)", - "RetryAfter:Seconds": "{0} segundo(s)" + "RetryAfter:Seconds": "{0} segundo(s)", + "Volo.Abp.OperationRateLimiting:010002": "Limite de taxa de operação excedido. Esta solicitação está permanentemente negada." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ro-RO.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ro-RO.json index cef165fa42..178042fa85 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ro-RO.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ro-RO.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} oră/ore și {1} minut(e)", "RetryAfter:Minutes": "{0} minut(e)", "RetryAfter:MinutesAndSeconds": "{0} minut(e) și {1} secundă/secunde", - "RetryAfter:Seconds": "{0} secundă/secunde" + "RetryAfter:Seconds": "{0} secundă/secunde", + "Volo.Abp.OperationRateLimiting:010002": "Limita de rată a operației a fost depășită. Această solicitare este permanent refuzată." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ru.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ru.json index dc4ddf6db6..5260a9c90c 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ru.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ru.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} час/часов и {1} минута/минут", "RetryAfter:Minutes": "{0} минута/минут", "RetryAfter:MinutesAndSeconds": "{0} минута/минут и {1} секунда/секунд", - "RetryAfter:Seconds": "{0} секунда/секунд" + "RetryAfter:Seconds": "{0} секунда/секунд", + "Volo.Abp.OperationRateLimiting:010002": "Превышен лимит частоты операций. Этот запрос постоянно отклонён." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sk.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sk.json index bd849adb48..73cdbb2b5d 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sk.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sk.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} hodina/hodín a {1} minúta/minút", "RetryAfter:Minutes": "{0} minúta/minút", "RetryAfter:MinutesAndSeconds": "{0} minúta/minút a {1} sekunda/sekúnd", - "RetryAfter:Seconds": "{0} sekunda/sekúnd" + "RetryAfter:Seconds": "{0} sekunda/sekúnd", + "Volo.Abp.OperationRateLimiting:010002": "Bol prekročený limit frekvencie operácie. Táto požiadavka je trvalo zamietnutá." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sl.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sl.json index eb6c54980e..333f51efb5 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sl.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sl.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} ura/ur in {1} minuta/minut", "RetryAfter:Minutes": "{0} minuta/minut", "RetryAfter:MinutesAndSeconds": "{0} minuta/minut in {1} sekunda/sekund", - "RetryAfter:Seconds": "{0} sekunda/sekund" + "RetryAfter:Seconds": "{0} sekunda/sekund", + "Volo.Abp.OperationRateLimiting:010002": "Prekoračena je omejitev hitrosti operacije. Ta zahteva je trajno zavrnjena." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sv.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sv.json index 562ba3d586..ef5172867c 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sv.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sv.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} timme/timmar och {1} minut(er)", "RetryAfter:Minutes": "{0} minut(er)", "RetryAfter:MinutesAndSeconds": "{0} minut(er) och {1} sekund(er)", - "RetryAfter:Seconds": "{0} sekund(er)" + "RetryAfter:Seconds": "{0} sekund(er)", + "Volo.Abp.OperationRateLimiting:010002": "Hastighetsgränsen för operationen har överskridits. Denna förfrågan är permanent nekad." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/tr.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/tr.json index 3ce04aa915..0480003f9c 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/tr.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/tr.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} saat ve {1} dakika", "RetryAfter:Minutes": "{0} dakika", "RetryAfter:MinutesAndSeconds": "{0} dakika ve {1} saniye", - "RetryAfter:Seconds": "{0} saniye" + "RetryAfter:Seconds": "{0} saniye", + "Volo.Abp.OperationRateLimiting:010002": "İşlem hızı sınırı aşıldı. Bu istek kalıcı olarak reddedildi." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/vi.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/vi.json index 6b0ee47927..53059f819c 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/vi.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/vi.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} giờ và {1} phút", "RetryAfter:Minutes": "{0} phút", "RetryAfter:MinutesAndSeconds": "{0} phút và {1} giây", - "RetryAfter:Seconds": "{0} giây" + "RetryAfter:Seconds": "{0} giây", + "Volo.Abp.OperationRateLimiting:010002": "Vượt quá giới hạn tần suất thao tác. Yêu cầu này bị từ chối vĩnh viễn." } } diff --git a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/zh-Hans.json b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/zh-Hans.json index 6472587357..632d0e438f 100644 --- a/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/zh-Hans.json +++ b/framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/zh-Hans.json @@ -12,6 +12,7 @@ "RetryAfter:HoursAndMinutes": "{0} 小时 {1} 分钟", "RetryAfter:Minutes": "{0} 分钟", "RetryAfter:MinutesAndSeconds": "{0} 分钟 {1} 秒", - "RetryAfter:Seconds": "{0} 秒" + "RetryAfter:Seconds": "{0} 秒", + "Volo.Abp.OperationRateLimiting:010002": "操作频率超出限制。此请求已被永久拒绝。" } } diff --git a/framework/test/Volo.Abp.OperationRateLimiting.Tests/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingException_Tests.cs b/framework/test/Volo.Abp.OperationRateLimiting.Tests/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingException_Tests.cs index bf20e1f6a4..9d88c5e57d 100644 --- a/framework/test/Volo.Abp.OperationRateLimiting.Tests/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingException_Tests.cs +++ b/framework/test/Volo.Abp.OperationRateLimiting.Tests/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingException_Tests.cs @@ -24,14 +24,15 @@ public class AbpOperationRateLimitingException_Tests } [Fact] - public void Should_Set_Default_ErrorCode() + public void Should_Use_ExceedLimit_Code_When_RetryAfter_Is_Set() { var result = new OperationRateLimitingResult { IsAllowed = false, MaxCount = 3, CurrentCount = 3, - RemainingCount = 0 + RemainingCount = 0, + RetryAfter = TimeSpan.FromMinutes(5) }; var exception = new AbpOperationRateLimitingException("TestPolicy", result); @@ -39,6 +40,23 @@ public class AbpOperationRateLimitingException_Tests exception.Code.ShouldBe(AbpOperationRateLimitingErrorCodes.ExceedLimit); } + [Fact] + public void Should_Use_ExceedLimitPermanently_Code_When_RetryAfter_Is_Null() + { + var result = new OperationRateLimitingResult + { + IsAllowed = false, + MaxCount = 0, + CurrentCount = 0, + RemainingCount = 0, + RetryAfter = null + }; + + var exception = new AbpOperationRateLimitingException("TestPolicy", result); + + exception.Code.ShouldBe(AbpOperationRateLimitingErrorCodes.ExceedLimitPermanently); + } + [Fact] public void Should_Set_Custom_ErrorCode() { diff --git a/framework/test/Volo.Abp.OperationRateLimiting.Tests/Volo/Abp/OperationRateLimiting/OperationRateLimitingChecker_Tests.cs b/framework/test/Volo.Abp.OperationRateLimiting.Tests/Volo/Abp/OperationRateLimiting/OperationRateLimitingChecker_Tests.cs index 08a605c894..fd3d9f4214 100644 --- a/framework/test/Volo.Abp.OperationRateLimiting.Tests/Volo/Abp/OperationRateLimiting/OperationRateLimitingChecker_Tests.cs +++ b/framework/test/Volo.Abp.OperationRateLimiting.Tests/Volo/Abp/OperationRateLimiting/OperationRateLimitingChecker_Tests.cs @@ -655,6 +655,7 @@ public class OperationRateLimitingChecker_Tests : OperationRateLimitingTestBase exception.Result.MaxCount.ShouldBe(0); exception.Result.RetryAfter.ShouldBeNull(); exception.HttpStatusCode.ShouldBe(429); + exception.Code.ShouldBe(AbpOperationRateLimitingErrorCodes.ExceedLimitPermanently); } [Fact]