0

In a .NET Core 6 RestAPI application, I'm tracking global stock exchanges and have an instance of the below Exchange class called "ex".

public class Exchange
{
    public string CountryCode { get; set; }
    public string Currency { get; set; }
    public string DataSourceCode { get; set; }
    public int DaysHoursId { get; set; }
    public string ExchangeCode { get; set; }
    public string ExchangeName { get; set; }
    public int Id { get; set; }
    public bool IsActive { get; set; }
    public DateTimeOffset LastUpdatedDate { get; set; }
    public string LastUpdatedStatus { get; set; }
    public DateTimeOffset NextUpdateDateTime { get; set; }
    public string Region { get; set; }
    public string Timezone { get; set; }
    public string Type { get; set; }
    public string Url { get; set; }
    public string Website { get; set; }
}

All fields are populated with non-null data. In this case, the body of my Postman call is: { "CountryCode": "USA", "Currency": "USD", "DataSourceCode": "IA2", "DaysHoursId": 2, "ExchangeCode": "AMEX", "ExchangeName": "AMEX",
"IsActive": true, "LastUpdatedDate": "2022-04-24T15:42:28.2533333+00:00", "LastUpdatedStatus": "OK", "NextUpdateDateTime": "2022-04-24T15:42:28.2533333+00:00", "Region": "NORTH AMERICA", "Timezone": "EST", "Type": "STOCK", "Url": "https://www.nyse.com/markets/nyse-american", "Website": "www.AMEX.com" }

Using Reflection, I create a DataTable from this object with all columns except for "Id", which is an Identity primary key in the table to which data will be loaded, as follows:

 PropertyDescriptorCollection props = TypeDescriptor.GetProperties(ex);
 DataTable dt = new DataTable();
 foreach (PropertyDescriptor p in props)
 {
      if (p.Name != "Id")  // insert into an identity column not allowed.
      { 
           dt.Columns.Add(p.Name, p.PropertyType);
      }
 }

I then attempt to create a row in the dt datatable, as follows:

DataRow dr = dt.NewRow();
Type t = ex.GetType();
for (int i = 0; i <= dt.Columns.Count; i++)
{
    t.InvokeMember(dt.Columns[i].ColumnName, System.Reflection.BindingFlags.SetProperty, null, ex, new object[] { dt.Columns[i].ColumnName });
}

... which, when executed and traced, InvokeMember successfully iterated through the CountryCode, Currency, and DataSourceCode columns, but then - when it reaches DaysHoursId - threw a "System.MissingMethodException: 'Method MarketApi.Core.Entitites.Exchange.DaysHoursId' not found' exception.

Any insight as to what I'm doing wrong would be very much appreciated!

PaulPerkins
  • 113
  • 3
  • 12
  • I would assume that it's failing on that property because the value you're passing is a `string`. The previous properties are all type `string` so assigning a column name to them will work. That property is type `int` though, so you need to pass an `int` value to assign to it, not a `string`. – John Apr 28 '22 at 09:23
  • @John - In the above Postman call, I am passing an integer value of 2. Is this what you meant? – PaulPerkins Apr 28 '22 at 09:29
  • 2
    When you call `t.InvokeMember`, the last argument you provide, i.e. `new object[] { dt.Columns[i].ColumnName }` is an array of values to pass to the invoked member. Because you're invoking a property setter, that means that the element of that array is the value being assigned to the property. You are passing `dt.Columns[i].ColumnName` and expecting that to be assigned to an `int` property. – John Apr 28 '22 at 09:33

1 Answers1

0

It throws for DaysHoursId because it is the first non-string Property of your class Exchange. The problem is that you set the property names also as their values.

Works for CountryCode, Currency, DataSourceCode, that expect each a string value. But crashes on DaysHoursId. The binder looks for a string property setter method of name/signature set_DaysHoursId(string) which actually doesn't exist.

You rather want to assign the values in that loop:

DataRow dr = dt.NewRow();
Type t = ex.GetType();
//TODO fill your data in here
object [] values = new [dt.Columns.Count] { /* "de", "EUR", ... */};

for (int i = 0; i <= dt.Columns.Count; i++)
{
    t.InvokeMember(dt.Columns[i].ColumnName, System.Reflection.BindingFlags.SetProperty, null, ex, 
                  new [] { values [i] });
}
lidqy
  • 1,891
  • 1
  • 9
  • 11