Browse Source

feat: Enhance operation rate limiting with permanent denial error codes

pull/25024/head
maliming 4 weeks ago
parent
commit
76b279c6ac
No known key found for this signature in database GPG Key ID: A646B9CB645ECEA4
  1. 17
      docs/en/framework/infrastructure/operation-rate-limiting.md
  2. 7
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingErrorCodes.cs
  3. 9
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Exceptions/AbpOperationRateLimitingException.cs
  4. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ar.json
  5. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/cs.json
  6. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/de.json
  7. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/el.json
  8. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/en-GB.json
  9. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/en.json
  10. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/es.json
  11. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fa.json
  12. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fi.json
  13. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/fr.json
  14. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hi.json
  15. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hr.json
  16. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/hu.json
  17. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/is.json
  18. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/it.json
  19. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/nl.json
  20. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/pl-PL.json
  21. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/pt-BR.json
  22. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ro-RO.json
  23. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/ru.json
  24. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sk.json
  25. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sl.json
  26. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/sv.json
  27. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/tr.json
  28. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/vi.json
  29. 3
      framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/Localization/zh-Hans.json
  30. 22
      framework/test/Volo.Abp.OperationRateLimiting.Tests/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingException_Tests.cs
  31. 1
      framework/test/Volo.Abp.OperationRateLimiting.Tests/Volo/Abp/OperationRateLimiting/OperationRateLimitingChecker_Tests.cs

17
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 =>

7
framework/src/Volo.Abp.OperationRateLimiting/Volo/Abp/OperationRateLimiting/AbpOperationRateLimitingErrorCodes.cs

@ -3,7 +3,12 @@ namespace Volo.Abp.OperationRateLimiting;
public static class AbpOperationRateLimitingErrorCodes
{
/// <summary>
/// Default error code for rate limit exceeded.
/// Default error code for rate limit exceeded (with a retry-after window).
/// </summary>
public const string ExceedLimit = "Volo.Abp.OperationRateLimiting:010001";
/// <summary>
/// Error code for ban policy (maxCount: 0) where requests are permanently denied.
/// </summary>
public const string ExceedLimitPermanently = "Volo.Abp.OperationRateLimiting:010002";
}

9
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;
}
}

3
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": "تم تجاوز حد معدل العملية. هذا الطلب مرفوض بشكل دائم."
}
}

3
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."
}
}

3
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."
}
}

3
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": "Υπερβλήθηκε το όριο συχνότητας λειτουργίας. Αυτό το αίτημα απορρίπτεται μόνιμα."
}
}

3
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."
}
}

3
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."
}
}

3
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."
}
}

3
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": "محدودیت نرخ عملیات از حد مجاز فراتر رفت. این درخواست به طور دائمی رد شده است."
}
}

3
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."
}
}

3
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."
}
}

3
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": "ऑपरेशन दर सीमा पार हो गई। यह अनुरोध स्थायी रूप से अस्वीकृत है।"
}
}

3
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."
}
}

3
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."
}
}

3
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ð."
}
}

3
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."
}
}

3
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."
}
}

3
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."
}
}

3
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."
}
}

3
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ă."
}
}

3
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": "Превышен лимит частоты операций. Этот запрос постоянно отклонён."
}
}

3
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á."
}
}

3
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."
}
}

3
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."
}
}

3
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."
}
}

3
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."
}
}

3
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": "操作频率超出限制。此请求已被永久拒绝。"
}
}

22
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()
{

1
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]

Loading…
Cancel
Save