Highrise Api, Subject data not posting with RestSharp

111 views Asked by At

I am trying to use the Highrise Api with the .NET 4.5 wrapper by scottschluer in order to post a new Person to our Highrise account along with any custom data that they enter.

The issue that I am running into is with the custom data. The person object gets posted just fine, but the subject data fields are not being included with the post.

I did come across this post: Highrise Custom Fields. It looked like the thing that was missing was the type="array" attribute from the subject_datas field. I tested this hypothesis by manually creating a request using the serialized value of the object I was trying to post. The result of this test, was a successful post to the server with all custom data fields filled.

I've tried extending the classes from the wrapper assembly to add that missing attribute to the list, but that still didn't seem to work. The Person object has a property for a List of SubjectData objects, I overwrote that property in a child class to use a custom class instead. This way I could add a property to use as the attribute. This custom class still didn't seem to work.

After looking at the code for RestSharp's XmlSerializer, it appears that it will only add a list of items when that object implements IList. That wasn't an issue, i was able to get that working, but the code does not seem to allow for adding attributes to the list element. It only looks at the children of the list class and ignores any other properties on the object.

So my question is this:

Is it possible to apply attributes to a list property in RestSharp, or is there another way to add the type="array" attribute to the data_subjects xml node before the request is sent?

1

There are 1 answers

0
Michael DeRuscio On BEST ANSWER

I eventually solved the problem myself by creating a new request class that would create a RestRequest using a custom XmlSerializer.

I then extended the Person class and hid the property behind a custom list object property

Before:

[SerializeAs(Name = "subject_datas")]
public List<SubjectData> SubjectDatas { get; set; }

After:

[SerializeAs(Name = "subject_datas")]
public new SubjectDataList SubjectDatas { get; set; }

The SubjectDataList class is just a wrapper for List<SubjectData>.

SubjectDataList implements an interface called ISerializeList<SubjectData> which is defined as:

interface ISerializeList : IEnumerable {}
interface ISerializeList<T> :IEnumerable<T>, ISerializeList {}

SubjectDataList also has a type property to render the type attribute onto the subjectdatas node of the rest request.

[SerializeAs(Name = "type", Attribute = true)]
public string Type { get; set; } = "array";

I then made a class called XmlListSerializer which implements ISerializer. I copied the implementation of XmlSerializer, but i made a few modifications. In the Map method, there is a part that checks if the variable rawValue is an IList. I changed this part slightly, and added a clause for my XmlListSerializer class.

So it now looks like this:

if (propType.IsPrimitive || propType.IsValueType || propType == typeof(string)) {
    //...
} else if (rawValue is IList) {
    ProcessIList((IList) rawValue, element);
} else if (rawValue is ISerializeList) {
    ProcessISerializeList((ISerializeList) rawValue, element);
} else {
    Map(element, rawValue);
}

Where ProcessIList and ProcessISerializeList are defined as:

private void ProcessIList(IList list, XElement element) {
    ProcessIEnumerable(list, element);
}
private void ProcessISerializeList(ISerializeList list, XElement element) {
    ProcessIEnumerable(list, element);
    Map(element, list);
}
private void ProcessIEnumerable(IEnumerable list, XElement element) {
    var itemTypeName = "";
    foreach (var item in list) {
        if (itemTypeName == "") {
            var type = item.GetType();
            var setting = type.GetAttribute<SerializeAsAttribute>();

            itemTypeName = setting != null && setting.Name.HasValue() ? setting.Name : type.Name;
        }

        var instance = new XElement(itemTypeName.AsNamespaced(Namespace));

        Map(instance, item);
        element.Add(instance);
    }
}

I hope this answer will be able to help anyone else having issues with this problem.