mardi 11 juin 2019

Generic Mapper on Enumerable properties

I'm making a generic mapper to map an entity from DynamicsCrm web service request to a response model. My plan was to decorate each property in the response with an attribute that holds the equivalent dynamics entity's field name. I'm having some trouble figuring out what to do with enumerable types and nested classes, if someone could point me in the right direction I'd be grateful.

The map method (so far)

public static T Map<T>(this Entity entity, T response) where T : class
{
    if (entity != null)
    {
        foreach (var prop in response.GetType()
            .GetProperties(BindingFlags.Instance | BindingFlags.Public))
        {                   
            if (null != prop && prop.CanWrite)
            {
                if (IsEnumerable(prop))
                {
                    //I think here I need to first check if it's 
                    //an enumerated class, loop and recursively call 
                    //this method for the property types of that class?
                    //otherwise just loop and assign values
                }
                else
                {

                    //here I need to check if the property is a nested class
                    // and recursively call this method if so.

                    //If it's not a class then the following code will
                    //assign values to the property
                    //Get attributes on the property and if correct 
                    //attribute, get column name 
                    var attribute = prop.GetCustomAttributes(typeof(Attributes.DynamicsCrmAttribute), true);

                    if (attribute.Length > 0)
                    {
                        var crmColumnName = ((Attributes.DynamicsCrmAttribute)attribute[0]).CrmColumnName;

                        if (entity.Contains(crmColumnName) && !string.IsNullOrWhiteSpace(crmColumnName))
                        {
                            if (!string.IsNullOrWhiteSpace(entity[crmColumnName].ToString()))
                            {
                                var value = Convert.ChangeType(entity[crmColumnName], prop.PropertyType, null);

                                prop.SetValue(response, value);
                            }
                        }
                    }
                }
            }
        }
    }

    return response;
}

An example of a response, and it's nested models:

 public class CrmGetUserResponse : CrmBaseResponse
 {
    public IEnumerable<CrmUser> CrmUsers { get; set; }
 }

 public class CrmUser
 {
     [DynamicsCrm(CrmColumnName = "Id")]
     public string ContactId { get; set; }

     [DynamicsCrm(CrmColumnName = "firstName")]
     public string FirstName { get; set; }

     [DynamicsCrm(CrmColumnName = "lastName")]
     public string LastName { get; set; }

     public IEnumerable<CrmAddress> ContactAddresses {get; set;}
  }

 public class CrmAddress
 {
     [DynamicsCrm(CrmColumnName = "address1")]
     public string Address1 {get; set;}

     [DynamicsCrm(CrmColumnName = "address2")]
     public string Address2 {get; set;}

     //....etc...

  }





Aucun commentaire:

Enregistrer un commentaire