LCOV - code coverage report
Current view: top level - Cqrs.WebApi/Formatters/FormMultipart/Converters - FormDataToObjectConverter.cs Hit Total Coverage
Test: doc-coverage.info Lines: 0 3 0.0 %
Date: 2017-07-26

          Line data    Source code
       1             : using System;
       2             : using System.Collections.Generic;
       3             : using System.Linq;
       4             : using System.Reflection;
       5             : using Cqrs.WebApi.Formatters.FormMultipart.Infrastructure;
       6             : using Cqrs.WebApi.Formatters.FormMultipart.Infrastructure.Extensions;
       7             : using Cqrs.WebApi.Formatters.FormMultipart.Infrastructure.Logger;
       8             : 
       9             : namespace Cqrs.WebApi.Formatters.FormMultipart.Converters
      10             : {
      11             :         public class FormDataToObjectConverter
      12           0 :         {
      13             :                 private readonly FormData _sourceData;
      14             : 
      15             :                 private readonly IFormDataConverterLogger _logger;
      16             : 
      17             :                 private readonly MultipartFormatterSettings _settings;
      18             : 
      19           0 :                 public FormDataToObjectConverter(FormData sourceData, IFormDataConverterLogger logger, MultipartFormatterSettings settings) 
      20             :                 {
      21             :                         if (sourceData == null)
      22             :                                 throw new ArgumentNullException("sourceData");
      23             :                         if (logger == null)
      24             :                                 throw new ArgumentNullException("logger");
      25             :                         if (settings == null)
      26             :                                 throw new ArgumentNullException("settings");
      27             : 
      28             :                         _settings = settings;
      29             :                         _sourceData = sourceData;
      30             :                         _logger = logger;
      31             :                 }
      32             : 
      33           0 :                 public object Convert(Type destinationType) 
      34             :                 {
      35             :                         if (destinationType == null)
      36             :                                 throw new ArgumentNullException("destinationType");
      37             : 
      38             :                         if (destinationType == typeof(FormData))
      39             :                                 return _sourceData;
      40             : 
      41             :                         var objResult = CreateObject(destinationType);
      42             :                         return objResult;
      43             :                 } 
      44             : 
      45             :                 private object CreateObject(Type destinationType, string propertyName = "")
      46             :                 {
      47             :                         object propValue = null;
      48             : 
      49             :                         if (propertyName == null)
      50             :                         {
      51             :                                 propertyName = "";
      52             :                         }
      53             : 
      54             :                         object buf;
      55             :                         if (TryGetAsNotIndexedListOrArray(destinationType, propertyName, out buf)
      56             :                                 || TryGetFromFormData(destinationType, propertyName, out buf)
      57             :                                 || TryGetAsGenericDictionary(destinationType, propertyName, out buf)
      58             :                                 || TryGetAsIndexedGenericListOrArray(destinationType, propertyName, out buf)
      59             :                                 || TryGetAsCustomType(destinationType, propertyName, out buf))
      60             :                         {
      61             :                                 propValue = buf;
      62             :                         }
      63             :                         else if (IsNotNullableValueType(destinationType)
      64             :                                 && IsNeedValidateMissedProperty(propertyName))
      65             :                         {
      66             :                                 _logger.LogError(propertyName, "The value is required.");
      67             :                         }
      68             :                         else if (!IsFileOrConvertableFromString(destinationType))
      69             :                         {
      70             :                                 _logger.LogError(propertyName, String.Format("Cannot parse type \"{0}\".", destinationType.FullName));
      71             :                         }
      72             : 
      73             :                         return propValue;
      74             :                 }
      75             : 
      76             :                 private bool TryGetAsNotIndexedListOrArray(Type destinationType, string propertyName, out object propValue)
      77             :                 {
      78             :                         propValue = null;
      79             : 
      80             :                         Type genericListItemType;
      81             :                         bool isGenericList = IsGenericListOrArray(destinationType, out genericListItemType);
      82             :                         if (isGenericList)
      83             :                         {
      84             :                                 var items = GetNotIndexedListItems(propertyName, genericListItemType);
      85             :                                 propValue = MakeList(genericListItemType, destinationType, items, propertyName);
      86             :                         }
      87             : 
      88             :                         return propValue != null;
      89             :                 }
      90             : 
      91             :                 private List<object> GetNotIndexedListItems(string propertyName, Type genericListItemType)
      92             :                 {
      93             :                         List<object> res;
      94             :                         if (!TryGetListFromFormData(genericListItemType, propertyName, out res))
      95             :                         {
      96             :                                 TryGetListFromFormData(genericListItemType, propertyName + "[]", out res);
      97             :                         }
      98             : 
      99             :                         return res ?? new List<object>();
     100             :                 }
     101             : 
     102             :                 private bool TryGetFromFormData(Type destinationType, string propertyName, out object propValue)
     103             :                 {
     104             :                         propValue = null;
     105             :                         List<object> values;
     106             :                         if (TryGetListFromFormData(destinationType, propertyName, out values))
     107             :                         {
     108             :                                 propValue = values.FirstOrDefault();
     109             :                                 return true;
     110             :                         }
     111             :                         return false;
     112             :                 }
     113             : 
     114             :                 private bool TryGetListFromFormData(Type destinationType, string propertyName, out List<object> propValue)
     115             :                 {
     116             :                         bool existsInFormData = false;
     117             :                         propValue = null;
     118             : 
     119             :                         if (destinationType == typeof(HttpFile) || destinationType == typeof(byte[]))
     120             :                         {
     121             :                                 var files = _sourceData.GetFiles(propertyName, _settings.CultureInfo);
     122             :                                 if (files.Any())
     123             :                                 {
     124             :                                         existsInFormData = true;
     125             :                                         propValue = new List<object>();
     126             : 
     127             :                                         foreach (var httpFile in files)
     128             :                                         {
     129             :                                                 var item = destinationType == typeof(byte[])
     130             :                                                         ? httpFile.Buffer
     131             :                                                         : (object)httpFile;
     132             : 
     133             :                                                 propValue.Add(item);
     134             :                                         }
     135             :                                 }
     136             :                         }
     137             :                         else
     138             :                         {
     139             :                                 var values = _sourceData.GetValues(propertyName, _settings.CultureInfo);
     140             :                                 if (values.Any())
     141             :                                 {
     142             :                                         existsInFormData = true;
     143             :                                         propValue = new List<object>();
     144             : 
     145             :                                         foreach (var value in values)
     146             :                                         {
     147             :                                                 object val;
     148             :                                                 if(TryConvertFromString(destinationType, propertyName, value, out val))
     149             :                                                 {
     150             :                                                         propValue.Add(val);
     151             :                                                 }
     152             :                                         }
     153             :                                 }
     154             :                         }
     155             : 
     156             :                         return existsInFormData;
     157             :                 }
     158             : 
     159             :                 private bool TryConvertFromString(Type destinationType, string propertyName, string val, out object propValue)
     160             :                 {
     161             :                         propValue = null;
     162             :                         var typeConverter = destinationType.GetFromStringConverter();
     163             :                         if (typeConverter == null)
     164             :                         {
     165             :                                 _logger.LogError(propertyName, "Cannot find type converter for field - " + propertyName);
     166             :                         }
     167             :                         else
     168             :                         {
     169             :                                 try
     170             :                                 {
     171             :                                         propValue = typeConverter.ConvertFromString(val, _settings.CultureInfo);
     172             :                                         return true;
     173             :                                 }
     174             :                                 catch (Exception ex)
     175             :                                 {
     176             :                                         _logger.LogError(propertyName, String.Format("Error parsing field \"{0}\": {1}", propertyName, ex.Message));
     177             :                                 }
     178             :                         }
     179             :                         return false;
     180             :                 }
     181             : 
     182             :                 private bool TryGetAsGenericDictionary(Type destinationType, string propertyName, out object propValue)
     183             :                 {
     184             :                         propValue = null;
     185             :                         Type keyType, valueType;
     186             :                         bool isGenericDictionary = IsGenericDictionary(destinationType, out keyType, out valueType);
     187             :                         if (isGenericDictionary)
     188             :                         {
     189             :                                 var dictType = typeof(Dictionary<,>).MakeGenericType(new[] { keyType, valueType });
     190             :                                 var add = dictType.GetMethod("Add");
     191             : 
     192             :                                 var pValue = Activator.CreateInstance(dictType);
     193             : 
     194             :                                 int index = 0;
     195             :                                 string origPropName = propertyName;
     196             :                                 bool isFilled = false;
     197             :                                 while (true)
     198             :                                 {
     199             :                                         string propertyKeyName = String.Format("{0}[{1}].Key", origPropName, index);
     200             :                                         var objKey = CreateObject(keyType, propertyKeyName);
     201             :                                         if (objKey != null)
     202             :                                         {
     203             :                                                 string propertyValueName = String.Format("{0}[{1}].Value", origPropName, index);
     204             :                                                 var objValue = CreateObject(valueType, propertyValueName);
     205             : 
     206             :                                                 if (objValue != null)
     207             :                                                 {
     208             :                                                         add.Invoke(pValue, new[] { objKey, objValue });
     209             :                                                         isFilled = true;
     210             :                                                 }
     211             :                                         }
     212             :                                         else
     213             :                                         {
     214             :                                                 break;
     215             :                                         }
     216             :                                         index++;
     217             :                                 }
     218             : 
     219             :                                 if (isFilled || IsRootProperty(propertyName))
     220             :                                 {
     221             :                                         propValue = pValue;
     222             :                                 }
     223             :                         }
     224             : 
     225             :                         return isGenericDictionary;
     226             :                 }
     227             : 
     228             :                 private bool TryGetAsIndexedGenericListOrArray(Type destinationType, string propertyName, out object propValue)
     229             :                 {
     230             :                         propValue = null;
     231             :                         Type genericListItemType;
     232             :                         bool isGenericList = IsGenericListOrArray(destinationType, out genericListItemType);
     233             :                         if (isGenericList)
     234             :                         {
     235             :                                 var items = GetIndexedListItems(propertyName, genericListItemType);
     236             :                                 propValue =  MakeList(genericListItemType, destinationType, items, propertyName);
     237             :                         }
     238             : 
     239             :                         return isGenericList;
     240             :                 }
     241             : 
     242             :                 private object MakeList(Type genericListItemType, Type destinationType, List<object> listItems, string propertyName)
     243             :                 {
     244             :                         object result = null;
     245             : 
     246             :                         if (listItems.Any() || IsRootProperty(propertyName))
     247             :                         {
     248             :                                 var listType = typeof(List<>).MakeGenericType(genericListItemType);
     249             : 
     250             :                                 var add = listType.GetMethod("Add");
     251             :                                 var pValue = Activator.CreateInstance(listType);
     252             : 
     253             :                                 foreach (var listItem in listItems)
     254             :                                 {
     255             :                                         add.Invoke(pValue, new[] { listItem });
     256             :                                 }
     257             : 
     258             :                                 if (destinationType.IsArray)
     259             :                                 {
     260             :                                         var toArrayMethod = listType.GetMethod("ToArray");
     261             :                                         result = toArrayMethod.Invoke(pValue, new object[0]);
     262             :                                 }
     263             :                                 else
     264             :                                 {
     265             :                                         result = pValue;
     266             :                                 }
     267             :                         }
     268             : 
     269             :                         return result;
     270             :                 }
     271             : 
     272             :                 private List<object> GetIndexedListItems(string origPropName, Type genericListItemType)
     273             :                 {
     274             :                         var res = new List<object>();
     275             :                         int index = 0;
     276             :                         while (true)
     277             :                         {
     278             :                                 var propertyName = String.Format("{0}[{1}]", origPropName, index);
     279             :                                 var objValue = CreateObject(genericListItemType, propertyName);
     280             :                                 if (objValue != null)
     281             :                                 {
     282             :                                         res.Add(objValue);
     283             :                                 }
     284             :                                 else
     285             :                                 {
     286             :                                         break;
     287             :                                 }
     288             : 
     289             :                                 index++;
     290             :                         }
     291             :                         return res;
     292             :                 }
     293             : 
     294             :                 private bool TryGetAsCustomType(Type destinationType, string propertyName, out object propValue)
     295             :                 {
     296             :                         propValue = null;
     297             :                         bool isCustomNonEnumerableType = destinationType.IsCustomNonEnumerableType();
     298             :                         if (isCustomNonEnumerableType && IsRootPropertyOrAnyChildPropertiesExistsInFormData(propertyName))
     299             :                         {
     300             :                                 propValue = Activator.CreateInstance(destinationType);
     301             :                                 foreach (PropertyInfo propertyInfo in destinationType.GetProperties().Where(m => m.SetMethod != null))
     302             :                                 {
     303             :                                         var propName = (!String.IsNullOrEmpty(propertyName) ? propertyName + "." : "") + propertyInfo.Name;
     304             : 
     305             :                                         var objValue = CreateObject(propertyInfo.PropertyType, propName);
     306             :                                         if (objValue != null)
     307             :                                         {
     308             :                                                 propertyInfo.SetValue(propValue, objValue);
     309             :                                         }
     310             :                                 }
     311             :                         }
     312             :                         return isCustomNonEnumerableType;
     313             :                 }
     314             : 
     315             : 
     316             :                 private bool IsGenericDictionary(Type type, out Type keyType, out Type valueType)
     317             :                 {
     318             :                         Type iDictType = type.GetInterface(typeof (IDictionary<,>).Name);
     319             :                         if (iDictType != null)
     320             :                         {
     321             :                                 var types = iDictType.GetGenericArguments();
     322             :                                 if (types.Length == 2)
     323             :                                 {
     324             :                                         keyType = types[0];
     325             :                                         valueType = types[1];
     326             :                                         return true;
     327             :                                 }
     328             :                         }
     329             : 
     330             :                         keyType = null;
     331             :                         valueType = null;
     332             :                         return false;
     333             :                 }
     334             : 
     335             :                 private bool IsGenericListOrArray(Type type, out Type itemType)
     336             :                 {
     337             :                         if (type.GetInterface(typeof(IDictionary<,>).Name) == null) //not a dictionary
     338             :                         {
     339             :                                 if (type.IsArray)
     340             :                                 {
     341             :                                         itemType = type.GetElementType();
     342             :                                         return true;
     343             :                                 }
     344             : 
     345             :                                 Type iListType = type.GetInterface(typeof(ICollection<>).Name);
     346             :                                 if (iListType != null) 
     347             :                                 {
     348             :                                         Type[] genericArguments = iListType.GetGenericArguments();
     349             :                                         if (genericArguments.Length == 1)
     350             :                                         {
     351             :                                                 itemType = genericArguments[0];
     352             :                                                 return true;
     353             :                                         }
     354             :                                 }
     355             :                         }
     356             :                   
     357             :                         itemType = null;
     358             :                         return false;
     359             :                 }
     360             : 
     361             :                 private bool IsFileOrConvertableFromString(Type type)
     362             :                 {
     363             :                         if (type == typeof (HttpFile))
     364             :                                 return true;
     365             : 
     366             :                         return type.GetFromStringConverter() != null;
     367             :                 }
     368             : 
     369             :                 private bool IsNotNullableValueType(Type type)
     370             :                 {
     371             :                         if (!type.IsValueType)
     372             :                                 return false;
     373             : 
     374             :                         return Nullable.GetUnderlyingType(type) == null;
     375             :                 }
     376             : 
     377             :                 private bool IsNeedValidateMissedProperty(string propertyName)
     378             :                 {
     379             :                         return _settings.ValidateNonNullableMissedProperty
     380             :                                         && !IsIndexedProperty(propertyName)
     381             :                                         && IsRootPropertyOrAnyParentsPropertyExistsInFormData(propertyName);
     382             :                 }
     383             : 
     384             :                 private bool IsRootPropertyOrAnyParentsPropertyExistsInFormData(string propertyName)
     385             :                 {
     386             :                         string parentName = "";
     387             :                         if (propertyName != null)
     388             :                         {
     389             :                                 int lastDotIndex = propertyName.LastIndexOf('.');
     390             :                                 if (lastDotIndex >= 0)
     391             :                                 {
     392             :                                         parentName = propertyName.Substring(0, lastDotIndex);
     393             :                                 }
     394             :                         }
     395             : 
     396             :                         bool result = IsRootPropertyOrAnyChildPropertiesExistsInFormData(parentName);
     397             :                         return result;
     398             :                 }
     399             : 
     400             :                 private bool IsRootPropertyOrAnyChildPropertiesExistsInFormData(string propertyName)
     401             :                 {
     402             :                         if (IsRootProperty(propertyName))
     403             :                                 return true;
     404             : 
     405             :                         string prefixWithDot = propertyName + ".";
     406             :                         bool result = _sourceData.GetAllKeys().Any(m => m.StartsWith(prefixWithDot, true, _settings.CultureInfo));
     407             :                         return result;
     408             :                 }
     409             : 
     410             :                 private bool IsRootProperty(string propertyName)
     411             :                 {
     412             :                         return propertyName == "";
     413             :                 }
     414             : 
     415             :                 private bool IsIndexedProperty(string propName)
     416             :                 {
     417             :                         return propName != null && propName.EndsWith("]");
     418             :                 }
     419             :         }
     420             : }

Generated by: LCOV version 1.10