title: ASP.NET Core: Complex Model with comma separated values list
body: <p>Our request models are growing according to the growing complexity of our APIs and we decided to use complex types instead of using simple types for the parameters of the actions. </p>
  
  <p>One typical type is <code>IEnumerable</code> for comma-separated values, like <code>items=1,2,3,5...</code> and we solved the issue of converting from string to IEnumerable using the workaround provided in <a href="https://www.strathweb.com/2017/07/customizing-query-string-parameter-binding-in-asp-net-core-mvc/" rel="nofollow noreferrer">https://www.strathweb.com/2017/07/customizing-query-string-parameter-binding-in-asp-net-core-mvc/</a> where the key point is implementing the <code>IActionModelConvention</code> interface to identify the parameters marked with a specific attribute <code>[CommaSeparated]</code>. </p>
  
  <p>Everything worked fine until we moved the simple parameters into a single complex parameter, now we are unable to inspect the complex parameters in the <code>IActionModelConvention</code> implementation. The same happens using <code>IParameterModelConvention</code>. Please, see the code below: </p>
  
  <p>this works fine:</p>
  
  <pre><code> public async Task&lt;IActionResult&gt; GetByIds(
         [FromRoute]int day,
         [BindRequired][FromQuery][CommaSeparated]IEnumerable&lt;int&gt; ids,
         [FromQuery]string order)
   {
          // do something
   }
  </code></pre>
  
  <p>while this variant does not work</p>
  
  <pre><code> public class GetByIdsRequest
   {
      [FromRoute(Name = "day")]
      public int Day { get; set; }
  
      [BindRequired]
      [FromQuery(Name = "ids")]
      [CommaSeparated]
      public IEnumerable&lt;int&gt; Ids { get; set; }
  
      [FromQuery(Name = "order")]
      public string Order { get; set; }
   }
  
   public async Task&lt;IActionResult&gt; GetByIds(GetByIdsRequest request)
   {
          // do something
   }
  </code></pre>
  
  <p>the <code>IActionModelConvention</code> implementation is very simple:</p>
  
  <pre><code>public void Apply(ActionModel action)
  {
     SeparatedQueryStringAttribute attribute = null;
     for (int i = 0; i &lt; action.Parameters.Count; i++)
     {
         var parameter = action.Parameters[i];
         var commaSeparatedAttr = parameter.Attributes.OfType&lt;CommaSeparatedAttribute&gt;().FirstOrDefault();
         if (commaSeparatedAttr != null)
         {
             if (attribute == null)
             {
                  attribute = new SeparatedQueryStringAttribute(",", commaSeparatedAttr.RemoveDuplicatedValues);
                   parameter.Action.Filters.Add(attribute);
              }
  
              attribute.AddKey(parameter.ParameterName);
          }
      }
   } 
  </code></pre>
  
  <p>As you can see, the code is inspecting the parameters marked with <code>CommaSeparatedAttribute</code>...but it doesn't work with complex parameters like the one used in my second variant. </p>
  
  <p>Note: I added some minor changes to the original code provided in the post above mentioned like enabling the <code>CommaSeparatedAttribute</code> to be used not only for parameters but also for properties, but still it doesn't work</p>