Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public class FormDataToObjectConverter
private readonly IFormDataConverterLogger Logger;
private readonly MultipartFormatterSettings Settings;

public FormDataToObjectConverter(FormData sourceData, IFormDataConverterLogger logger, MultipartFormatterSettings settings)
public FormDataToObjectConverter(FormData sourceData, IFormDataConverterLogger logger,
MultipartFormatterSettings settings)
{
if (sourceData == null)
throw new ArgumentNullException("sourceData");
Expand All @@ -28,7 +29,7 @@ public FormDataToObjectConverter(FormData sourceData, IFormDataConverterLogger l
Logger = logger;
}

public object Convert(Type destinationType)
public object Convert(Type destinationType)
{
if (destinationType == null)
throw new ArgumentNullException("destinationType");
Expand All @@ -38,7 +39,7 @@ public object Convert(Type destinationType)

var objResult = CreateObject(destinationType);
return objResult;
}
}

private object CreateObject(Type destinationType, string propertyName = "")
{
Expand All @@ -59,7 +60,7 @@ private object CreateObject(Type destinationType, string propertyName = "")
propValue = buf;
}
else if (IsNotNullableValueType(destinationType)
&& IsNeedValidateMissedProperty(propertyName))
&& IsNeedValidateMissedProperty(propertyName))
{
Logger.LogError(propertyName, "The value is required.");
}
Expand All @@ -75,7 +76,7 @@ private bool TryGetAsNotIndexedListOrArray(Type destinationType, string property
{
propValue = null;

Type genericListItemType;
Type genericListItemType;
if (IsGenericEnumerable(destinationType, out genericListItemType))
{
var items = GetNotIndexedListItems(propertyName, genericListItemType);
Expand Down Expand Up @@ -105,6 +106,7 @@ private bool TryGetFromFormData(Type destinationType, string propertyName, out o
propValue = values.FirstOrDefault();
return true;
}

return false;
}

Expand Down Expand Up @@ -142,7 +144,7 @@ private bool TryGetListFromFormData(Type destinationType, string propertyName, o
foreach (var value in values)
{
object val;
if(TryConvertFromString(destinationType, propertyName, value, out val))
if (TryConvertFromString(destinationType, propertyName, value, out val))
{
propValue.Add(val);
}
Expand Down Expand Up @@ -170,16 +172,18 @@ private bool TryConvertFromString(Type destinationType, string propertyName, str
}
catch (Exception ex)
{
Logger.LogError(propertyName, String.Format("Error parsing field \"{0}\": {1}", propertyName, ex.Message));
Logger.LogError(propertyName,
String.Format("Error parsing field \"{0}\": {1}", propertyName, ex.Message));
}
}

return false;
}

private bool TryGetAsGenericDictionary(Type destinationType, string propertyName, out object propValue)
{
propValue = null;
Type keyType, valueType;
Type keyType, valueType;
if (IsGenericDictionary(destinationType, out keyType, out valueType))
{
var dictType = typeof(Dictionary<,>).MakeGenericType(new[] { keyType, valueType });
Expand Down Expand Up @@ -209,6 +213,7 @@ private bool TryGetAsGenericDictionary(Type destinationType, string propertyName
{
break;
}

index++;
}

Expand All @@ -218,25 +223,27 @@ private bool TryGetAsGenericDictionary(Type destinationType, string propertyName
}

return true;
}
}

return false;
}

private bool TryGetAsIndexedGenericListOrArray(Type destinationType, string propertyName, out object propValue)
{
Type genericListItemType;
{
Type genericListItemType;
if (IsGenericEnumerable(destinationType, out genericListItemType))
{
var items = GetIndexedListItems(propertyName, genericListItemType);
propValue = MakeList(genericListItemType, destinationType, items, propertyName);
propValue = MakeList(genericListItemType, destinationType, items, propertyName);
return true;
}

propValue = null;
return false;
}

private object MakeList(Type genericListItemType, Type destinationType, List<object> listItems, string propertyName)
private object MakeList(Type genericListItemType, Type destinationType, List<object> listItems,
string propertyName)
{
object result = null;

Expand Down Expand Up @@ -285,17 +292,45 @@ private List<object> GetIndexedListItems(string origPropName, Type genericListIt

index++;
}

return res;
}

private bool TryGetAsCustomType(Type destinationType, string propertyName, out object propValue)
{
var realDestinationType = destinationType;

propValue = null;
bool isCustomNonEnumerableType = destinationType.IsCustomNonEnumerableType();
if (isCustomNonEnumerableType && IsRootPropertyOrAnyChildPropertiesExistsInFormData(propertyName))
{
propValue = Activator.CreateInstance(destinationType);
foreach (PropertyInfo propertyInfo in destinationType.GetProperties().Where(m => m.SetMethod != null))
propValue = null;
var typeConverter = destinationType.GetFromValueStringConverter();

if (typeConverter == null)
{
propValue = Activator.CreateInstance(destinationType);
}
else
{
try
{
var prefixWithDot = propertyName + ".";
var values = SourceData.Fields
.Where(_ => _.Name.StartsWith(prefixWithDot, true, Settings.CultureInfo)).ToArray();
propValue = typeConverter.ConvertFromValueString(values, Settings.CultureInfo);
realDestinationType = propValue.GetType();
}

catch (Exception ex)
{
Logger.LogError(propertyName,
String.Format("Error parsing field \"{0}\": {1}", propertyName, ex.Message));
}
}

foreach (PropertyInfo propertyInfo in realDestinationType.GetProperties()
.Where(m => m.SetMethod != null))
{
var propName = (!String.IsNullOrEmpty(propertyName) ? propertyName + "." : "") + propertyInfo.Name;

Expand All @@ -306,10 +341,10 @@ private bool TryGetAsCustomType(Type destinationType, string propertyName, out o
}
}
}

return isCustomNonEnumerableType;
}


private bool IsGenericDictionary(Type type, out Type keyType, out Type valueType)
{
var iDictType = GetGenericType(type, typeof(IDictionary<,>));
Expand All @@ -335,7 +370,7 @@ private bool IsGenericEnumerable(Type type, out Type itemType)
&& !type.Equals(typeof(string))) //not a string
{
var enumerType = GetGenericType(type, typeof(IEnumerable<>));
if (enumerType != null)
if (enumerType != null)
{
Type[] genericArguments = enumerType.GetGenericArguments();
if (genericArguments.Length == 1)
Expand All @@ -345,21 +380,21 @@ private bool IsGenericEnumerable(Type type, out Type itemType)
}
}
}

itemType = null;
return false;
}

