6

So, I am using CookComputings XMLRPC library to be able to talk to InfusionSoft (it's an online CRM that's quite popular). The main method is:

 [XmlRpcMethod("DataService.query")]
 IEnumerable<object> QuerySubscriptionStatus(string apiKey, 
        string table, int limit, int page, 
        IDictionary queryData, string[] selectedFields);

I am REQUIRED to use an IEnumerable<object> sadly, as the InfusionSoft XML/RPC API requires it. I wish it wasn't the case, but sadly it is.

Since I use .NET 4.5, I figured I can just do a dynamic cast:

  var subStatus = proxy.QuerySubscriptionStatus(
      _key, "RecurringOrder", 500, 0, dict, sarray);
  var result = subStatus.Cast<SubscriptionStatus>();

Unfortunately, this doesn't work, I'm given a very upset error from C#:

Unable to cast object of type 'CookComputing.XmlRpc.XmlRpcStruct' to type 'WBI.Model.SubscriptionStatus'.`

I've tried specifying my class as a struct; heck I've even tried specifying it with XMLRpcMember() tags, but nope, it just wont convert.

How can I interact with the data in the IEnumerable?

Class/Struct Types I've Tried

public struct SubStatus
{
    public int AffiliateId;
    public int AutoCharge;
    public double BillingAmt;
    public string BillingCycle;
    public int CC1;
    public int CC2;
    public int ContactId;
    public DateTime EndDate;
    public int Frequency;
    public int Id;
    public DateTime LastBillDate;
    public int LeadAffiliateId;
    public int MaxRetry;
    public int MerchantAccountId;
    public DateTime NextBillDate;
    public int NumDaysBetweenRetry;
    public int OriginatingOrderId;
    public DateTime PaidThruDate;
    public int PaymentGatewayId;
    public int ProductId;
    public int ProgramId;
    public string PromoCode;
    public int Qty;
    public string ReasonStopped;
    public int ShippingOptionId;
    public DateTime StartDate;
    public string Status;
    public int SubscriptionPlanId;
}

I also just tried a simple class with the XMLRpcMember tags:

public class SubscriptionStatus
{
    [XmlRpcMember("AffiliateId")]
    public int AffiliateId { get; set; }
    [XmlRpcMember("AutoCharge")]
    public int AutoCharge { get; set; }
    [XmlRpcMember("BillingAmt")]
    public double BillingAmt { get; set; }
    [XmlRpcMember("BillingCycle")]
    public string BillingCycle { get; set; }
    [XmlRpcMember("CC1")]
    public int CC1 { get; set; }
    [XmlRpcMember("CC2")]
    public int CC2 { get; set; }
    [XmlRpcMember("ContactId")]
    public int ContactId { get; set; }
    [XmlRpcMember("EndDate")]
    public DateTime EndDate { get; set; }
    [XmlRpcMember("Frequency")]
    public int Frequency { get; set; }
    [XmlRpcMember("Id")]
    public int Id { get; set; }
    [XmlRpcMember("LastBillDate")]
    public DateTime LastBillDate { get; set; }
    [XmlRpcMember("LeadAffiliateId")]
    public int LeadAffiliateId { get; set; }
    [XmlRpcMember("MaxRetry")]
    public int MaxRetry { get; set; }
    [XmlRpcMember("MerchantAccountId")]
    public int MerchantAccountId { get; set; }
    [XmlRpcMember("NextBillDate")]
    public DateTime NextBillDate { get; set; }
    [XmlRpcMember("NumDaysBetweenRetry")]
    public int NumDaysBetweenRetry { get; set; }
    [XmlRpcMember("OriginatingOrderId")]
    public int OriginatingOrderId { get; set; }
    [XmlRpcMember("PaidThruDate")]
    public DateTime PaidThruDate { get; set; }
    [XmlRpcMember("PaymentGatewayId")]
    public int PaymentGatewayId { get; set; }
    [XmlRpcMember("ProductId")]
    public int ProductId { get; set; }
    [XmlRpcMember("ProgramId")]
    public int ProgramId { get; set; }
    [XmlRpcMember("PromoCode")]
    public string PromoCode { get; set; }
    [XmlRpcMember("Qty")]
    public int Qty { get; set; }
    [XmlRpcMember("ReasonStopped")]
    public string ReasonStopped { get; set; }
    [XmlRpcMember("ShippingOptionId")]
    public int ShippingOptionId { get; set; }
    [XmlRpcMember("StartDate")]
    public DateTime StartDate { get; set; }
    [XmlRpcMember("Status")]
    public string Status { get; set; }
    [XmlRpcMember("SubscriptionPlanId")]
    public int SubscriptionPlanId { get; set; }
}
zackrspv
  • 170
  • 14

2 Answers2

1

So, after some extended help from another senior developer, it turns out we were able to make some changes to the struct:

    private string[] retFlds = { "Id", "ContactId", "OriginatingOrderId", "ProgramId", "SubscriptionPlanId", "ProductId", "StartDate", "NextBillDate", "BillingCycle", "Frequency", "BillingAmt", "Status", "ReasonStopped", "AutoCharge", "CC1", "CC2", "NumDaysBetweenRetry", "MaxRetry", "MerchantAccountId", "AffiliateId", "PromoCode", "LeadAffiliateId", "Qty", "ShippingOptionId" };
    private string table = "RecurringOrder";
    private DataTable dt = new DataTable();
    // here's the query 
    XmlRpcStruct[] retData = proxy.Query(Auth.key, table, 1000, 0, qryData, returnFields);
    dt = StructArrayToDT(retData);

    public static DataTable StructArrayToDT(XmlRpcStruct[] data)
    {
        DataTable dt = new DataTable();
        if (data.Length == 0) { return dt; }

        // do columns
        foreach (DictionaryEntry d in data[0])
        {
            dt.Columns.Add(d.Key.ToString(), typeof(object));
        }

        foreach (XmlRpcStruct xmlstruct in data)
        {
            DataRow dr = dt.NewRow();
            foreach (DictionaryEntry d in xmlstruct)
            {
                try
                {
                    dr[d.Key.ToString()] = d.Value;
                }
                catch (Exception ex)
                { 
                    // handle errors
                }

            }
            dt.Rows.Add(dr);
        }
        return dt;
    }

Finally can access that data without any issue now.

zackrspv
  • 170
  • 14
0

Looking at signature of QuerySubscriptionStatus its returning IEnumerable. Again if you look at definition of XmlRpcStruct (Fork of XML.Rpc.Net) which is implementing IDictionary, ICollection, IEnumerable. So if we assume that QuerySubscriptionStatus is returning XmlRpcStruct which implements IEnumerable then you are getting Enumeration in response which is essentially collection of items (even if it contains single item). You are trying to typecast Enumeration to structure (SubscriptionStatus) which is not collection. Hence the error. If items contained in Enumeration are of type SubscriptionStatus structure then following line should do trick.

var resultList = subStatus.ToList<SubscriptionStatus();

and then loop through resultList to access response from QuerySubscriptionStatus method.

foreach(var result in resultList)
{

}

OR if you are sure that response list will have single entry then you may also use following

var result = resultList.FirstOrDefault();

Hope that helps.

Pankaj Kapare
  • 7,486
  • 5
  • 40
  • 56
  • Unfortunately, casting that to a List isn't possible as IEnumerable doesn't allow it. This has been a frustrating journey lol thank you for the suggestion though :) `Compiler Error Message: CS1929: 'IEnumerable' does not contain a definition for 'ToList' and the best extension method overload 'Enumerable.ToList(IEnumerable)' requires a receiver of type 'IEnumerable'` – zackrspv Mar 01 '17 at 20:42