{"id":318344,"date":"2021-02-20T15:00:40","date_gmt":"2021-02-20T15:00:40","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=318344"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=318344","title":{"rendered":"\u041a\u0430\u043a \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 JSON \u043d\u0430 Snake Case \u0432 ASP.NET Core Web API"},"content":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 ASP.NET Web API &#8212; \u044d\u0442\u043e Camel Case. \u041d\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u0437\u0430\u0434\u0430\u0447\u0438, \u043a\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u043d\u0435\u0447\u0442\u043e \u0434\u0440\u0443\u0433\u043e\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0435 \u0443 \u0432\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c SPA, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043a\u0430\u043a \u0440\u0430\u0437 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 snake case. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 ASP.NET Core Web API.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/737\/527\/d3b\/737527d3b4ea831f55a90a060a1566a3.jpg\" alt=\"Camel case vs Snake case\" title=\"Camel case vs Snake case\" width=\"1486\" height=\"466\"><figcaption>Camel case vs Snake case<\/figcaption><\/figure>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432 \u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043f\u043e\u0441\u0442\u0430 &#8212; \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 Github \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u0433\u0434\u0435 \u044f \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0432 snake case. \u0412\u0441\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043a\u043e\u0434\u0430 \u0438 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430 ASP.NET Core \u0432\u0435\u0440\u0441\u0438\u0438 .net5.<\/p>\n<h3>\u041c\u0435\u043d\u044f\u0435\u043c \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/h3>\n<p>\u0412\u0441\u0435, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u044d\u0442\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c Naming Policy \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u0441\u0438 &#8212; \u044d\u0442\u043e Camel Case. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u043e\u043b\u0438\u0441\u0438 \u043d\u0430 Snake Case &#8212; \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u0430\u044f.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0443\u0442\u0438\u043b\u0438\u0442\u0430\u0440\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u043e\u043a \u043a snake case: <\/p>\n<pre><code class=\"cs\">using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Utils.Helpers;  namespace YourNamespace {     public static class JsonSerializationExtensions     {         private static readonly SnakeCaseNamingStrategy _snakeCaseNamingStrategy             = new SnakeCaseNamingStrategy();          private static readonly JsonSerializerSettings _snakeCaseSettings = new JsonSerializerSettings         {             ContractResolver = new DefaultContractResolver             {                 NamingStrategy = _snakeCaseNamingStrategy             }         };          public static string ToSnakeCase(this T instance)         {             if (instance == null)               {                    throw new ArgumentNullException(paramName: nameof(instance));                }              return JsonConvert.SerializeObject(instance, _snakeCaseSettings);         }          public static string ToSnakeCase(this string @string)         {             if (@string == null)               {                    throw new ArgumentNullException(paramName: nameof(@string));                }              return _snakeCaseNamingStrategy.GetPropertyName(@string, false);         }     } } <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0430\u0440\u0443 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432: \u043f\u0435\u0440\u0432\u0430\u044f \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u043d\u0430\u043c \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u0445, \u0432\u0442\u043e\u0440\u0430\u044f &#8212; \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f. \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0442\u0443\u0442 \u043a\u043b\u0430\u0441\u0441 <code>SnakeCaseNamingStrategy<\/code>&nbsp;\u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u043e\u043a. \u042d\u0442\u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u043d\u0430\u043c \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430\u0448\u0435\u0433\u043e Naming Policy:&nbsp;<\/p>\n<pre><code class=\"cs\">using System.Text.Json; using Utils.Serialization;  namespace YourNamespace {     public class SnakeCaseNamingPolicy : JsonNamingPolicy     {         public override string ConvertName(string name) =&gt; name.ToSnakeCase();     } } <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u043a\u0430\u043a \u0440\u0430\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434-\u044d\u043a\u0441\u0442\u0435\u043d\u0448\u043d  <code>ToSnakeCase()<\/code>  \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438. \u0418\u043d\u0441\u0442\u0430\u043d\u0441 \u043a\u043b\u0430\u0441\u0441\u0430 <code>SnakeCaseNamingPolicy<\/code>&nbsp;\u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 <code>Startup.cs<\/code> \u0432 \u043c\u0435\u0442\u043e\u0434\u0435&nbsp;<code>ConfigureServices<\/code>:<\/p>\n<pre><code class=\"cs\">public class Startup {   public void ConfigureServices(IServiceCollection services)   {     \/\/ ...     services         .AddMvc()         .AddJsonOptions(x =&gt;         {             x.JsonSerializerOptions.PropertyNamingPolicy = new SnakeCaseNamingPolicy();         });     \/\/ ...   } } <\/code><\/pre>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 Web API, \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>.AddMvc()<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>.AddControllers()<\/code>, \u0442\u0430\u043a \u043a\u0430\u043a \u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043d\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0420\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u0448 Web API \u0431\u0443\u0434\u0435\u0442 \u0438 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 MVC.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0438 \u043e\u0442\u0434\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 JSON \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Snake Case:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/0e4\/b56\/c09\/0e4b56c0913d3400fa1be3e684224eb4.png\" alt=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u0432 Snake Case \u0444\u043e\u0440\u043c\u0430\u0442\u0435\" title=\"\u0414\u0430\u043d\u043d\u044b\u0435 \u0432 Snake Case \u0444\u043e\u0440\u043c\u0430\u0442\u0435\" width=\"1442\" height=\"706\"><figcaption>\u0414\u0430\u043d\u043d\u044b\u0435 \u0432 Snake Case \u0444\u043e\u0440\u043c\u0430\u0442\u0435<\/figcaption><\/figure>\n<p>\u041d\u043e \u043a\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043c\u044b \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043c, \u0447\u0442\u043e\u2026<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/4a8\/659\/50a\/4a865950a06625e04f65e028c7659b12.png\" alt=\"\u0424\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0434\u0430\u0447\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u0432 Camel Case\" title=\"\u0424\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0434\u0430\u0447\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u0432 Camel Case\" width=\"1626\" height=\"1124\"><figcaption>\u0424\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0434\u0430\u0447\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u0432 Camel Case<\/figcaption><\/figure>\n<p>\u0421\u043a\u0440\u0438\u043d \u0432\u044b\u0448\u0435 &#8212; \u044d\u0442\u043e \u0442\u043e, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438. \u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u043e\u043d\u0430 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Camel Case, \u0434\u0430\u0436\u0435 \u0441 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043d\u0430\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438. \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u043f\u043e\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430 FirstName \u0438 LastName \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0443\u0436\u0435 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Pascal Case, \u0430 \u043c\u044b \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0438 \u043e\u0442\u0434\u0430\u0435\u043c \u0438\u0445 \u0432 Snake Case. \u041d\u0430\u043c \u0442\u0430\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442, \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c.<\/p>\n<h3>\u041c\u0435\u043d\u044f\u0435\u043c \u0444\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0434\u0430\u0447\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438<\/h3>\n<p>\u0427\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e &#171;\u0444\u0430\u0431\u0440\u0438\u043a\u0443 \u043e\u0442\u0432\u0435\u0442\u043e\u0432&#187; \u0432 ASP \u043d\u0430 \u0441\u0432\u043e\u044e \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043e\u0448\u0438\u0431\u043e\u043a:<\/p>\n<pre><code class=\"cs\">using System; using System.Collections.Generic; using System.Net; using Microsoft.AspNetCore.Mvc;  namespace YourNamespace {     public class ValidationProblemDetails : ProblemDetails     {         \/\/ 400 status ccode is usually used for input validation errors         public const int ValidationStatusCode = (int)HttpStatusCode.BadRequest;          public ValidationProblemDetails(ICollection validationErrors)         {             ValidationErrors = validationErrors;             Status = ValidationStatusCode;             Title = \"Request Validation Error\";         }          public ICollection ValidationErrors { get; }          public string RequestId =&gt; Guid.NewGuid().ToString();     } } <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043e\u0448\u0438\u0431\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d \u0432 JSON. \u041a\u043b\u0430\u0441\u0441 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442\u0441\u044f \u043e\u0442 <code>ProblemDetails<\/code>&nbsp;\u0438\u0437 \u043d\u0435\u0439\u043c\u0441\u043f\u0435\u0439\u0441\u0430 <code>Microsoft.AspNetCore.Mvc<\/code>. \u041f\u043e\u043b\u0435 RequestId \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0439\u0442\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043b\u043e\u0433\u0430\u0445 \u043f\u0440\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435 \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0448 UI \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0437\u0430\u043c\u0435\u043d\u044b \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e <code>InvalidModelStateResponseFactory<\/code>:<\/p>\n<pre><code class=\"cs\">using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Utils.Serialization;  namespace YourNamespace {     public class ValidationProblemDetailsResult : IActionResult     {         public async Task ExecuteResultAsync(ActionContext context)         {             var modelStateEntries = context.ModelState                 .Where(e =&gt; e.Value.Errors.Count &gt; 0)                 .ToArray();              var errors = new List();              if (modelStateEntries.Any())             {                 foreach (var (key, value) in modelStateEntries)                 {                     errors.AddRange(value.Errors                         .Select(modelStateError =&gt; new ValidationError(                             name: key.ToSnakeCase(),                             description: modelStateError.ErrorMessage)));                 }             }              await new JsonErrorResponse(                 context: context.HttpContext,                 error: new ValidationProblemDetails(errors),                 statusCode: ValidationProblemDetails.ValidationStatusCode).WriteAsync();         }     } } <\/code><\/pre>\n<p>\u041d\u0430\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u043a \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0437\u0430\u043c\u0435\u043d\u0443 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043e\u043a \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>Startup.cs<\/code>:<\/p>\n<pre><code class=\"cs\">public class Startup {    \/\/ ...   public void ConfigureServices(IServiceCollection services)   {     \/\/ ...     services         .Configure(x =&gt;         {             x.InvalidModelStateResponseFactory = ctx =&gt; new ValidationProblemDetailsResult();         });     \/\/ ...   } } <\/code><\/pre>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448\u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u0432 Snake Case \u0442\u043e\u0436\u0435:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/579\/881\/d3f\/579881d3fd052520593c2f90f4d50714.png\" alt=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Snake Case\" title=\"\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Snake Case\" width=\"1626\" height=\"1124\"><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Snake Case<\/figcaption><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u0434\u0430\u0435\u0442 \u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 JSON \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Snake Case, \u043d\u043e \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0442\u043e\u0436\u0435 \u0432 \u0442\u043e\u043c \u0432\u0438\u0434\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e. \u0417\u0434\u0435\u0441\u044c \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u044c <a href=\"https:\/\/github.com\/maximgorbatyuk\/snake-case-net-demo\" rel=\"noopener noreferrer nofollow\">Github \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a>, \u0433\u0434\u0435 \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c \u0448\u0430\u0433\u0430\u043c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e Snake Case, \u043d\u043e \u0438 \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u0430\u043c \u043f\u043e \u0434\u0443\u0448\u0435.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/543370\/\"> https:\/\/habr.com\/ru\/post\/543370\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text_v2\" id=\"post-content-body\">\n<p>\u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u0441\u043f\u043e\u0441\u043e\u0431 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u0432 ASP.NET Web API &#8212; \u044d\u0442\u043e Camel Case. \u041d\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u0432\u043e\u0437\u043d\u0438\u043a\u0430\u044e\u0442 \u0437\u0430\u0434\u0430\u0447\u0438, \u043a\u043e\u0433\u0434\u0430 \u043d\u0443\u0436\u043d\u043e \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442 \u0434\u0430\u043d\u043d\u044b\u0445 \u043d\u0430 \u043d\u0435\u0447\u0442\u043e \u0434\u0440\u0443\u0433\u043e\u0435. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440, \u043d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0435 \u0443 \u0432\u0430\u0441 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c SPA, \u043a\u043e\u0442\u043e\u0440\u043e\u0435 \u043a\u0430\u043a \u0440\u0430\u0437 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u0441 \u0434\u0430\u043d\u043d\u044b\u043c\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 snake case. \u0412 \u044d\u0442\u043e\u0439 \u0441\u0442\u0430\u0442\u044c\u0435 \u044f \u043f\u043e\u043a\u0430\u0436\u0443, \u043a\u0430\u043a \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0432 ASP.NET Core Web API.<\/p>\n<figure class=\"full-width\"><figcaption>Camel case vs Snake case<\/figcaption><\/figure>\n<p>\u0412 \u0441\u0442\u0430\u0442\u044c\u0435 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u044b \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043a\u043e\u0434\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0431\u0443\u0434\u0435\u0442 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0442\u0438 \u0432 \u0441\u0432\u043e\u0439 \u043f\u0440\u043e\u0435\u043a\u0442. \u0412 \u043a\u043e\u043d\u0446\u0435 \u043f\u043e\u0441\u0442\u0430 &#8212; \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 Github \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439, \u0433\u0434\u0435 \u044f \u0443\u0436\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0438\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044e \u0432 snake case. \u0412\u0441\u0435 \u043f\u0440\u0438\u043c\u0435\u0440\u044b \u043a\u043e\u0434\u0430 \u0438 \u043f\u0440\u043e\u0435\u043a\u0442 \u0432 \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u043d\u0430 ASP.NET Core \u0432\u0435\u0440\u0441\u0438\u0438 .net5.<\/p>\n<h3>\u041c\u0435\u043d\u044f\u0435\u043c \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432 \u0438 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u0441\u0435\u0440\u0432\u0435\u0440\u0430<\/h3>\n<p>\u0412\u0441\u0435, \u0447\u0442\u043e \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0434\u043b\u044f \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438, \u044d\u0442\u043e \u0443\u0441\u0442\u0430\u043d\u043e\u0432\u0438\u0442\u044c Naming Policy \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u0421\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u044b\u0439 \u043f\u043e\u043b\u0438\u0441\u0438 &#8212; \u044d\u0442\u043e Camel Case. \u0423\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430 \u043f\u043e\u043b\u0438\u0441\u0438 \u043d\u0430 Snake Case &#8212; \u0437\u0430\u0434\u0430\u0447\u0430 \u043d\u0435\u0441\u043b\u043e\u0436\u043d\u0430\u044f.<\/p>\n<p>\u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0443\u0442\u0438\u043b\u0438\u0442\u0430\u0440\u043d\u044b\u0435 \u043c\u0435\u0442\u043e\u0434\u044b \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u043e\u043a \u043a snake case: <\/p>\n<pre><code class=\"cs\">using Newtonsoft.Json; using Newtonsoft.Json.Serialization; using Utils.Helpers;  namespace YourNamespace {     public static class JsonSerializationExtensions     {         private static readonly SnakeCaseNamingStrategy _snakeCaseNamingStrategy             = new SnakeCaseNamingStrategy();          private static readonly JsonSerializerSettings _snakeCaseSettings = new JsonSerializerSettings         {             ContractResolver = new DefaultContractResolver             {                 NamingStrategy = _snakeCaseNamingStrategy             }         };          public static string ToSnakeCase(this T instance)         {             if (instance == null)               {                    throw new ArgumentNullException(paramName: nameof(instance));                }              return JsonConvert.SerializeObject(instance, _snakeCaseSettings);         }          public static string ToSnakeCase(this string @string)         {             if (@string == null)               {                    throw new ArgumentNullException(paramName: nameof(@string));                }              return _snakeCaseNamingStrategy.GetPropertyName(@string, false);         }     } } <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u0435\u043c \u043f\u0430\u0440\u0443 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0445 \u043c\u0435\u0442\u043e\u0434\u043e\u0432: \u043f\u0435\u0440\u0432\u0430\u044f \u043f\u0435\u0440\u0435\u0433\u0440\u0443\u0437\u043a\u0430 \u043c\u0435\u0442\u043e\u0434\u0430 \u043d\u0430\u043c \u043f\u0440\u0438\u0433\u043e\u0434\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u0438\u044f \u043d\u0430 \u043e\u0431\u044a\u0435\u043a\u0442\u0430\u0445, \u0432\u0442\u043e\u0440\u0430\u044f &#8212; \u0434\u043b\u044f \u0441\u0442\u0440\u043e\u043a\u043e\u0432\u043e\u0433\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f. \u041c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u0442\u0443\u0442 \u043a\u043b\u0430\u0441\u0441 <code>SnakeCaseNamingStrategy<\/code>&nbsp;\u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u0441\u0442\u0440\u043e\u043a. \u042d\u0442\u0438 \u043c\u0435\u0442\u043e\u0434\u044b \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u044f\u0442\u0441\u044f \u043d\u0430\u043c \u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u043d\u0430\u0448\u0435\u0433\u043e Naming Policy:&nbsp;<\/p>\n<pre><code class=\"cs\">using System.Text.Json; using Utils.Serialization;  namespace YourNamespace {     public class SnakeCaseNamingPolicy : JsonNamingPolicy     {         public override string ConvertName(string name) =&gt; name.ToSnakeCase();     } } <\/code><\/pre>\n<p>\u0417\u0434\u0435\u0441\u044c \u043c\u044b \u043a\u0430\u043a \u0440\u0430\u0437 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434-\u044d\u043a\u0441\u0442\u0435\u043d\u0448\u043d  <code>ToSnakeCase()<\/code>  \u0434\u043b\u044f \u0442\u0440\u0430\u043d\u0441\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438. \u0418\u043d\u0441\u0442\u0430\u043d\u0441 \u043a\u043b\u0430\u0441\u0441\u0430 <code>SnakeCaseNamingPolicy<\/code>&nbsp;\u043c\u044b \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0432 <code>Startup.cs<\/code> \u0432 \u043c\u0435\u0442\u043e\u0434\u0435&nbsp;<code>ConfigureServices<\/code>:<\/p>\n<pre><code class=\"cs\">public class Startup {   public void ConfigureServices(IServiceCollection services)   {     \/\/ ...     services         .AddMvc()         .AddJsonOptions(x =&gt;         {             x.JsonSerializerOptions.PropertyNamingPolicy = new SnakeCaseNamingPolicy();         });     \/\/ ...   } } <\/code><\/pre>\n<p>\u041d\u0435\u0441\u043c\u043e\u0442\u0440\u044f \u043d\u0430 \u0442\u043e, \u0447\u0442\u043e \u0443 \u043d\u0430\u0441 Web API, \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u0442\u043e\u0434 <code>.AddMvc()<\/code> \u0432\u043c\u0435\u0441\u0442\u043e <code>.AddControllers()<\/code>, \u0442\u0430\u043a \u043a\u0430\u043a \u0443 \u043f\u043e\u0441\u043b\u0435\u0434\u043d\u0435\u0433\u043e \u043d\u0435\u0442 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0438 \u043f\u0435\u0440\u0435\u043e\u043f\u0440\u0435\u0434\u0435\u043b\u044f\u0442\u044c \u0441\u043f\u043e\u0441\u043e\u0431 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u0420\u0430\u0431\u043e\u0442\u0430\u0442\u044c \u043d\u0430\u0448 Web API \u0431\u0443\u0434\u0435\u0442 \u0438 \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 MVC.<\/p>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f \u044d\u0442\u043e\u0439 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0438 \u043e\u0442\u0434\u0430\u0435\u0442 \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 JSON \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Snake Case:<\/p>\n<figure class=\"full-width\"><figcaption>\u0414\u0430\u043d\u043d\u044b\u0435 \u0432 Snake Case \u0444\u043e\u0440\u043c\u0430\u0442\u0435<\/figcaption><\/figure>\n<p>\u041d\u043e \u043a\u043e\u0433\u0434\u0430 \u0443 \u043d\u0430\u0441 \u0432\u043e\u0437\u043d\u0438\u043a\u043d\u0435\u0442 \u043e\u0448\u0438\u0431\u043a\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u0432\u0445\u043e\u0434\u044f\u0449\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445, \u043c\u044b \u043e\u0431\u043d\u0430\u0440\u0443\u0436\u0438\u043c, \u0447\u0442\u043e\u2026<\/p>\n<figure class=\"full-width\"><figcaption>\u0424\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0434\u0430\u0447\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u0432 Camel Case<\/figcaption><\/figure>\n<p>\u0421\u043a\u0440\u0438\u043d \u0432\u044b\u0448\u0435 &#8212; \u044d\u0442\u043e \u0442\u043e, \u043a\u0430\u043a \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d\u0430 \u043e\u0448\u0438\u0431\u043a\u0430 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438. \u041a\u0430\u043a \u043c\u044b \u0432\u0438\u0434\u0438\u043c, \u043e\u043d\u0430 \u0434\u043e \u0441\u0438\u0445 \u043f\u043e\u0440 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Camel Case, \u0434\u0430\u0436\u0435 \u0441 \u043f\u0440\u0438\u043c\u0435\u043d\u0435\u043d\u043d\u044b\u043c\u0438 \u043d\u0430\u043c\u0438 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430\u043c\u0438. \u0411\u043e\u043b\u0435\u0435 \u0442\u043e\u0433\u043e, \u043f\u043e\u043b\u044f \u043a\u043b\u0430\u0441\u0441\u0430 FirstName \u0438 LastName \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u044b \u0443\u0436\u0435 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Pascal Case, \u0430 \u043c\u044b \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u043c \u0438 \u043e\u0442\u0434\u0430\u0435\u043c \u0438\u0445 \u0432 Snake Case. \u041d\u0430\u043c \u0442\u0430\u043a\u043e\u0435 \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043d\u0435 \u043f\u043e\u0434\u0445\u043e\u0434\u0438\u0442, \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0442\u044c.<\/p>\n<h3>\u041c\u0435\u043d\u044f\u0435\u043c \u0444\u043e\u0440\u043c\u0430\u0442 \u0432\u044b\u0434\u0430\u0447\u0438 \u043e\u0448\u0438\u0431\u043e\u043a \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u0438<\/h3>\n<p>\u0427\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c, \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0437\u0430\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u0443\u044e &#171;\u0444\u0430\u0431\u0440\u0438\u043a\u0443 \u043e\u0442\u0432\u0435\u0442\u043e\u0432&#187; \u0432 ASP \u043d\u0430 \u0441\u0432\u043e\u044e \u0441\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0443\u044e. \u0421\u043d\u0430\u0447\u0430\u043b\u0430 \u0441\u043e\u0437\u0434\u0430\u0434\u0438\u043c \u043a\u043b\u0430\u0441\u0441, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u0431\u0443\u0434\u0435\u0442 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u043d\u0430\u043c \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0443 \u043e\u0448\u0438\u0431\u043e\u043a:<\/p>\n<pre><code class=\"cs\">using System; using System.Collections.Generic; using System.Net; using Microsoft.AspNetCore.Mvc;  namespace YourNamespace {     public class ValidationProblemDetails : ProblemDetails     {         \/\/ 400 status ccode is usually used for input validation errors         public const int ValidationStatusCode = (int)HttpStatusCode.BadRequest;          public ValidationProblemDetails(ICollection validationErrors)         {             ValidationErrors = validationErrors;             Status = ValidationStatusCode;             Title = \"Request Validation Error\";         }          public ICollection ValidationErrors { get; }          public string RequestId =&gt; Guid.NewGuid().ToString();     } } <\/code><\/pre>\n<p>\u042d\u0442\u043e\u0442 \u043a\u043b\u0430\u0441\u0441 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u043e\u0448\u0438\u0431\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0438 \u0431\u0443\u0434\u0435\u0442 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0435\u043d \u0432 JSON. \u041a\u043b\u0430\u0441\u0441 \u043d\u0430\u0441\u043b\u0435\u0434\u0443\u0435\u0442\u0441\u044f \u043e\u0442 <code>ProblemDetails<\/code>&nbsp;\u0438\u0437 \u043d\u0435\u0439\u043c\u0441\u043f\u0435\u0439\u0441\u0430 <code>Microsoft.AspNetCore.Mvc<\/code>. \u041f\u043e\u043b\u0435 RequestId \u043d\u0430\u043c \u043f\u043e\u043c\u043e\u0436\u0435\u0442 \u043d\u0430\u0439\u0442\u0438 \u043a\u043e\u043d\u043a\u0440\u0435\u0442\u043d\u0443\u044e \u0437\u0430\u043f\u0438\u0441\u044c \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u043b\u043e\u0433\u0430\u0445 \u043f\u0440\u0438 \u043f\u0440\u043e\u0441\u043c\u043e\u0442\u0440\u0435 \u0447\u0435\u0440\u0435\u0437 \u043d\u0430\u0448 UI \u043c\u043e\u043d\u0438\u0442\u043e\u0440\u0438\u043d\u0433\u0430.<\/p>\n<p>\u0417\u0430\u0442\u0435\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0442\u044c \u043a\u043b\u0430\u0441\u0441 \u0434\u043b\u044f \u0437\u0430\u043c\u0435\u043d\u044b \u0441\u0442\u0430\u043d\u0434\u0430\u0440\u0442\u043d\u043e\u0433\u043e <code>InvalidModelStateResponseFactory<\/code>:<\/p>\n<pre><code class=\"cs\">using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc; using Utils.Serialization;  namespace YourNamespace {     public class ValidationProblemDetailsResult : IActionResult     {         public async Task ExecuteResultAsync(ActionContext context)         {             var modelStateEntries = context.ModelState                 .Where(e =&gt; e.Value.Errors.Count &gt; 0)                 .ToArray();              var errors = new List();              if (modelStateEntries.Any())             {                 foreach (var (key, value) in modelStateEntries)                 {                     errors.AddRange(value.Errors                         .Select(modelStateError =&gt; new ValidationError(                             name: key.ToSnakeCase(),                             description: modelStateError.ErrorMessage)));                 }             }              await new JsonErrorResponse(                 context: context.HttpContext,                 error: new ValidationProblemDetails(errors),                 statusCode: ValidationProblemDetails.ValidationStatusCode).WriteAsync();         }     } } <\/code><\/pre>\n<p>\u041d\u0430\u043f\u043e\u0441\u043b\u0435\u0434\u043e\u043a \u0434\u043e\u0431\u0430\u0432\u0438\u043c \u0437\u0430\u043c\u0435\u043d\u0443 \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c\u0430 \u0444\u043e\u0440\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f \u043e\u0448\u0438\u0431\u043e\u043a \u0432 \u043a\u043b\u0430\u0441\u0441\u0435 <code>Startup.cs<\/code>:<\/p>\n<pre><code class=\"cs\">public class Startup {    \/\/ ...   public void ConfigureServices(IServiceCollection services)   {     \/\/ ...     services         .Configure(x =&gt;         {             x.InvalidModelStateResponseFactory = ctx =&gt; new ValidationProblemDetailsResult();         });     \/\/ ...   } } <\/code><\/pre>\n<p>\u0418 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0448\u0438 \u043e\u0448\u0438\u0431\u043a\u0438 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0443\u044e\u0442\u0441\u044f \u0432 Snake Case \u0442\u043e\u0436\u0435:<\/p>\n<figure class=\"full-width\"><figcaption>\u0421\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0430 \u043e\u0448\u0438\u0431\u043a\u0438 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Snake Case<\/figcaption><\/figure>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0432\u0441\u0435\u0445 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439 \u043d\u0430\u0448\u0435 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u0442\u0435\u043f\u0435\u0440\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e \u043e\u0442\u0434\u0430\u0435\u0442 \u0438 \u043f\u0440\u0438\u043d\u0438\u043c\u0430\u0435\u0442 JSON \u0434\u0430\u043d\u043d\u044b\u0435 \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 Snake Case, \u043d\u043e \u0438 \u043f\u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442 \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u043e\u043d\u043d\u044b\u0435 \u043e\u0448\u0438\u0431\u043a\u0438 \u0442\u043e\u0436\u0435 \u0432 \u0442\u043e\u043c \u0432\u0438\u0434\u0435, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u043d\u0430\u043c \u043d\u0443\u0436\u043d\u043e. \u0417\u0434\u0435\u0441\u044c \u043f\u043e \u0441\u0441\u044b\u043b\u043a\u0435 \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043e\u0442\u043a\u0440\u044b\u0442\u044c <a href=\"https:\/\/github.com\/maximgorbatyuk\/snake-case-net-demo\" rel=\"noopener noreferrer nofollow\">Github \u0440\u0435\u043f\u043e\u0437\u0438\u0442\u043e\u0440\u0438\u0439<\/a>, \u0433\u0434\u0435 \u0435\u0441\u0442\u044c \u043f\u0440\u0438\u043c\u0435\u0440 \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043d\u043d\u043e\u0433\u043e \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f. \u041f\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043d\u044b\u043c \u0448\u0430\u0433\u0430\u043c \u0432\u044b \u043c\u043e\u0436\u0435\u0442\u0435 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e Snake Case, \u043d\u043e \u0438 \u043b\u044e\u0431\u043e\u0439 \u0434\u0440\u0443\u0433\u043e\u0439 \u0444\u043e\u0440\u043c\u0430\u0442 \u0441\u0435\u0440\u0438\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0434\u0430\u043d\u043d\u044b\u0445, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u0430\u043c \u043f\u043e \u0434\u0443\u0448\u0435.<\/p>\n<\/div>\n<p> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/post\/543370\/\"> https:\/\/habr.com\/ru\/post\/543370\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-318344","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/318344","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=318344"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/318344\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=318344"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=318344"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=318344"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}