private Type GetGenericType(Type type, Type genericTypeDefinition)
{
{
return type.IsGenericType && genericTypeDefinition.Equals(type.GetGenericTypeDefinition())
? type
: type.GetInterface(genericTypeDefinition.Name);
}

private bool IsFileOrConvertableFromString(Type type)
{
if (type == typeof (HttpFile))
if (type == typeof(HttpFile))
return true;

return type.GetFromStringConverter() != null;
Expand All @@ -376,8 +411,8 @@ private bool IsNotNullableValueType(Type type)
private bool IsNeedValidateMissedProperty(string propertyName)
{
return Settings.ValidateNonNullableMissedProperty
&& !IsIndexedProperty(propertyName)
&& IsRootPropertyOrAnyParentsPropertyExistsInFormData(propertyName);
&& !IsIndexedProperty(propertyName)
&& IsRootPropertyOrAnyParentsPropertyExistsInFormData(propertyName);
}

private bool IsRootPropertyOrAnyParentsPropertyExistsInFormData(string propertyName)
Expand Down Expand Up @@ -416,4 +451,4 @@ private bool IsIndexedProperty(string propName)
return propName != null && propName.EndsWith("]");
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace MultipartDataMediaFormatter.Infrastructure.Extensions
{
internal static class TypeExtensions
{
internal static FromStringConverterAdapter GetFromStringConverter(this Type type)
internal static FromStringOrValueStringConverterAdapter GetFromStringConverter(this Type type)
{
TypeConverter typeConverter = TypeDescriptor.GetConverter(type);

Expand All @@ -21,7 +21,7 @@ internal static FromStringConverterAdapter GetFromStringConverter(this Type type
typeConverter = null;
}

return typeConverter == null ? null : new FromStringConverterAdapter(type, typeConverter);
return typeConverter == null ? null : new FromStringOrValueStringConverterAdapter(type, typeConverter);
}

internal static TypeConverter GetToStringConverter(this Type type)
Expand All @@ -38,18 +38,39 @@ internal static TypeConverter GetToStringConverter(this Type type)
}
return typeConverter;
}

internal static FromStringOrValueStringConverterAdapter GetFromValueStringConverter(this Type type)
{
TypeConverter typeConverter = TypeDescriptor.GetConverter(type);

if (typeConverter is BooleanConverter)
{
//replace default boolean converter for deserializing on/off values received from html page
typeConverter = new BooleanConverterEx();
}

if (typeConverter != null && !typeConverter.CanConvertFrom(typeof(FormData.ValueString)))
{
typeConverter = null;
}

return typeConverter == null ? null : new FromStringOrValueStringConverterAdapter(type, typeConverter);
}

internal static bool IsCustomNonEnumerableType(this Type type)
{
var nullType = Nullable.GetUnderlyingType(type);

if (nullType != null)
{
type = nullType;
}

if (type.IsGenericType)
{
type = type.GetGenericTypeDefinition();
}

return type != typeof(object)
&& Type.GetTypeCode(type) == TypeCode.Object
&& type != typeof(HttpFile)
Expand Down
19 changes: 18 additions & 1 deletion src/MultipartDataMediaFormatter/Infrastructure/HttpFile.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace MultipartDataMediaFormatter.Infrastructure
using System.IO;

namespace MultipartDataMediaFormatter.Infrastructure
{
public class HttpFile
{
Expand All @@ -14,5 +16,20 @@ public HttpFile(string fileName, string mediaType, byte[] buffer)
MediaType = mediaType;
Buffer = buffer;
}

public void SaveAs(string fileName)
{
var fileStream = new FileStream(fileName, FileMode.Create);
try
{
fileStream.Write(Buffer, 0, Buffer.Length);
fileStream.Flush();
}

finally
{
fileStream.Close();
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

namespace MultipartDataMediaFormatter.Infrastructure.TypeConverters
{
public class FromStringConverterAdapter
public class FromStringOrValueStringConverterAdapter
{
private readonly Type Type;
private readonly TypeConverter TypeConverter;
public FromStringConverterAdapter(Type type, TypeConverter typeConverter)

public FromStringOrValueStringConverterAdapter(Type type, TypeConverter typeConverter)
{
if(type == null)
if (type == null)
throw new ArgumentNullException("type");
if (typeConverter == null)
throw new ArgumentNullException("typeConverter");
Expand All @@ -27,5 +28,14 @@ public object ConvertFromString(string src, CultureInfo culture)

return TypeConverter.ConvertFromString(null, culture, src);
}

public object ConvertFromValueString(FormData.ValueString[] src, CultureInfo culture)
{
var isUndefinedNullable = Nullable.GetUnderlyingType(Type) != null;
if (isUndefinedNullable)
return null;

return TypeConverter.ConvertFrom(null, culture, src);
}
}
}