{"id":318200,"date":"2021-02-18T03:00:59","date_gmt":"2021-02-18T03:00:59","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=318200"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=318200","title":{"rendered":"\u0414\u0435\u043b\u0430\u0435\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u00ab\u043a\u0430\u043a \u0432 \u044d\u043a\u0441\u0435\u043b\u0435\u00bb \u043d\u0430 ASP.NET Core"},"content":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p>\u00ab\u0421\u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u043d\u0430\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u00ab\u043a\u0430\u043a \u0432 \u044d\u043a\u0441\u0435\u043b\u0435\u00bb, \u2014 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 &quot;\u0441\u043b\u0435\u0433\u043a\u0430&quot; \u0434\u043b\u0438\u043d\u0435\u0435, \u0447\u0435\u043c \u0435\u0433\u043e \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u0430\u044f \u043f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430. \u0415\u0441\u043b\u0438 \u0432\u0434\u0440\u0443\u0433 \u0432\u044b \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u044d\u0442\u0438\u043c\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c\u0438, \u0442\u043e <a href=\"https:\/\/docs.google.com\/spreadsheets\/d\/1C-yNfFMJNGHec3NxIdZeGYYsKmz41nBs2NmcG169OkA\/edit?usp=sharing\" rel=\"nofollow noopener noreferrer\">\u0432\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440<\/a>. \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0444\u0438\u0448\u043a\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432 \u0441\u0442\u0440\u043e\u0447\u043a\u0435 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f\u043c \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0438 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u0438\u0437 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432 \u043a\u043e\u043b\u043e\u043d\u043a\u0430\u0445 <strong>\u0410<\/strong> \u0438 <strong>B<\/strong> \u2014 4000 \u0441\u0442\u0440\u043e\u043a \u0438 3999 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 (\u043f\u0435\u0440\u0432\u0443\u044e \u0441\u0442\u0440\u043e\u0447\u043a\u0443 \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0442 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a). \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0432\u0442\u0443\u044e\u0449\u0438\u0445 \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0445 \u0441\u043f\u0438\u0441\u043a\u0430\u0445 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e 3999 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439. \u0412 \u043a\u043e\u043b\u043e\u043d\u043a\u0435 <strong>C<\/strong> \u2014 220 \u0441\u0442\u0440\u043e\u043a \u0438 219 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0435\u043c \u0441\u043f\u0438\u0441\u043a\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/oi\/zx\/vl\/oizxvlqqwomnaojtyrr5g5si7ey.png\"><\/p>\n<p><a name=\"habracut\"><\/a>  <\/p>\n<h2 id=\"todropdownoption\">ToDropdownOption<\/h2>\n<p>  <\/p>\n<p>\u0412 .NET \u0438\u0441\u043f\u043e\u043a\u043e\u043d \u0432\u0435\u043a\u043e\u0432 \u0441\u0443\u0449\u0435\u0441\u0442\u0432\u0443\u0435\u0442 \u043f\u0440\u0435\u043a\u0440\u0430\u0441\u043d\u044b\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/api\/system.linq.iqueryable-1?view=net-5.0\" rel=\"nofollow noopener noreferrer\"><code>IQuerable&lt;T&gt;<\/code><\/a>, \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0438\u0439 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0440\u0430\u0437\u043d\u043e\u043e\u0431\u0440\u0430\u0437\u043d\u044b\u043c \u0438\u0441\u0442\u043e\u0447\u043d\u0438\u043a\u0430\u043c \u0434\u0430\u043d\u043d\u044b\u0445. \u0415\u0433\u043e \u0438 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c. \u041e\u043f\u0440\u0435\u0434\u0435\u043b\u0438\u043c \u043c\u0435\u0442\u043e\u0434-\u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f <code>ToDropdownOption<\/code> \u043f\u043e\u0432\u0435\u0440\u0445 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441\u0430.<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static IQueryable&lt;DropdownOption&lt;TValue&gt;&gt; ToDropdownOption&lt;TQueryable, TValue, TDropdownOption&gt;(    this IQueryable&lt;TQueryable&gt; q,    Expression&lt;Func&lt;TQueryable, string&gt;&gt; labelExpression,    Expression&lt;Func&lt;TQueryable, TValue&gt;&gt; valueExpression)    where TDropdownOption: DropdownOption&lt;TValue&gt; {    \/\/ \u0412\u044b\u0437\u044b\u0432\u0430\u0435\u043c \u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440 \u043f\u043e \u0443\u043c\u043e\u043b\u0447\u0430\u043d\u0438\u044e     \/\/ \u0412 Cache&lt;TValue, TDropdownOption&gt;.Constructor \u043a\u0435\u0448\u0438\u0440\u0443\u0435\u0442\u0441\u044f reflection    var newExpression = Expression.New(Cache&lt;TValue, TDropdownOption&gt;.Constructor);     \/\/ \u041f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043e\u0431 \u044d\u0442\u043e\u0439 \u043e\u0441\u043e\u0431\u043e\u0439 \u0443\u043b\u0438\u0447\u043d\u043e\u0439 \u043c\u0430\u0433\u0438\u0438 \u0437\u0434\u0435\u0441\u044c    \/\/ https:\/\/habr.com\/ru\/company\/jugru\/blog\/423891\/#predicate-builder    var e2Rebind = Rebind(valueExpression, labelExpression);    var e1ExpressionBind = Expression.Bind(        Cache&lt;TValue, TDropdownOption&gt;.LabelPropertyInfo, labelExpression.Body);    var e2ExpressionBind = Expression.Bind(        Cache&lt;TValue, TDropdownOption&gt;.ValuePropertyInfo, e2Rebind.Body);     \/\/ \u0418\u043d\u0438\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u0443\u0435\u043c \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f Label \u0438 Value    var result = Expression.MemberInit(        newExpression, e1ExpressionBind, e2ExpressionBind);    var lambda = Expression.Lambda&lt;Func&lt;TQueryable, DropdownOption&lt;TValue&gt;&gt;&gt;(        result, labelExpression.Parameters);     \/*    \u0412 \u0438\u0442\u043e\u0433\u0435 \u043f\u043e\u043b\u0443\u0447\u0438\u043c    return q.Select(x =&gt; new DropdownOption&lt;TValue&gt;    {      Label = labelExpression      Value = valueExpression    });    \u041d\u043e \u0442\u0430\u043a\u043e\u0439 \u043a\u043e\u0434 \u043d\u0435 \u0441\u043a\u043e\u043c\u043f\u043b\u0438\u0440\u0443\u0435\u0442\u0441\u044f,    \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0442\u044c \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e API Expression Trees    *\/    return q.Select(lambda); }<\/code><\/pre>\n<p>  <\/p>\n<blockquote><p>\u0415\u0441\u043b\u0438 \u043a\u043e\u0434 \u043c\u0435\u0442\u043e\u0434\u0430 \u043a\u0430\u0436\u0435\u0442\u0441\u044f \u043d\u0435\u043f\u043e\u043d\u044f\u0442\u043d\u044b\u043c, \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u0439\u0442\u0435 \u0440\u0430\u0441\u0448\u0438\u0444\u0440\u043e\u0432\u043a\u0443 \u0438\u043b\u0438 \u043f\u043e\u0441\u043c\u043e\u0442\u0440\u0438\u0442\u0435 \u0434\u043e\u043a\u043b\u0430\u0434 <a href=\"https:\/\/habr.com\/ru\/company\/jugru\/blog\/423891\/\">\u0414\u0435\u0440\u0435\u0432\u044c\u044f \u0432\u044b\u0440\u0430\u0436\u0435\u043d\u0438\u0439 \u0432 enterprise-\u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435<\/a>. \u0421\u0442\u0430\u043d\u0435\u0442 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u043f\u043e\u043d\u044f\u0442\u043d\u0435\u0435.<\/p><\/blockquote>\n<p>\u0421\u0430\u043c\u0438 \u043a\u043b\u0430\u0441\u0441\u044b <code>DropdownOption<\/code> \u0438 <code>DropdownOption&lt;T&gt;<\/code> \u0432\u044b\u043b\u0433\u044f\u0434\u044f\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public class DropdownOption {    \/\/ \u0417\u0430\u043f\u0440\u0435\u0449\u0430\u0435\u043c \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u043d\u043e \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0435\u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 DropdownOption    \/\/ \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u0441\u0431\u043e\u0440\u043a\u0438    internal DropdownOption() {}     internal DropdownOption(string label, object value)    {        Value = value ?? throw new ArgumentNullException(nameof(value));        Label = label ?? throw new ArgumentNullException(nameof(label));    }     \/\/ \u0414\u0435\u043b\u0430\u0435\u043c \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u0430 \u043d\u0435\u0438\u0437\u043c\u0435\u043d\u044f\u0435\u043c\u044b\u043c\u0438 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0435\u0430\u043c\u0438 \u0441\u0431\u043e\u0440\u043a\u0438    public string Label { get; internal set; }     public object Value { get; internal set; } }  public class DropdownOption&lt;T&gt;: DropdownOption {     internal DropdownOption() {}      \/\/ \u0422\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0435 \u043e\u043f\u0446\u0438\u0438 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u0441\u0431\u043e\u0440\u043a\u0438     public DropdownOption(string label, T value) : base(label, value)     {         _value = value;     }      private T _value;      \/\/ \u041f\u0435\u0440\u0435\u043a\u0440\u044b\u0432\u0430\u0435\u043c \u0431\u0430\u0437\u043e\u0432\u043e\u0435 \u0441\u0432\u043e\u0439\u0441\u0442\u0432\u043e \u0442\u0438\u043f\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u043c     public new virtual T Value     {         get =&gt; _value;        internal set        {            _value = value;            base.Value = value;        }     } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0440\u044e\u043a \u0441 internal-\u043a\u043e\u043d\u0441\u0442\u0440\u0443\u043a\u0442\u043e\u0440\u043e\u043c \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u043f\u0440\u0438\u0432\u0435\u0441\u0442\u0438 \u043b\u044e\u0431\u043e\u0439 <code>DropdownOption&lt;T&gt;<\/code> \u043a <code>DropdownOption<\/code> \u0431\u0435\u0437 generic-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430, \u043e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u043e, \u043d\u0435 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u044f \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u044d\u043a\u0437\u0435\u043c\u043f\u043b\u044f\u0440\u044b \u043a\u043b\u0430\u0441\u0441\u0430 \u0431\u0435\u0437 generic-\u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u0430 \u0437\u0430 \u043f\u0440\u0435\u0434\u0435\u043b\u0430\u043c\u0438 \u0441\u0431\u043e\u0440\u043a\u0438.<\/p>\n<p>  <\/p>\n<blockquote><p>\u0411\u0443\u0434\u0435\u0442 \u0437\u0434\u043e\u0440\u043e\u0432\u043e \u043a\u043e\u0433\u0434\u0430\/\u0435\u0441\u043b\u0438 <a href=\"https:\/\/docs.microsoft.com\/en-us\/dotnet\/csharp\/language-reference\/proposals\/csharp-9.0\/covariant-returns\" rel=\"nofollow noopener noreferrer\">\u043a\u043e\u0432\u0430\u0440\u0438\u0430\u043d\u0442\u043d\u044b\u0435 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u043c\u044b\u0435 \u0442\u0438\u043f\u044b<\/a> \u0431\u0443\u0434\u0443\u0442 \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u044b. \u0421 \u043d\u0438\u043c\u0438 \u043c\u043e\u0436\u043d\u043e \u0438\u0437\u0431\u0430\u0432\u0438\u0442\u044c\u0441\u044f \u043e\u0442 \u043f\u0435\u0440\u0435\u043a\u0440\u044b\u0442\u0438\u044f \u0447\u0435\u0440\u0435\u0437 <code>new<\/code>. \u041f\u043e\u043a\u0430 \u0438\u043c\u0435\u0435\u043c, \u0447\u0442\u043e \u0438\u043c\u0435\u0435\u043c.<\/p><\/blockquote>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0443 \u043d\u0430\u0441 \u0435\u0441\u0442\u044c \u0443\u0434\u043e\u0431\u043d\u043e\u0435 API \u0434\u043b\u044f \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445. \u041f\u0440\u0438\u043a\u043b\u0430\u0434\u043d\u043e\u0439 \u043a\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u0432\u044b\u0433\u043b\u044f\u0434\u0435\u0442\u044c \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c.<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public IEnumerable GetDropdowns(IQueryable&lt;SomeData&gt; q) =&gt;     q.ToDropdownOption(x =&gt; x.String, x =&gt; x.Id)<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"idropdownprovider\">IDropdownProvider<\/h2>\n<p>  <\/p>\n<p>\u0413\u0434\u0435 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u0440\u0430\u0441\u0448\u0438\u0440\u0435\u043d\u0438\u044f? \u0414\u043e\u043f\u0443\u0441\u0442\u0438\u043c, \u043c\u044b \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u043c \u0441 \u0442\u0430\u043a\u0438\u043c \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public IActionResult GetData(     [FromServices] IQueryable&lt;SomeData&gt; q     [FromQuery] SomeDataFilter filter) =&gt;     Ok(q     .Filter(filter)     .ToList());<\/code><\/pre>\n<p>  <\/p>\n<p>\u041a\u043b\u0430\u0441\u0441\u044b <code>SomeData<\/code> \u0438 <code>SomeDataFilter<\/code> \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u044b \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public class SomeDataFilter {    public int[] Number { get; set; }     public DateTime[]? Date { get; set; }     public string[]? String { get; set; } }  public class SomeData {    public int Number { get; set; }     public DateTime Date { get; set; }     public string String { get; set; } } <\/code><\/pre>\n<p>  <\/p>\n<p>\u0410 \u043c\u0435\u0442\u043e\u0434 <code>Filter<\/code> \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static IQueryable&lt;SomeData&gt; Filter(     this IQueryable&lt;SomeData&gt; q,     SomeDataFilter filter) {     if (filter.Number != null)     {         q = q.Where(x =&gt; filter.Number.Contains(x.Number));     }      if (filter.Date != null)     {         q = q.Where(x =&gt; filter.Date.Contains(x.Date));     }      if (filter.String != null)     {         q = q.Where(x =&gt; filter.String.Contains(x.String));     }      return q; }<\/code><\/pre>\n<p>  <\/p>\n<blockquote><p>\u0414\u043b\u044f \u0440\u0435\u0430\u043b\u044c\u043d\u044b\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u043e\u0432, \u044d\u0442\u043e\u0442 \u043c\u0435\u0442\u043e\u0434 \u043c\u043e\u0436\u043d\u043e \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043e\u0431\u043e\u0431\u0449\u0435\u043d\u043d\u044b\u043c \u041a\u0430\u043a \u0438\u043c\u0435\u043d\u043d\u043e \u043e\u043f\u0438\u0441\u0430\u043d\u043e <a href=\"https:\/\/habr.com\/ru\/company\/jugru\/blog\/423891\/#filters\">\u0437\u0434\u0435\u0441\u044c<\/a><\/p><\/blockquote>\n<p><code>SomeDataFilter<\/code> \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043c\u0430\u0441\u0441\u0438\u0432\u044b \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0438\u0437 \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0445 \u0441\u043f\u0438\u0441\u043a\u043e\u0432, \u0437\u0430\u043f\u043e\u043b\u043d\u0435\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u043c, \u0430 \u0437\u043d\u0430\u0447\u0438\u0442 \u043c\u044b \u0433\u0434\u0435-\u0442\u043e \u0432 \u0434\u0440\u0443\u0433\u043e\u043c \u043c\u0435\u0441\u0442\u0435 \u043f\u0435\u0440\u0435\u0434\u0430\u043b\u0438 \u0438\u0445 \u043d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434, \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f \u043c\u0435\u0442\u043e\u0434 \u0432\u0440\u043e\u0434\u0435 \u044d\u0442\u043e\u0433\u043e:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public IActionResult GetSomeDataFilterDropdownOptions(    [FromServices] IQueryable&lt;SomeData&gt; q) {    var number = q        .ToDropdownOption(x =&gt; x.Number.ToString(), x =&gt; x.Number)        .Distinct()        .ToList();     var date = q        .ToDropdownOption(x =&gt; x.Date.ToString(&quot;d&quot;), x =&gt; x.Date)        .Distinct()        .ToList();     var @string = q        .ToDropdownOption(x =&gt; x.String, x =&gt; x.String)        .Distinct()        .ToList();     return Ok(new    {        number,        date,        @string    }); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0422\u0430\u043a\u043e\u0439 \u043a\u043e\u0434 \u043c\u043e\u0436\u0435\u0442 \u043f\u043e\u043d\u0430\u0434\u043e\u0431\u0438\u0442\u0441\u044f \u0434\u043b\u044f \u043b\u044e\u0431\u043e\u0433\u043e \u0442\u0438\u043f\u0430 \u0444\u0438\u043b\u044c\u0442\u0440\u043e\u0432, \u0430 \u043d\u0435 \u0442\u043e\u043b\u044c\u043a\u043e SomeDataFilters, \u043f\u043e\u044d\u0442\u043e\u043c\u0443 \u0432\u0432\u0435\u0434\u0435\u043c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441.<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public interface IDropdownProvider&lt;T&gt; {   Dictionary&lt;string, IEnumerable&lt;DropdownOption&gt;&gt; GetDropdownOptions(); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0418 \u043f\u0435\u0440\u0435\u043d\u0435\u0441\u0435\u043c \u043a\u043e\u0434 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u044f \u043e\u043f\u0446\u0438\u0439 \u0432 \u043a\u043b\u0430\u0441\u0441, \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u044e\u0449\u0438\u0439 \u0438\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public class SomeDataFiltersDropdownProvider: IDropdownProvider&lt;SomeDataFilter&gt; {    private readonly IQueryable&lt;SomeData&gt; _q;     public SomeDataFiltersDropdownProvider(IQueryable&lt;SomeData&gt; q)    {        _q = q;    }     public Dictionary&lt;string, IEnumerable&lt;DropdownOption&gt;&gt; GetDropdownOptions()    {        return new Dictionary&lt;string, IEnumerable&lt;DropdownOption&gt;&gt;()        {            {                &quot;name&quot;, _q                .ToDropdownOption(x =&gt; x.Number.ToString(), x =&gt; x.Number)                .Distinct()                .ToList();            },            {                &quot;date&quot;, _q                .ToDropdownOption(x =&gt; x.Date.ToString(&quot;d&quot;), x =&gt; x.Date)                .Distinct()                .ToList();                       },            {                &quot;string&quot;, _q                .ToDropdownOption(x =&gt; x.String, x =&gt; x.String)                .Distinct()                .ToList();            }        };    } }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0432\u043e\u0442 \u0442\u0430\u043a\u043e\u0439 \u043e\u0431\u043e\u0431\u0449\u0435\u043d\u043d\u044b\u0439 \u043c\u0435\u0442\u043e\u0434 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044e \u0442\u0438\u043f\u0430 \u0438\u0441\u043a\u0430\u0442\u044c \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0443\u044e\u0449\u0438\u0439 <code>DropdownProvider<\/code> \u0438 \u0432\u044b\u0437\u044b\u0432\u0430\u0442\u044c \u0435\u0433\u043e \u043c\u0435\u0442\u043e\u0434.<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">[HttpGet] [Route(&quot;Dropdowns\/{type}&quot;)] public async IActionResult Dropdowns(      string type,       [FromServices] IServiceProvider serviceProvider      [TypeResolver] ITypeResolver typeResolver) {    var t = typeResolver(type);    if (t == null)    {        return NotFound();    }     \/\/ \u041f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u043a dynamic, \u0447\u0442\u043e\u0431\u044b \u043d\u0435 \u043f\u0430\u0440\u0438\u0442\u044c\u0441\u044f \u0441 \u043f\u0440\u0438\u0432\u0435\u0434\u0435\u043d\u0438\u0435\u043c \u0442\u0438\u043f\u043e\u0432.    \/\/ T \u043d\u0435\u0438\u0437\u0432\u0435\u0441\u0442\u0435\u043d, \u043f\u043e\u0442\u043e\u043c\u0443 \u0447\u0442\u043e \u043c\u0435\u0442\u043e\u0434 \u043a\u043e\u043d\u0442\u0440\u043e\u043b\u043b\u0435\u0440\u0430 \u043d\u0435 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u0434\u0436\u0435\u043d\u0435\u0440\u0438\u043a\u0430.    dynamic service = serviceProvider        .GetService(typeof(IDropdownProvider&lt;&gt;)        .MakeGenericType(t));     if (service == null)    {        return NotFound();    }     var res = service.GetDropdownOptions();    return Ok(res); }<\/code><\/pre>\n<p>  <\/p>\n<h2 id=\"odnovremennye-zaprosy\">\u041e\u0434\u043d\u043e\u0432\u0440\u0435\u043c\u0435\u043d\u043d\u044b\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b<\/h2>\n<p>  <\/p>\n<p>\u041d\u0430 \u044d\u0442\u043e\u043c \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0438 \u0437\u0430\u043a\u043e\u043d\u0447\u0438\u0442\u044c, \u043d\u043e, \u043a\u0430\u043a \u0433\u043e\u0432\u043e\u0440\u0438\u0442\u0441\u044f, \u0435\u0441\u0442\u044c \u043d\u044e\u0430\u043d\u0441. \u0412 \u043f\u0440\u0438\u043c\u0435\u0440\u0435 \u0441\u0432\u0435\u0440\u0445\u0443 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0411\u0414 \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e, \u0445\u043e\u0442\u044f \u043e\u043d\u0438 \u043d\u0435 \u0437\u0430\u0432\u0438\u0441\u044f\u0442 \u0434\u0440\u0443\u0433 \u043e\u0442 \u0434\u0440\u0443\u0433\u0430. \u0427\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0435 \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u0441 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c\u0438, \u0442\u0435\u043c \u0431\u043e\u043b\u044c\u0448\u0438\u0439 \u0432\u044b\u0438\u0433\u0440\u044b\u0448 \u043c\u043e\u0436\u043d\u043e \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u0437\u0430 \u0441\u0447\u0435\u0442 \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e\u0433\u043e \u0432\u044b\u043f\u043e\u043b\u043d\u0435\u043d\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432. \u0420\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>IQueryable<\/code> \u0447\u0430\u0449\u0435 \u0432\u0441\u0435\u0433\u043e \u0431\u0430\u0437\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u043d\u0430 \u0442\u043e\u0439 \u0438\u043b\u0438 \u0438\u043d\u043e\u0439 ORM, \u0430 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 <code>Unit Of Work<\/code> ORM \u0447\u0430\u0441\u0442\u043e \u043d\u0435 \u043f\u043e\u0442\u043e\u043a\u043e\u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b (\u0438\u043d\u0430\u0447\u0435 \u0441\u043b\u0438\u0448\u043a\u043e\u043c \u0441\u043b\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c change tracking). \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u0431\u0443\u0434\u0435\u043c \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u043e\u0442\u0434\u0435\u043b\u044c\u043d\u044b\u0435 \u043e\u0431\u043b\u0430\u0441\u0442\u0438 \u0432\u0438\u0434\u0438\u043c\u043e\u0441\u0442\u0438 (scope) <a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/fundamentals\/dependency-injection?view=aspnetcore-5.0#lifetime-and-registration-options\" rel=\"nofollow noopener noreferrer\"><code>ServiceProvider<\/code><\/a> \u0438 \u0430\u0441\u0438\u043d\u0445\u0440\u043e\u043d\u043d\u044b\u0435 \u0432\u0435\u0440\u0441\u0438\u0438 \u043c\u0435\u0442\u043e\u0434\u043e\u0432.<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public static async Task&lt;TResult&gt; InScopeAsync&lt;TService, TResult&gt;(     this IServiceProvider serviceProvider,     Func&lt;TService, IServiceProvider, Task&lt;TResult&gt;&gt; func) {     using var scope = serviceProvider.CreateScope();      return await func(         scope.ServiceProvider.GetService&lt;TService&gt;(),         scope.ServiceProvider); }<\/code><\/pre>\n<p>  <\/p>\n<p>\u0412 \u0438\u0442\u043e\u0433\u0435 \u043a\u043e\u0434 <code>DropdownProvider<\/code> \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u043f\u0438\u0441\u0430\u0442\u044c \u0432 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c \u0432\u0438\u0434\u0435:<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public async Task&lt;Dictionary&lt;string, IEnumerable&lt;DropdownOption&gt;&gt;&gt;    GetDropdownOptionsAsync() {     var dict = new Dictionary&lt;string, IEnumerable&lt;DropdownOption&gt;&gt;();     var name = sp.InScopeAsync&lt;IQueryable&lt;SomeData&gt;&gt;(q =&gt; q         .ToDropdownOption(x =&gt; x.Number.ToString(), x =&gt; x.Number)         .Distinct()         .ToListAsync());      var date = sp.InScopeAsync&lt;IQueryable&lt;SomeData&gt;&gt;(q =&gt; q         .ToDropdownOption(x =&gt; x.Date.ToString(&quot;d&quot;), x =&gt; x.Date)         .Distinct()         .ToListAsync());         var @string = sp.InScopeAsync&lt;IQueryable&lt;SomeData&gt;&gt;(q =&gt; q         .ToDropdownOption(x =&gt; x.String, x =&gt; x.String)         .Distinct()         .ToListAsync());      \/\/ \u0422\u0435\u043f\u0435\u0440\u044c \u0432\u0441\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0432\u044b\u043f\u043e\u043b\u043d\u044f\u044e\u0442\u0441\u044f \u043f\u0430\u0440\u0430\u043b\u043b\u0435\u043b\u044c\u043d\u043e     await Task.WhenAll(new []{name, date, @string}});     dict[&quot;name&quot;] = await name;     dict[&quot;date&quot;] = await date;     dict[&quot;string&quot;] = await @string;     return dict; }<\/code><\/pre>\n<p>  <\/p>\n<p>\u041e\u0441\u0442\u0430\u043b\u043e\u0441\u044c \u043f\u0440\u0438\u0431\u0440\u0430\u0442\u044c \u043a\u043e\u0434, \u0443\u0441\u0442\u0440\u0430\u043d\u0438\u0442\u044c \u0434\u0443\u0431\u043b\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0438 \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c \u0431\u043e\u043b\u0435\u0435 \u0443\u0434\u043e\u0431\u043d\u043e\u0435 API. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u0445\u043e\u0440\u043e\u0448\u043e \u043f\u043e\u0434\u043e\u0439\u0434\u0435\u0442 \u0448\u0430\u0431\u043b\u043e\u043d \u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f <a href=\"https:\/\/refactoring.guru\/ru\/design-patterns\/builder\" rel=\"nofollow noopener noreferrer\">\u0441\u0442\u0440\u043e\u0438\u0442\u0435\u043b\u044c<\/a>. \u042f \u043e\u043f\u0443\u0449\u0443 \u0434\u0435\u0442\u0430\u043b\u0438 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438. \u041f\u044b\u0442\u043b\u0438\u0432\u044b\u0439 \u0447\u0438\u0442\u0430\u0442\u0435\u043b\u044c \u043d\u0430\u0432\u0435\u0440\u043d\u044f\u043a\u0430 \u0441\u043c\u043e\u0436\u0435\u0442 \u0441\u043f\u0440\u043e\u0435\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0430\u043d\u0430\u043b\u043e\u0433\u0438\u0447\u043d\u044b\u0439 API \u0441\u0430\u043c\u043e\u0441\u0442\u043e\u044f\u0442\u0435\u043b\u044c\u043d\u043e.<\/p>\n<p>  <\/p>\n<pre><code class=\"cs\">public async Task&lt;Dictionary&lt;string, IEnumerable&lt;DropdownOption&gt;&gt;&gt;     GetDropdownOptionsAsync() {      return sp         .DropdownsFor&lt;SomeDataFilters&gt;          .With(x =&gt; x.Number)         .As&lt;SomeData, int&gt;(GetNumbers)          .With(x =&gt; x.Date)         .As&lt;SomeData, DateTime&gt;(GetDates)          .With(x =&gt; x.String)         .As&lt;SomeData, string&gt;(GetStrings) }<\/code><\/pre>\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\/542990\/\"> https:\/\/habr.com\/ru\/post\/542990\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"\n<div class=\"post__text post__text-html post__text_v1\" id=\"post-content-body\">\n<p>\u00ab\u0421\u0434\u0435\u043b\u0430\u0439\u0442\u0435 \u043d\u0430\u043c \u0444\u0438\u043b\u044c\u0442\u0440\u044b \u00ab\u043a\u0430\u043a \u0432 \u044d\u043a\u0441\u0435\u043b\u0435\u00bb, \u2014 \u0434\u043e\u0432\u043e\u043b\u044c\u043d\u043e \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u0439 \u0437\u0430\u043f\u0440\u043e\u0441 \u043d\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0443. \u041a \u0441\u043e\u0436\u0430\u043b\u0435\u043d\u0438\u044e, \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u044f \u0437\u0430\u043f\u0440\u043e\u0441\u0430 &quot;\u0441\u043b\u0435\u0433\u043a\u0430&quot; \u0434\u043b\u0438\u043d\u0435\u0435, \u0447\u0435\u043c \u0435\u0433\u043e \u043b\u0430\u043a\u043e\u043d\u0438\u0447\u043d\u0430\u044f \u043f\u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043a\u0430. \u0415\u0441\u043b\u0438 \u0432\u0434\u0440\u0443\u0433 \u0432\u044b \u043d\u0438\u043a\u043e\u0433\u0434\u0430 \u043d\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c \u044d\u0442\u0438\u043c\u0438 \u0444\u0438\u043b\u044c\u0442\u0440\u0430\u043c\u0438, \u0442\u043e <a href=\"https:\/\/docs.google.com\/spreadsheets\/d\/1C-yNfFMJNGHec3NxIdZeGYYsKmz41nBs2NmcG169OkA\/edit?usp=sharing\" rel=\"nofollow noopener noreferrer\">\u0432\u043e\u0442 \u043f\u0440\u0438\u043c\u0435\u0440<\/a>. \u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0444\u0438\u0448\u043a\u0430 \u0432 \u0442\u043e\u043c, \u0447\u0442\u043e \u0432 \u0441\u0442\u0440\u043e\u0447\u043a\u0435 \u0441 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f\u043c \u043a\u043e\u043b\u043e\u043d\u043e\u043a \u043f\u043e\u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0435 \u0441\u043f\u0438\u0441\u043a\u0438 \u0441\u043e \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u044f\u043c\u0438 \u0438\u0437 \u0432\u044b\u0431\u0440\u0430\u043d\u043d\u043e\u0433\u043e \u0434\u0438\u0430\u043f\u0430\u0437\u043e\u043d\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0435\u0440 \u0432 \u043a\u043e\u043b\u043e\u043d\u043a\u0430\u0445 <strong>\u0410<\/strong> \u0438 <strong>B<\/strong> \u2014 4000 \u0441\u0442\u0440\u043e\u043a \u0438 3999 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 (\u043f\u0435\u0440\u0432\u0443\u044e \u0441\u0442\u0440\u043e\u0447\u043a\u0443 \u0437\u0430\u043d\u0438\u043c\u0430\u044e\u0442 \u043d\u0430\u0437\u0432\u0430\u043d\u0438\u044f \u043a\u043e\u043b\u043e\u043d\u043e\u043a). \u0422\u0430\u043a\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c, \u0432 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0432\u0442\u0443\u044e\u0449\u0438\u0445 \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0438\u0445 \u0441\u043f\u0438\u0441\u043a\u0430\u0445 \u0431\u0443\u0434\u0435\u0442 \u043f\u043e 3999 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439. \u0412 \u043a\u043e\u043b\u043e\u043d\u043a\u0435 <strong>C<\/strong> \u2014 220 \u0441\u0442\u0440\u043e\u043a \u0438 219 \u0437\u043d\u0430\u0447\u0435\u043d\u0438\u0439 \u0432 \u0432\u044b\u043f\u0430\u0434\u0430\u044e\u0449\u0435\u043c \u0441\u043f\u0438\u0441\u043a\u0435 \u0441\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e.<\/p>\n<p>  <\/p>\n<p><img decoding=\"async\" src=\"https:\/\/habrastorage.org\/webt\/oi\/zx\/vl\/oizxvlqqwomnaojtyrr5g5si7ey.png\"><\/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-318200","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/318200","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=318200"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/318200\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=318200"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=318200"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=318200"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}