public override SelectParameterResult TryCast(BindingData bindingData) { var parameterRequiringValidation = bindingData.parameterRequiringValidation; var baseValue = base.TryCast(bindingData); if (baseValue.valid) { return(baseValue); } baseValue.value = GetValue(); baseValue.valid = true; baseValue.fromQuery = true; return(baseValue); object GetValue() { if (parameterRequiringValidation.ParameterType.IsSubClassOfGeneric(typeof(IRefOptional <>))) { var instance = RefOptionalHelper.CreateEmpty( parameterRequiringValidation.ParameterType.GenericTypeArguments.First()); return(instance); } return(parameterRequiringValidation.ParameterType.GetDefault()); } }
public override SelectParameterResult TryCast(BindingData bindingData) { var parameterRequiringValidation = bindingData.parameterRequiringValidation; var baseValue = base.TryCast(bindingData); if (baseValue.valid) { return(baseValue); } baseValue.valid = true; baseValue.fromBody = true; baseValue.value = GetValue(); return(baseValue); object GetValue() { var parameterType = parameterRequiringValidation.ParameterType; if (parameterType.IsSubClassOfGeneric(typeof(IRefOptional <>))) { var refType = parameterType.GenericTypeArguments.First(); var parameterTypeGeneric = RefOptionalHelper.CreateEmpty(refType); return(parameterTypeGeneric); } if (parameterType.IsSubClassOfGeneric(typeof(IRefs <>))) { var refType = parameterType.GenericTypeArguments.First(); var parameterTypeGeneric = typeof(Refs <>).MakeGenericType(new Type[] { refType }); var refIds = new Guid[] { }; var refIdsLookupType = typeof(Func <,>).MakeGenericType(new Type[] { typeof(Guid), refType }); var refIdsLookup = refIdsLookupType.GetDefault(); return(Activator.CreateInstance( parameterTypeGeneric, new object[] { refIds })); } if (parameterType.IsSubClassOfGeneric(typeof(IDictionary <,>))) { var parameterTypeGeneric = typeof(Dictionary <,>).MakeGenericType(parameterType.GenericTypeArguments); return(Activator.CreateInstance(parameterTypeGeneric)); } return(parameterType.GetDefault()); } }
public static object ReadJsonStatic(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { if (objectType == typeof(string)) { if (reader.TokenType == JsonToken.String) { var stringValue = reader.Value as string; return(stringValue); } if (reader.TokenType == JsonToken.Null) { return(null); } } if (objectType.IsSubClassOfGeneric(typeof(IReferenceable))) { if (objectType.IsSubClassOfGeneric(typeof(IRef <>))) { var id = GetGuid(); if (id.IsDefault()) { return(existingValue); } var refType = typeof(Ref <>).MakeGenericType(objectType.GenericTypeArguments); return(Activator.CreateInstance(refType, id)); } } if (objectType.IsSubClassOfGeneric(typeof(IReferenceableOptional))) { if (objectType.IsSubClassOfGeneric(typeof(IRefOptional <>))) { var id = GetGuidMaybe(); if (id == null) { return(RefOptionalHelper.CreateEmpty(objectType.GenericTypeArguments.First())); } var refType = typeof(RefOptional <>).MakeGenericType(objectType.GenericTypeArguments); return(Activator.CreateInstance(refType, id)); } } if (objectType.IsSubClassOfGeneric(typeof(IReferences))) { if (objectType.IsSubClassOfGeneric(typeof(IRefs <>))) { var ids = GetGuids(); var refType = typeof(Refs <>).MakeGenericType(objectType.GenericTypeArguments); return(Activator.CreateInstance(refType, ids)); } } if (objectType.IsSubClassOfGeneric(typeof(IDictionary <,>))) { var dictionaryType = typeof(Dictionary <,>).MakeGenericType(objectType.GenericTypeArguments); var instance = Activator.CreateInstance(dictionaryType); if (reader.TokenType == JsonToken.StartArray) { var addMethod = dictionaryType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance); while (reader.Read()) { if (reader.TokenType == JsonToken.EndArray) { return(instance); } if (reader.TokenType != JsonToken.StartObject) { Console.WriteLine($"{reader.TokenType} != JsonToken.StartObject"); continue; } if (!reader.Read()) { Console.WriteLine($"Reader terminated w/o finding JsonToken.EndArray"); return(instance); } if (!GetValue("key", objectType.GenericTypeArguments.First(), out object keyValue)) { continue; } if (!GetValue("value", objectType.GenericTypeArguments.Last(), out object valueValue)) { continue; } addMethod.Invoke(instance, new object[] { keyValue, valueValue }); if (reader.TokenType != JsonToken.EndObject) { Console.WriteLine($"{reader.TokenType} != JsonToken.EndObject"); } //if (!reader.Read()) //{ // Console.WriteLine($"Reader terminated w/o finding JsonToken.EndArray (after kvp)."); // return instance; //} bool GetValue(string expectedName, Type type, out object value) { if (reader.TokenType != JsonToken.PropertyName) { value = null; return(false); } var jprop = JProperty.Load(reader); //Console.WriteLine($"Property[{jprop.Name}] = ({type.FullName}) {jprop.Value.Value<string>()}"); var name = jprop.Name; var valueReader = jprop.Value.CreateReader(); value = serializer.Deserialize(valueReader, type); if (expectedName.Equals(name, StringComparison.InvariantCultureIgnoreCase)) { return(true); } Console.WriteLine($"`{expectedName}` != `{name}`."); return(false); } } return(instance); } if (reader.TokenType == JsonToken.StartObject) { if (!reader.Read()) { return(instance); } var addMethod = dictionaryType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance); do { Console.WriteLine($"{reader.Path} = ({reader.TokenType}) {reader.Value}"); if (reader.TokenType == JsonToken.EndObject) { return(instance); } if (reader.TokenType == JsonToken.PropertyName) { var jprop = JProperty.Load(reader); var type = objectType.GenericTypeArguments.Last(); Console.WriteLine($"Property[{jprop.Name}] = ({type.FullName}) {jprop.Value.Value<string>()}"); var name = jprop.Name; var value = serializer.Deserialize(jprop.Value.CreateReader(), type); //var value = GetValue(); //object GetValue() //{ // if (jprop.Value.Type == JTokenType.String) // return jprop.Value.Value<string>(); // if (jprop.Value.Type == JTokenType.Guid) // return jprop.Value.Value<Guid>(); // return jprop.Value.Value<object>(); //} //var value = serializer.Deserialize(reader, type); addMethod.Invoke(instance, new object[] { name, value }); continue; } else { Console.WriteLine($"Using path for {reader.TokenType}: {reader.Path} = {reader.Value}"); addMethod.Invoke(instance, new object[] { reader.Path, reader.Value }); if (!reader.Read()) { return(instance); } } } while (true); } return(instance); } if (objectType == typeof(byte[])) { if (reader.TokenType == JsonToken.String) { var bytesString = reader.Value as string; return(bytesString.FromBase64String()); } } if (objectType == typeof(Type)) { if (reader.TokenType == JsonToken.String) { var bytesString = reader.Value as string; return(bytesString.GetClrType( matched => matched, () => default(Type))); } return(default(Type)); } if (objectType.IsEnum) { if (reader.TokenType == JsonToken.String) { var enumString = reader.Value as string; if (Enum.TryParse(objectType, enumString, out object enumValue)) { return(enumValue); } } } return(existingValue); Guid GetGuid() { if (reader.TokenType == JsonToken.String) { var guidString = reader.Value as string; return(Guid.Parse(guidString)); } if (reader.TokenType == JsonToken.Null) { return(default(Guid)); } throw new Exception(); } Guid?GetGuidMaybe() { if (reader.TokenType == JsonToken.Null) { return(default(Guid?)); } return(GetGuid()); } Guid[] GetGuids() { if (reader.TokenType == JsonToken.Null) { return new Guid[] { } } ; IEnumerable <Guid> Enumerate() { while (reader.TokenType != JsonToken.EndArray) { if (!reader.Read()) { yield break; } var guidStr = reader.ReadAsString(); yield return(Guid.Parse(guidStr)); } } return(Enumerate().ToArray()); } }
public TResult Bind <TResult>(Type objectType, JsonReader reader, IApplication application, Func <object, TResult> onParsed, Func <string, TResult> onDidNotBind, Func <string, TResult> onBindingFailure) { if (objectType.IsSubClassOfGeneric(typeof(IRef <>))) { return(GetGuid( (id) => { var refType = typeof(Ref <>).MakeGenericType(objectType.GenericTypeArguments); var value = Activator.CreateInstance(refType, id); return onParsed(value); }, onDidNotBind, onBindingFailure)); } if (objectType.IsSubClassOfGeneric(typeof(IRefOptional <>))) { return(GetGuidMaybe( id => { if (!id.HasValue) { var emptyValue = RefOptionalHelper.CreateEmpty(objectType.GenericTypeArguments.First()); return onParsed(emptyValue); } var refType = typeof(RefOptional <>).MakeGenericType(objectType.GenericTypeArguments); var value = Activator.CreateInstance(refType, id.Value); return onParsed(value); })); } if (objectType.IsSubClassOfGeneric(typeof(IRefs <>))) { return(GetGuids( ids => { var refType = typeof(Refs <>).MakeGenericType(objectType.GenericTypeArguments); var value = Activator.CreateInstance(refType, ids); return onParsed(value); })); } if (objectType.IsSubClassOfGeneric(typeof(IDictionary <,>))) { var dictionaryKeyType = objectType.GenericTypeArguments[0]; var dictionaryValueType = objectType.GenericTypeArguments[1]; var dictionaryType = typeof(Dictionary <,>).MakeGenericType(objectType.GenericTypeArguments); var instance = Activator.CreateInstance(dictionaryType); if (reader.TokenType != JsonToken.StartObject) { return(onParsed(instance)); } if (!reader.Read()) { return(onParsed(instance)); } var addMethod = dictionaryType.GetMethod("Add", BindingFlags.Public | BindingFlags.Instance); do { if (reader.TokenType == JsonToken.EndObject) { return(onParsed(instance)); } instance = StandardStringBindingsAttribute.BindDirect(dictionaryKeyType, reader.Path, keyValue => { var valueValue = Bind(dictionaryValueType, reader, application, v => v, why => dictionaryValueType.GetDefault(), why => dictionaryValueType.GetDefault()); addMethod.Invoke(instance, new object[] { keyValue, valueValue }); return(instance); }, (why) => instance, (why) => instance); } while (reader.Read()); } if (objectType == typeof(byte[])) { if (reader.TokenType == JsonToken.String) { var bytesString = reader.Value as string; var value = bytesString.FromBase64String(); return(onParsed(value)); } } if (objectType.IsAssignableFrom(typeof(Type))) { if (application is IApiApplication) { var apiApplication = application as IApiApplication; if (reader.TokenType == JsonToken.String) { var stringValue = reader.Value as string; var(success, type) = apiApplication.GetResourceType(stringValue, type => (true, type), () => (false, default(Type))); if (success) { return(onParsed(type)); } } } } if (objectType.IsNullable()) { var underlyingType = objectType.GetNullableUnderlyingType(); if (reader.TokenType == JsonToken.Null) { return(onParsed(objectType.GetDefault())); } return(Bind(underlyingType, reader, application, obj => onParsed(obj.AsNullable()), (why) => onParsed(objectType.GetDefault()), (why) => onParsed(objectType.GetDefault()))); } // As a last ditch effort, see if the JToken deserialization will work. var token = JToken.ReadFrom(reader); return(BindDirect(objectType, token, onParsed, onDidNotBind, onBindingFailure)); TR GetGuid <TR>( Func <Guid, TR> onGot, Func <string, TR> onIgnored, Func <string, TR> onFailed) { if (reader.TokenType == JsonToken.String) { var guidString = reader.Value as string; if (Guid.TryParse(guidString, out Guid guid)) { return(onGot(guid)); } return(onFailed($"Cannot parse `{guidString}` as a Guid.")); } if (reader.TokenType == JsonToken.StartObject) { if (!reader.Read()) { return(onIgnored("Empty object")); } return(GetGuid( guid => { while (reader.TokenType != JsonToken.EndObject) { if (!reader.Read()) { break; } } return onGot(guid); }, onIgnored, onFailed)); } if (reader.TokenType == JsonToken.PropertyName) { var propertyName = reader.Value as string; if (!reader.Read()) { return(onFailed("Property did not have value.")); } if (propertyName.ToLower() == "uuid") { return(GetGuid(onGot, onIgnored, onFailed)); } if (propertyName.ToLower() == "id") { return(GetGuid(onGot, onIgnored, onFailed)); } if (!reader.Read()) { return(onIgnored("'uuid' Property not found.")); } return(GetGuid(onGot, onIgnored, onFailed)); } return(onFailed($"Cannot decode token of type `{reader.TokenType}` to UUID.")); } TResult GetGuidMaybe(Func <Guid?, TResult> callback) { if (reader.TokenType == JsonToken.Null) { return(callback(default(Guid?))); } return(GetGuid( (x) => callback(x), onDidNotBind, onBindingFailure)); } TResult GetGuids(Func <Guid[], TResult> onGot) { if (reader.TokenType == JsonToken.Null) { return(onGot(new Guid[] { })); } if (reader.TokenType == JsonToken.StartArray) { var list = new List <Guid>(); while (reader.Read()) { if (reader.TokenType == JsonToken.EndArray) { break; } var result = GetGuid( g => new { why = string.Empty, g = g.AsOptional(), success = true, }, why => new { why = why, g = default(Guid?), success = true, }, why => new { why = why, g = default(Guid?), success = false, }); if (!result.success) { return(onBindingFailure(result.why)); } if (result.g.HasValue) { list.Add(result.g.Value); } } return(onGot(list.ToArray())); } return(onBindingFailure($"Cannot decode token of type `{reader.TokenType}` to {objectType.FullName}.")); } }
public static TResult BindDirect <TResult>(Type type, JToken content, Func <object, TResult> onParsed, Func <string, TResult> onDidNotBind, Func <string, TResult> onBindingFailure) { if (type.IsAssignableFrom(typeof(Guid))) { if (content.Type == JTokenType.Guid) { var guidValue = content.Value <Guid>(); return(onParsed(guidValue)); } if (content.Type == JTokenType.String) { var stringValue = content.Value <string>(); if (Guid.TryParse(stringValue, out Guid guidValue)) { return(onParsed(guidValue)); } return(onBindingFailure($"Cannot convert `{stringValue}` to Guid.")); } var webId = ReadObject <WebId>(content); if (webId.IsDefaultOrNull()) { return(onBindingFailure("Null value for GUID.")); } var guidValueMaybe = webId.ToGuid(); if (!guidValueMaybe.HasValue) { return(onBindingFailure("Null WebId cannot be converted to a Guid.")); } var webIdGuidValue = guidValueMaybe.Value; return(onParsed(webIdGuidValue)); } if (type.IsSubClassOfGeneric(typeof(IRef <>))) { var activatableType = typeof(Ref <>).MakeGenericType(type.GenericTypeArguments); if (content.Type == JTokenType.Guid) { var guidValue = content.Value <Guid>(); var iref = Activator.CreateInstance(activatableType, guidValue); return(onParsed(iref)); } if (content.Type == JTokenType.String) { return(StandardStringBindingsAttribute.BindDirect(type, content.Value <string>(), onParsed, onDidNotBind, onBindingFailure)); } if (content.Type == JTokenType.Object) { var objectContent = (content as JObject); if (objectContent.TryGetValue("uuid", StringComparison.OrdinalIgnoreCase, out JToken idContentUuid)) { return(BindDirect(type, idContentUuid, onParsed, onDidNotBind, onBindingFailure)); } if (objectContent.TryGetValue("id", StringComparison.OrdinalIgnoreCase, out JToken idContentId)) { return(BindDirect(type, idContentId, onParsed, onDidNotBind, onBindingFailure)); } var guidStr = objectContent.ToString(); return(StandardStringBindingsAttribute.BindDirect(type, guidStr, onParsed, onDidNotBind, onBindingFailure)); } if (content.Type == JTokenType.Null) { return(onBindingFailure("Value was null.")); } } if (type.IsSubClassOfGeneric(typeof(IRefOptional <>))) { if (content.Type == JTokenType.Guid) { var guidValue = content.Value <Guid>(); var activatableType = typeof(IRefOptional <>).MakeGenericType(type.GenericTypeArguments); var iref = Activator.CreateInstance(activatableType, guidValue); return(onParsed(iref)); } if (content.Type == JTokenType.Object) { var objectContent = (content as JObject); if (objectContent.TryGetValue("uuid", StringComparison.OrdinalIgnoreCase, out JToken idContent)) { return(BindDirect(type, idContent, onParsed, onDidNotBind, onBindingFailure)); } var guidStr = objectContent.ToString(); return(StandardStringBindingsAttribute.BindDirect(type, guidStr, onParsed, onDidNotBind, onBindingFailure)); } if (content.Type == JTokenType.Null) { var irefOptional = RefOptionalHelper.CreateEmpty(type.GenericTypeArguments.First()); return(onParsed(irefOptional)); } // Standard string binding fallback at end of function will work for this case // if (content.Type == JTokenType.String) } if (type.IsSubClassOfGeneric(typeof(IRefs <>))) { var activatableType = typeof(Refs <>).MakeGenericType(type.GenericTypeArguments); if (content.Type == JTokenType.Guid) { var guidValue = content.Value <Guid>(); var guids = guidValue.AsArray(); var irefs = Activator.CreateInstance(activatableType, guids); return(onParsed(irefs)); } if (content.Type == JTokenType.String) { return(StandardStringBindingsAttribute.BindDirect(type, content.Value <string>(), onParsed, onDidNotBind, onBindingFailure)); } if (content.Type == JTokenType.Array) { var guids = ReadArray(content) .Select( token => BindDirect(typeof(Guid), token, guid => (Guid?)((Guid)guid), (why) => default(Guid?), (why) => default(Guid?))) .SelectWhereHasValue() .ToArray(); var irefs = Activator.CreateInstance(activatableType, guids); return(onParsed(irefs)); } } if (type == typeof(int)) { if (content.Type == JTokenType.Float) { var floatValue = content.Value <double>(); var intValue = (int)floatValue; return(onParsed(intValue)); } if (content.Type == JTokenType.Integer) { var intValue = content.Value <int>(); return(onParsed(intValue)); } if (content.Type == JTokenType.String) { var stringValue = content.Value <string>(); return(StandardStringBindingsAttribute.BindDirect(type, stringValue, onParsed, onDidNotBind, onBindingFailure)); } return(onDidNotBind($"Cannot convert `{content.Type}` to {typeof(int).FullName}")); } if (type == typeof(double)) { if (content.Type == JTokenType.Float) { var floatValue = content.Value <double>(); return(onParsed(floatValue)); } if (content.Type == JTokenType.Integer) { var intValue = content.Value <int>(); var floatValue = (double)intValue; return(onParsed(floatValue)); } if (content.Type == JTokenType.String) { var stringValue = content.Value <string>(); return(StandardStringBindingsAttribute.BindDirect(type, stringValue, onParsed, onDidNotBind, onBindingFailure)); } return(onDidNotBind($"Cannot convert `{content.Type}` to {typeof(double).FullName}")); } if (type == typeof(decimal)) { if (content.Type == JTokenType.Float) { var floatValue = content.Value <double>(); var decimalValule = (decimal)floatValue; return(onParsed(decimalValule)); } if (content.Type == JTokenType.Integer) { var intValue = content.Value <int>(); var floatValue = (decimal)intValue; return(onParsed(floatValue)); } if (content.Type == JTokenType.String) { var stringValue = content.Value <string>(); return(StandardStringBindingsAttribute.BindDirect(type, stringValue, onParsed, onDidNotBind, onBindingFailure)); } return(onDidNotBind($"Cannot convert `{content.Type}` to {typeof(decimal).FullName}")); } if (type == typeof(DateTime)) { if (content.Type == JTokenType.Date) { var dateValue = content.Value <DateTime>(); return(onParsed(dateValue)); } if (content.Type == JTokenType.Integer) { var intValue = content.Value <long>(); var dateValue = new DateTime(intValue); return(onParsed(dateValue)); } if (content.Type == JTokenType.String) { var stringValue = content.Value <string>(); return(StandardStringBindingsAttribute.BindDirect(type, stringValue, onParsed, onDidNotBind, onBindingFailure)); } return(onDidNotBind($"Cannot convert `{content.Type}` to {typeof(DateTime).FullName}")); } if (type == typeof(bool)) { if (content.Type == JTokenType.Boolean) { var boolValue = content.Value <bool>(); return(onParsed(boolValue)); } if (content.Type == JTokenType.Integer) { var intValue = content.Value <int>(); var boolValue = intValue != 0; return(onParsed(boolValue)); } if (content.Type == JTokenType.String) { var stringValue = content.Value <string>(); return(StandardStringBindingsAttribute.BindDirect(type, stringValue, onParsed, onDidNotBind, onBindingFailure)); } return(onDidNotBind($"Cannot convert `{content.Type}` to {typeof(bool).FullName}")); } if (type == typeof(Func <Task <byte[]> >)) { if (content.Type == JTokenType.Bytes) { var bytes = content.Value <byte[]>(); Func <Task <byte[]> > callback = () => bytes.AsTask(); return(onParsed(callback)); } if (content.Type == JTokenType.String) { var stringValue = content.Value <string>(); if (stringValue.TryParseBase64String(out byte[] bytes)) { Func <Task <byte[]> > callback = () => bytes.AsTask(); return(onParsed(callback)); } if (Uri.TryCreate(stringValue, UriKind.Absolute, out Uri url)) { Func <Task <byte[]> > callback = async() => { using (var client = new HttpClient()) { using (var response = await client.GetAsync(url)) { var bytes = await response.Content.ReadAsByteArrayAsync(); return(bytes); } } }; return(onParsed(callback)); } return(GetHttpContentFromBase64(stringValue, context => { Func <Task <byte[]> > callback = context.ReadAsByteArrayAsync; return onParsed(callback); }, (prefix) => onBindingFailure($"Not a valid base64 string or a valid URL."))); } } if (type == typeof(HttpContent) || type.IsSubclassOf(typeof(HttpContent))) { if (content.Type == JTokenType.String) { var contentEncodedBase64String = content.Value <string>(); return(contentEncodedBase64String.MatchRegexInvoke( "data:(?<contentType>[^;]+);base64,(?<base64Data>.+)", (contentType, base64Data) => base64Data.PairWithValue(contentType), types => types.First( (ct, next) => { var base64EncodedData = ct.Key; var data = base64EncodedData.FromBase64String(); var contentType = ct.Value; var httpContent = new ByteArrayContent(data); httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType); return onParsed(httpContent); }, () => onBindingFailure( $"Could not decode JSON Binary prefix:{contentEncodedBase64String.Substring(0, 25)}")))); } return(onDidNotBind($"Cannot convert `{content.Type}` to {typeof(HttpContent).FullName}")); } if (type == typeof(Func <Task <HttpContent> >)) { if (content.Type == JTokenType.String) { var stringValue = content.Value <string>(); return(GetHttpContentFromBase64(stringValue, (content) => { Func <Task <HttpContent> > func = () => content.AsTask(); return onParsed(content); }, (prefix) => { if (Uri.TryCreate(stringValue, UriKind.Absolute, out Uri url)) { Func <Task <HttpContent> > callback = async() => { using (var client = new HttpClient()) { using (var response = await client.GetAsync(url)) { // Resource disposal creates issues so a copy is needed var data = await response.Content.ReadAsByteArrayAsync(); var httpContent = new ByteArrayContent(data); foreach (var header in response.Content.Headers) { httpContent.Headers.Add(header.Key, header.Value); } return httpContent; } } }; return onParsed(callback); } return onBindingFailure($"Not a valid base64 string or a valid URL."); })); } return(onDidNotBind($"Cannot convert `{content.Type}` to {typeof(Func<Task<HttpContent>>).FullName}")); } TResult GetHttpContentFromBase64(string contentEncodedBase64String, Func <HttpContent, TResult> onSuccess, Func <string, TResult> onFailure) { return(contentEncodedBase64String.MatchRegexInvoke( "data:(?<contentType>[^;]+);base64,(?<base64Data>.+)", (contentType, base64Data) => base64Data.PairWithValue(contentType), types => types.First( (ct, next) => { var base64EncodedData = ct.Key; var data = base64EncodedData.FromBase64String(); var contentType = ct.Value; var httpContent = new ByteArrayContent(data); httpContent.Headers.ContentType = new MediaTypeHeaderValue(contentType); return onSuccess(httpContent); }, () => onFailure(contentEncodedBase64String.Substring(0, 25))))); } if (type.IsNullable()) { var nullableT = type.GetNullableUnderlyingType(); return(BindDirect(nullableT, content, (v) => { var nullableV = v.AsNullable(); return onParsed(nullableV); }, (why) => onParsed(type.GetDefault()), (why) => onParsed(type.GetDefault()))); } if (type.IsAssignableFrom(typeof(IDictionary <,>))) { var keyType = type.GenericTypeArguments[0]; var valueType = type.GenericTypeArguments[1]; var refType = typeof(Dictionary <,>).MakeGenericType(type.GenericTypeArguments); var refInstance = Activator.CreateInstance(refType); var addMethod = refType.GetMethod("Add"); //Dictionary<string, int> dict; //dict.Add() foreach (var kvpToken in ReadDictionary(content)) { var keyToken = kvpToken.Key; var valueToken = kvpToken.Value; string result = StandardStringBindingsAttribute.BindDirect(keyType, keyToken, keyValue => { return(BindDirect(valueType, valueToken, valueValue => { addMethod.Invoke(refInstance, new object[] { keyValue, valueValue }); return string.Empty; }, (why) => why, (why) => why)); }, (why) => why, (why) => why); } return(onParsed(refInstance)); } if (type == typeof(object)) { var objectValue = ReadObject(content); return(onParsed(objectValue)); } if (content is JObject) { var jObj = content as JObject; var jsonText = jObj.ToString(); var value = JsonConvert.DeserializeObject(jsonText, type); return(onParsed(value)); } if (content.Type == JTokenType.String) { return(StandardStringBindingsAttribute.BindDirect(type, content.Value <string>(), onParsed, onDidNotBind, onBindingFailure)); } //if (content.Type == JTokenType.Object || content.Type == JTokenType.Array) //{ // try // { // var value = Newtonsoft.Json.JsonConvert.DeserializeObject( // content.ToString(), type, bindConvert); // return onParsed(value); // } // catch (Newtonsoft.Json.JsonSerializationException) // { // throw; // } //} if (content.Type == JTokenType.Null) { // PropertyAttribute will not recognize null values as specified w/o this. if (type.IsAssignableFrom(typeof(string))) { return(onParsed((string)null)); } //var defaultValue = type.GetDefault(); //return onParsed(defaultValue); } return(onDidNotBind($"Could not find binding for type {type.FullName}")); }
public static TResult BindDirect <TResult>(Type type, string content, Func <object, TResult> onParsed, Func <string, TResult> onDidNotBind, Func <string, TResult> onBindingFailure) { if (type == typeof(string)) { var stringValue = content; return(onParsed((object)stringValue)); } if (type == typeof(Guid)) { if (Guid.TryParse(content, out Guid stringGuidValue)) { return(onParsed(stringGuidValue)); } return(onBindingFailure($"Failed to convert `{content}` to type `{typeof(Guid).FullName}`.")); } if (type == typeof(Guid[])) { if (content.IsNullOrWhiteSpace()) { return(onParsed(new Guid[] { })); } if (content.StartsWith('[')) { content = content .TrimStart('[') .TrimEnd(']'); } var tokens = content.Split(','.AsArray()); var guids = tokens .Select( token => BindDirect(typeof(Guid), token, guid => guid, (why) => default(Guid?), (why) => default(Guid?))) .Cast <Guid?>() .Where(v => v.HasValue) .Select(v => v.Value) .ToArray(); return(onParsed(guids)); } if (type == typeof(DateTime)) { return(ParseDate(content, (currentDateString) => onDidNotBind( $"Failed to convert {content} to `{typeof(DateTime).FullName}`."))); TResult ParseDate(string dateString, Func <string, TResult> onParseFailed) { if (dateString.IsNullOrWhiteSpace()) { return(onParseFailed(dateString)); } if (DateTime.TryParse(dateString, out DateTime dateValue)) { return(onParsed(dateValue)); } // Common format not supported by TryParse if (DateTime.TryParseExact(dateString, "ddd MMM d yyyy HH:mm:ss 'GMT'K", null, System.Globalization.DateTimeStyles.AllowWhiteSpaces, out dateValue)) { return(onParsed(dateValue)); } var startOfDescText = dateString.IndexOf('('); if (startOfDescText > 0) { var cleanerText = content.Substring(0, startOfDescText); return(ParseDate(cleanerText, failedText => { var decodedContent = System.Net.WebUtility.UrlDecode(failedText); if (decodedContent != failedText) { return ParseDate(decodedContent, (failedDecodedText) => onParseFailed(failedDecodedText)); } return onParseFailed(failedText); })); } var decodedContent = System.Net.WebUtility.UrlDecode(dateString); if (decodedContent != dateString) { return(ParseDate(decodedContent, (failedDecodedText) => onParseFailed(failedDecodedText))); } return(onParseFailed(dateString)); } } if (type == typeof(DateTimeOffset)) { if (DateTimeOffset.TryParse(content, out DateTimeOffset dateValue)) { return(onParsed(dateValue)); } return(onDidNotBind($"Failed to convert {content} to `{typeof(DateTimeOffset).FullName}`.")); } if (type == typeof(int)) { if (int.TryParse(content, out int intValue)) { return(onParsed(intValue)); } return(onBindingFailure($"Failed to convert {content} to `{typeof(int).FullName}`.")); } if (type == typeof(double)) { if (double.TryParse(content, out double doubleValue)) { return(onParsed(doubleValue)); } return(onBindingFailure($"Failed to convert {content} to `{typeof(double).FullName}`.")); } if (type == typeof(decimal)) { if (decimal.TryParse(content, out decimal decimalValue)) { return(onParsed(decimalValue)); } return(onBindingFailure($"Failed to convert {content} to `{typeof(decimal).FullName}`.")); } if (type == typeof(bool)) { if (content.IsDefaultNullOrEmpty()) { return(onDidNotBind("Value not provided.")); } if ("t" == content.ToLower()) { return(onParsed(true)); } if ("on" == content.ToLower()) // used in check boxes { return(onParsed(true)); } if ("f" == content) { return(onParsed(false)); } if ("off" == content.ToLower()) // used in some check boxes { return(onParsed(false)); } // TryParse may convert "on" to false TODO: Test theory if (bool.TryParse(content, out bool boolValue)) { return(onParsed(boolValue)); } return(onDidNotBind($"Failed to convert {content} to `{typeof(bool).FullName}`.")); } if (type == typeof(Uri)) { if (content.IsDefaultNullOrEmpty()) { return(onBindingFailure("URL value was empty")); } if (Uri.TryCreate(content.Trim('"'.AsArray()), UriKind.RelativeOrAbsolute, out Uri uriValue)) { return(onParsed(uriValue)); } return(onBindingFailure($"Failed to convert {content} to `{typeof(Uri).FullName}`.")); } if (type == typeof(Type)) { return(content.GetClrType( typeInstance => onParsed(typeInstance), () => onDidNotBind( $"`{content}` is not a recognizable resource type or CLR type."))); //() => HttpApplication.GetResourceType(content, // (typeInstance) => onParsed(typeInstance), // () => content.GetClrType( // typeInstance => onParsed(typeInstance), // () => onDidNotBind( // $"`{content}` is not a recognizable resource type or CLR type.")))); } if (type == typeof(Stream)) { return(BindDirect(typeof(byte[]), content, byteArrayValueObj => { var byteArrayValue = (byte[])byteArrayValueObj; return onParsed(new MemoryStream(byteArrayValue)); }, onDidNotBind, onBindingFailure)); } if (type == typeof(byte[])) { if (content.TryParseBase64String(out byte[] byteArrayValue)) { return(onParsed(byteArrayValue)); } return(onDidNotBind($"Failed to convert {content} to `{typeof(byte[]).FullName}` as base64 string.")); } if (type == typeof(WebId)) { if (!Guid.TryParse(content, out Guid guidValue)) { return(onBindingFailure($"Could not convert `{content}` to GUID")); } var webIdObj = (object)new WebId() { UUID = guidValue }; return(onParsed(webIdObj)); } if (type == typeof(Controllers.DateTimeEmpty)) { if (String.Compare(content.ToLower(), "false") == 0) { return(onParsed(new Controllers.DateTimeEmpty())); } return(onBindingFailure($"Failed to convert {content} to `{typeof(Controllers.DateTimeEmpty).FullName}`.")); } if (type == typeof(Controllers.DateTimeQuery)) { if (DateTime.TryParse(content, out DateTime startEnd)) { return(onParsed(new Controllers.DateTimeQuery(startEnd, startEnd))); } return(onBindingFailure($"Failed to convert {content} to `{typeof(Controllers.DateTimeQuery).FullName}`.")); } if (type == typeof(object)) { var objValue = content; return(onParsed(objValue)); } if (type.IsSubClassOfGeneric(typeof(IRef <>))) { return(BindDirect(typeof(Guid), content, (id) => { var resourceType = type.GenericTypeArguments.First(); var instantiatableType = typeof(EastFive.Ref <>).MakeGenericType(resourceType); var instance = Activator.CreateInstance(instantiatableType, new object[] { id }); return onParsed(instance); }, onDidNotBind, (why) => onBindingFailure(why))); } if (type.IsSubClassOfGeneric(typeof(IRefOptional <>))) { var referredType = type.GenericTypeArguments.First(); TResult emptyOptional() { var refInst = RefOptionalHelper.CreateEmpty(referredType); return(onParsed(refInst)); }; if (content.IsNullOrWhiteSpace()) { return(emptyOptional()); } if (content.ToLower() == "empty") { return(emptyOptional()); } if (content.ToLower() == "null") { return(emptyOptional()); } var refType = typeof(IRef <>).MakeGenericType(referredType); return(BindDirect(refType, content, (v) => { var refOptionalType = typeof(RefOptional <>).MakeGenericType(referredType); var refInst = Activator.CreateInstance(refOptionalType, new object[] { v }); return onParsed(refInst); }, (why) => emptyOptional(), (why) => emptyOptional())); } if (type.IsSubClassOfGeneric(typeof(IRefs <>))) { return(BindDirect(typeof(Guid[]), content, (ids) => { var resourceType = type.GenericTypeArguments.First(); var instantiatableType = typeof(Refs <>).MakeGenericType(resourceType); var instance = Activator.CreateInstance(instantiatableType, new object[] { ids }); return onParsed(instance); }, onDidNotBind, (why) => onBindingFailure(why))); } if (type.IsSubClassOfGeneric(typeof(Nullable <>))) { var underlyingType = type.GetNullableUnderlyingType(); return(BindDirect(underlyingType, content, (nonNullable) => { var nullable = nonNullable.AsNullable(); return onParsed(nullable); }, (why) => onParsed(type.GetDefault()), (why) => onParsed(type.GetDefault()))); } if (type.IsEnum) { if (Enum.TryParse(type, content, out object value)) { return(onParsed(value)); } var validValues = Enum.GetNames(type).Join(", "); return(onDidNotBind($"Value `{content}` is not a valid value for `{type.FullName}.` Valid values are [{validValues}].")); } if (type.IsArray) { return(content.MatchRegexInvoke( @"(\[(?<index>[0-9]+)\]=)?(?<value>([^\;]|(?<=\\)\;)+)", (index, value) => index.PairWithValue(value), onMatched: tpls => { // either abc;def // or [0]=abc;[1]=def var matchesDictionary = tpls.Any(kvp => string.IsNullOrEmpty(kvp.Key)) ? tpls .Select( (kvp, index) => kvp.Value.PairWithKey(index)) .ToDictionary() : tpls .TryWhere( (KeyValuePair <string, string> kvp, out int indexedValue) => int.TryParse(kvp.Key, out indexedValue)) .Select( match => match.item.Value.PairWithKey(match.@out)) .ToDictionary(); // matchesDictionary.Keys will throw if empty var ordered = matchesDictionary.IsDefaultNullOrEmpty()? new (bool, string)[] { }