What am I doing wrong with JSON.NET's JsonConvert - c#

json string
{
"success": true,
"challenge_ts": "2016-11-03T17:30:00Z",
"hostname": "mydomain.com"
}
class
internal class reCaptchaResponse
{
internal bool success { get; set; }
internal DateTime challenge_ts { get; set; } // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
internal string hostname { get; set; } // the hostname of the site where the reCAPTCHA was solved
internal string[] error_codes { get; set; } // optional
}
attempt to serialize
reCaptchaResponse responseObject = Newtonsoft.Json.JsonConvert.DeserializeObject<reCaptchaResponse>(jsonResult);
attempt fails like...
Newtonsoft.Json.JsonConvert.SerializeObject(responseObject) returns
{}

Json.Net, by default, only serializes/deserialzes public fileds and properties, but you can also do it without changing access modifiers from internal to public.
Just use JsonProperty attribute
internal class reCaptchaResponse
{
[JsonProperty]
internal bool success { get; set; }
[JsonProperty]
internal DateTime challenge_ts { get; set; } // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
[JsonProperty]
internal string hostname { get; set; } // the hostname of the site where the reCAPTCHA was solved
[JsonProperty]
internal string[] error_codes { get; set; } // optional
}
(Without modifing the original class) You can even use ContractResolver to select which properties/fields should be used in serialization process
EDIT
Although this answer has already been accepted, I want to post a code where the original assembly can not be modified.
var settings = new JsonSerializerSettings() {
ContractResolver = new AllPropertiesContractResolver()
};
reCaptchaResponse responseObject =
JsonConvert.DeserializeObject<reCaptchaResponse>(jsonResult ,settings);
public class AllPropertiesContractResolver : DefaultContractResolver
{
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
var props = type.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
.Select(x => new Newtonsoft.Json.Serialization.JsonProperty()
{
PropertyName = x.Name,
PropertyType = x.PropertyType,
Readable = true,
ValueProvider = new AllPropertiesValueProvider(x),
Writable = true
})
.ToList();
return props;
}
}
public class AllPropertiesValueProvider : Newtonsoft.Json.Serialization.IValueProvider
{
PropertyInfo _propertyInfo;
public AllPropertiesValueProvider(PropertyInfo p)
{
_propertyInfo = p;
}
public object GetValue(object target)
{
return _propertyInfo.GetValue(target); //Serialization
}
public void SetValue(object target, object value)
{
_propertyInfo.SetValue(target, value, null); //Deserialization
}
}

Change the properties to public. By default it does not deserialize non-public properties
internal class reCaptchaResponse
{
public bool success { get; set; }
public DateTime challenge_ts { get; set; } // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
public string hostname { get; set; } // the hostname of the site where the reCAPTCHA was solved
public string[] error_codes { get; set; } // optional
}

the members must be public
internal class reCaptchaResponse
{
public bool success { get; set; }
public DateTime challenge_ts { get; set; } // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ)
public string hostname { get; set; } // the hostname of the site where the reCAPTCHA was solved
public string[] error_codes { get; set; } // optional
}

You can try to change modificator from internal to public

Related

How to provide the Default value to a boolean property when it was null

In the below code i am getting an exception because "isValid" is coming as null from the input request.
I want to set "isValid" to "False" when it was null from the input request.
Can anyone pls suggest me how i can do this ?
public class Details
{
public string status { get; set; }
public MessageInfo messageInfo { get; set; }
}
public class MessageInfo
{
public bool isValid { get; set; }
}
var inputMessage =
{
"Body":
{
"status":"success",
"MessageInfo":
{
"isValid":null
}
}
}
var messagebody = inputMessage.Body.ToObject<Details>();
this works for me
void Main()
{
var inputMessage = "{ \"Body\":{\"status\":\"success\", \"MessageInfo\":{\"isValid\":null} }}";
var inputMessageObj= JsonConvert.DeserializeObject<Root>(inputMessage);
}
classes
public class Details
{
public string status { get; set; }
public MessageInfo messageInfo { get; set; }
}
public class MessageInfo
{
private bool? _isValid = false;
public bool? IsValid
{
get { return _isValid; }
set { _isValid = value == null ? false : value; }
}
}
public class Body
{
public string Status { get; set; }
public MessageInfo MessageInfo { get; set; }
}
public class Root
{
public Body Body { get; set; }
}
Assuming you are using Newtonsoft.Json, use the NullValueHandling property of the JsonSerializer class, setting it to ignore. Then pass in this instance of JsonSerializer to an overload of the ToObject<T> function.
This tells serialization to ignore any properties that were null, leaving the property initialized to its default value. (You can control that default value separately via System.ComponentModel.DefaultValueAttribute if you want.)
Fully compiling example below. (The references to 'Body' were removed, to make it easier to focus on the main problem.)
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace SomeNamespace
{
public class Program
{
private static void Main()
{
var inputMessage = JToken.Parse(
#"{
""status"":""success"",
""MessageInfo"":
{
""isValid"":null
}
}");
// build a custom serializer with a setting to ignore null
var jsonSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
};
var serializer = JsonSerializer.Create(jsonSettings);
// using the serializer with custom settings avoids the original exception
var messagebody = inputMessage.ToObject<Details>(serializer);
}
}
public class Details
{
public string status { get; set; }
public MessageInfo messageInfo { get; set; }
}
public class MessageInfo
{
public bool isValid { get; set; }
}
}

Consume Data From this endpoint

I am getting tdata from a certain endpoint and the problem id on serialization to my classes. I want to cast the bellow data to my class but cant get how the class should be structured. Check out the data .....
{
"-LYG_AI_oGYjNBrzMlKF": {
"chatDispayText": "",
"chatId": "-LYG_AI_oGYjNBrzMlKF",
"chatName": "",
"chattype": "single",
"imageUrl": "https://wallpaper.wiki/wp-content/uploads/2017/04/wallpaper.wiki-Amazing-celebrities-hd-wallpaper-PIC-WPD004734.jpg",
"lastMessageSent": "aiye",
"lastMessageSentTime": 1549704416263,
"synched": false,
"users": {
"-LYG_AIZ5MvTbjR7DACe": "Uicpm3L15TX0c15pKCI6KUEARyB3",
"-LYG_AI_oGYjNBrzMlKE": "Xsr0z9lsqNOEytX61lJvaGz1A8F2"
}
}
}
If the data you get out the endpoint has a dynamic structure, you can make use of a key-vale pair collection or a dictionary. For instance:
JObject jObject = JObject.Parse(Data); // This would already give you a key-value pair collection
Dictionary<String,Object> collection = new Dictionary<String, Object>();
foreach(var obj in jObject){
collection.Add(obj.Key, obj.Value);
}
However, this isn't a strongly typed approach which means that it is not effective in the majority of scenarios. A better solution when dealing with endpoints would be to define a class with fixed schema, actually something you need in your code, and then map the class to the object yielded by the endpoint using a metadata struct. For example:
public class ChatInfoModel
{
[JsonProperty(Metadata.ChatId)]
public long ChatId { get; set; }
[JsonProperty(Metadata.ChatId, Required = Required.AllowNull)]
public String Message { get; set; }
}
public struct Metadata
{
public const String ChatId = "userChatId";
public const String Message = "messageTxt";
}
And then
var deserializedObject = JsonConvert.DeserializeObject<ChatInfoModel>(data);
However, if your class has the exact same naming convention (but should not necessarily follow the camelCase naming convention) for its properties as in the serialized data, the JsonProperty attribute would not be needed.
You can also deserialize the object without using JsonProperty attribute manually using the first approach, and it is actually advantageous in certain scenarios where your schema comes from a configuration file rather than a struct.
Take inspiration from the Structure below:
public class Rootobject
{
public LYG_AI_Ogyjnbrzmlkf LYG_AI_oGYjNBrzMlKF { get; set; }
}
public class LYG_AI_Ogyjnbrzmlkf
{
public string chatDispayText { get; set; }
public string chatId { get; set; }
public string chatName { get; set; }
public string chattype { get; set; }
public string imageUrl { get; set; }
public string lastMessageSent { get; set; }
public long lastMessageSentTime { get; set; }
public bool synched { get; set; }
public Users users { get; set; }
}
public class Users
{
public string LYG_AIZ5MvTbjR7DACe { get; set; }
public string LYG_AI_oGYjNBrzMlKE { get; set; }
}

How can I programmatically get the title of Microsoft knowledge base article by KB number?

I'm trying to develop a C# program that would get a list of available Windows Updates and look up KB articles to retrieve titles of each update. (Otherwise, they all look like cryptic "Update for Windows Server (KBxxxxx)")
I tried retrieving the HTML of each KB article but the title is not present in the HTML (I'm guessing they're using angular to build the page)
Here's an example: https://support.microsoft.com/en-us/kb/3102429
The title of the article as shown in the browser does not appear anywhere in the HTML when I view source
Is there a good way to do this?
For hotfixes released after August 2017, the new API link appears to be https://support.microsoft.com/app/content/api/content/help/en-us/4034733.
For hotfixes released after February 2017, the new API link appears to be https://support.microsoft.com/api/content/help/3115489.
The data on that page is JSON:
If you load that JSON data using Python, e.g., then you can find the title and other useful information under "details". In particular,
d["details"]["id"] == u'3115489'
d["details"]["title"] == u'February 7, 2017, update for Office 2013 (KB3115489)'
d["details"]["publishedOn"] == u'2017-02-07T17:05:19.000368Z'
Just for reference, when loading the URL https://support.microsoft.com/kb/3115489 in Chrome with Developer Tools running, the network activity shows an XHR transfer from api/content/help:
I discovered that they are now putting some prefetch script into the initial payload that contains some useful json. (Actually : this is the json mentioned by b.mcewan in the currently accepted answer).
Since I have this all ready for consumption.... Here is a link to some code that will gather your machine's installed hotfixes and present some detail including the KB title.
Code will run in LINQPad
http://share.linqpad.net/l6tdxc.linq
In case you do not use LP here are the routines. ParseTitle makes use of some autogenerated classes to deserialize the json. You will need to remove the .Dump() extension method calls and Hyperlinq class reference and present the data some other way. (EDIT: more than just the KB article Title is exposed by the ArticleInfo class.... like the details about what the hotfix does, how to get it and install it etc.)
void Main()
{
const string query = "SELECT HotFixID, InstalledOn, InstalledBy, Description, Caption, * FROM Win32_QuickFixEngineering";
var result =
(from ManagementObject quickfix in new ManagementObjectSearcher(query).Get() //.AsParallel()
orderby Convert.ToDateTime(quickfix["InstalledOn"]) descending
let web = new WebClient()
let input = quickfix["Caption"].ToString()
let id = input.Substring(35, input.Length - 35)
let url = $"{input.Replace("microsoft.com/?kbid=", "microsoft.com/en-us/help/")}/kb{id}"
let html = web.DownloadString(url)
where string.IsNullOrEmpty( html ).Equals(false)
let kbInfo = ParseInfo( url, html )
where kbInfo != null
let pub = kbInfo.Details.PublishedOn
let title = kbInfo.Details.Title
let desc = Util.OnDemand( "More....", () =>
Util.RawHtml(string.Join(Environment.NewLine,
kbInfo.Details.Body
.Select(i => $"<span class=typeglyphx>{i.Title}</span>{i.Content.Single()}")))
)
select
new
{
HotFixID = Util.RawHtml($"<span class=typeglyphx>{quickfix["HotFixID"].ToString()}</span>"),
Published = pub.Date,
InstalledOn = quickfix["InstalledOn"].ToString(),
InstallDelay = $"{Convert.ToInt16((Convert.ToDateTime(quickfix["InstalledOn"].ToString()).Date - pub.Date).TotalDays)} days",
InstalledBy = quickfix["InstalledBy"].ToString(),
Description = new Hyperlinq(quickfix["Description"].ToString()),
Title = Util.RawHtml($"<span class=typeglyphx>{title}</span>") ?? $"{url} [Could not obtain KB title]",
Body = desc,
Link = new Hyperlinq(url),
}
).Dump(1);
}
#nullable enable
string? ParseTitle ( string html )
{
var doc = new HtmlDocument();
doc.LoadHtml(html);
var meta = doc.DocumentNode
.SelectNodes("//script");
var searchToken = "microsoft.support.prefetchedArticle = (function() ";
var nuggets = meta
.Where(i => i.OuterHtml.Contains(searchToken))
.Select(i => i.OuterHtml)
.Single();
var start = nuggets.IndexOf(":") + 1;
var length = nuggets.Length - start - 28;
var json = nuggets.Substring(start, length);
string? ret = null;
try
{
var articleInfo = MSKBPreFetched.ArticleInfo.FromJson(json);
ret = articleInfo.Details.Title;
}
catch{ json.DumpTrace("could not deserialize the json for this article"); // LP only}
return ret;
}
#nullable disable
// <auto-generated />
// json2csharp
// To parse this JSON data, add NuGet 'Newtonsoft.Json' then do:
//
// using MSKBPreFetched;
//
// var articleInfo = ArticleInfo.FromJson(jsonString);
namespace MSKBPreFetched
{
using System;
using System.Collections.Generic;
using System.Globalization;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public partial class ArticleInfo
{
[JsonProperty("sideNav")]
//[JsonConverter(typeof(ParseStringConverter))]
public string SideNav { get; set; }
[JsonProperty("details")]
public Details Details { get; set; }
[JsonProperty("_ts")]
public long Ts { get; set; }
}
public partial class Details
{
[JsonProperty("subType")]
public string SubType { get; set; }
[JsonProperty("heading")]
public string Heading { get; set; }
[JsonProperty("description")]
public string Description { get; set; }
[JsonProperty("body")]
public List<Body> Body { get; set; }
[JsonProperty("urltitle")]
public string Urltitle { get; set; }
[JsonProperty("keywords")]
public List<string> Keywords { get; set; }
[JsonProperty("keywordsLower")]
public List<string> KeywordsLower { get; set; }
[JsonProperty("os")]
public List<object> Os { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("id")]
[JsonConverter(typeof(ParseStringConverter))]
public long Id { get; set; }
[JsonProperty("locale")]
public string Locale { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("titleLower")]
public string TitleLower { get; set; }
[JsonProperty("published")]
public bool Published { get; set; }
[JsonProperty("createdOn")]
public DateTimeOffset CreatedOn { get; set; }
[JsonProperty("publishedOn")]
public DateTimeOffset PublishedOn { get; set; }
[JsonProperty("version")]
public long Version { get; set; }
[JsonProperty("eolProject")]
public string EolProject { get; set; }
[JsonProperty("supportAreaPaths")]
public List<Guid> SupportAreaPaths { get; set; }
[JsonProperty("supportAreaPathNodes")]
public List<PrimarySupportAreaPath> SupportAreaPathNodes { get; set; }
[JsonProperty("disableVAPopup")]
public bool DisableVaPopup { get; set; }
[JsonProperty("primarySupportAreaPath")]
public List<PrimarySupportAreaPath> PrimarySupportAreaPath { get; set; }
[JsonProperty("isContentLocaleFallback")]
public bool IsContentLocaleFallback { get; set; }
[JsonProperty("contentLocale")]
public string ContentLocale { get; set; }
}
public partial class Body
{
[JsonProperty("meta")]
public Meta Meta { get; set; }
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("content")]
public List<string> Content { get; set; }
}
public partial class Meta
{
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("products")]
public List<object> Products { get; set; }
[JsonProperty("supportAreaPaths")]
public List<object> SupportAreaPaths { get; set; }
[JsonProperty("isInternalContent")]
public bool IsInternalContent { get; set; }
[JsonProperty("id")]
public string Id { get; set; }
}
public partial class PrimarySupportAreaPath
{
[JsonProperty("id")]
public Guid Id { get; set; }
[JsonProperty("parent", NullValueHandling = NullValueHandling.Ignore)]
public Guid? Parent { get; set; }
[JsonProperty("name")]
public string Name { get; set; }
[JsonProperty("type")]
public string Type { get; set; }
[JsonProperty("tree")]
public List<object> Tree { get; set; }
}
public partial class ArticleInfo
{
public static ArticleInfo FromJson(string json) => JsonConvert.DeserializeObject<ArticleInfo>(json, MSKBPreFetched.Converter.Settings);
}
public static class Serialize
{
public static string ToJson(this ArticleInfo self) => JsonConvert.SerializeObject(self, MSKBPreFetched.Converter.Settings);
}
internal static class Converter
{
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
DateParseHandling = DateParseHandling.None,
Converters =
{
new IsoDateTimeConverter { DateTimeStyles = DateTimeStyles.AssumeUniversal }
},
};
}
internal class ParseStringConverter : JsonConverter
{
public override bool CanConvert(Type t) => t == typeof(long) || t == typeof(long?);
public override object ReadJson(JsonReader reader, Type t, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var value = serializer.Deserialize<string>(reader);
long l;
if (Int64.TryParse(value, out l))
{
return l;
}
throw new Exception("Cannot unmarshal type long");
}
public override void WriteJson(JsonWriter writer, object untypedValue, JsonSerializer serializer)
{
if (untypedValue == null)
{
serializer.Serialize(writer, null);
return;
}
var value = (long)untypedValue;
serializer.Serialize(writer, value.ToString());
return;
}
public static readonly ParseStringConverter Singleton = new ParseStringConverter();
}
}
If somehow you can fetch the KB number out of a Windows Update, then the article should be accessible at the following URL:
https://support.microsoft.com/en-us/kb/YOUR_KB_NUMBER
And the id="mt5" seems like being the title.
EDIT:
My bad, the id do change in fact, the first child of <section> with class="section kb-article spacer-84-top" is the title, however this might change ... (take it as it is :)
As Specified by canon in the comments of Aybe's answer, the KB pages load source via script once the page is loaded, so you cannot easily get this programmatically.
You can, however use the API link directly at e.g.
https://support.microsoft.com/app/content/api/content/help/en-us/4034733

JSON need nested array for JavaScriptSerializer without naming the element

I would like to use JavaScriptSerializer for this because I'm afraid of how many things might break and I can't change anything on the client-side.
If Json.Net is the best way to go then I will try it but I need an example.
I have this class
Class Definition
[DataContract]
[Serializable]
public class Family
{
[DataMember(Order = 0)]
public List<Member> members { get; set; }
}
[DataContract]
[Serializable]
public class Member
{
[DataMember(Order = 0)]
public string FName { get; set; }
[DataMember(Order = 1)]
public string LName { get; set; }
[DataMember(Order = 2)]
public string DOB { get; set; }
[DataMember(Order = 3)]
public string Gender { get; set; }
[DataMember(Order = 4)]
public string Type { get; set; }
}
The JSON I am Deserializing looks like this
JSON Example
[
{
"Family": [
{
"FName": "Jane",
"LName": "Prospect",
"DOB": "04/01/1980",
"Gender": "Female",
"Type": "Adult"
},
{...}
]
},
{
"OptionChoice": 34,
"OptionText": "Aquatics"
},
{...},
{...}
]
I can deserialize the Answer objects fine (OptionChoice,OptionText).
Hower the answer object has an additional item full of nulls where it is parsing the Family section of the JSON. I don't really want that.
When I try to deserialize the Family part I get an error
Type 'Family' is not supported for deserialization of an array.
It says it has a null for the Family.members. Is it looking for "Family": [ "members": {...},{...}] ?
How can I get this working without changing the JSON example?
Update After dbc Answer:
Here is my model
[DataContract]
[Serializable]
public class Answer
{
[DataMember(Order = 2, EmitDefaultValue = false)]
public int FormID { get; set; }
[DataMember(Order = 3,EmitDefaultValue = false)]
public int Question { get; set; }
[DataMember(Order = 5)]
public int OptionChoice { get; set; }
[DataMember(Order = 6,IsRequired = false)]
public string OptionText { get; set; }
[DataMember(Order = 5, EmitDefaultValue = false)]
public bool lockAnswer { get; set; }
[DataMember(Order = 1,EmitDefaultValue= false)]
public List<FamilyMember> Family { get; set; }
}
[DataContract]
[Serializable]
public class FamilyMember
{
[DataMember(Order = 0)]
public string FName { get; set; }
[DataMember(Order = 1)]
public string LName { get; set; }
[DataMember(Order = 2)]
public string DOB { get; set; }
[DataMember(Order = 3)]
public string Gender { get; set; }
[DataMember(Order = 4)]
public string Type { get; set; }
}
At this point in my creation of my SO update I solved the problem with Rubber Duck Debugging
Turns out I had some regex that was stripping all "[" & "]" then manually adding them back but only on the ends.
This cool comparison tool at http://pro.jsonlint.com/ helped btw.
Thanks! If anybody in the future reads this and wants to show a testable way to do this in JSON.net (I tried but got stuck) please do.
Your question includes two related questions:
Exception loading the Family list.
The problem here is that, as you suspect, there is no property corresponding to members. What your JSON has is an array of objects, each of which might have an array-valued property Family. Thus your data model should look like:
public class ResponseItem
{
public int? OptionChoice { get; set; }
public string OptionText { get; set; }
public List<FamilyMember> Family { get; set; }
// Other fields not shown from {...}
}
public class FamilyMember
{
public string FName { get; set; }
public string LName { get; set; }
public string DOB { get; set; }
public string Gender { get; set; }
public string Type { get; set; }
}
You state, "Hower the answer object has an additional item full of nulls where it is parsing the Family section of the JSON. I don't really want that." This could be done by deserializing the JSON into a polymorphic array where each possible derived type has just the minimal number of fields. However, since there is no __type information in your JSON, you will need to add some slightly fussy logic to chose the correct concrete type for each array element. Your data model would look like:
public interface IResponseItem // base interface for all possible responses
{
}
public class FamilyResponse : IResponseItem
{
public List<FamilyMember> Family { get; set; }
}
public class OptionsResponse : IResponseItem
{
public int OptionChoice { get; set; }
public string OptionText { get; set; }
}
In complex serialization situations like this people seem to prefer Json.NET, nevertheless it's still possible with JavaScriptSerializer as per your question. You must code up a JavaScriptConverter to select the appropriate derived type from the base IResponseItem type by matching the property names, for instance:
public class PolymorphicTypeConverter : JavaScriptConverter
{
public Type BaseType { get; private set; }
public Type[] DerivedTypes { get; private set; }
public PolymorphicTypeConverter(Type baseType, IEnumerable<Type> derivedTypes)
{
this.BaseType = baseType;
this.DerivedTypes = derivedTypes.ToArray();
}
static MemberInfo FindMember(Type type, string name)
{
try
{
var propInfo = type.GetProperty(name,
BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public);
if (propInfo != null
&& propInfo.GetSetMethod() != null
&& propInfo.GetIndexParameters().Length == 0)
return propInfo;
var fieldInfo = type.GetField(name,
BindingFlags.Instance | BindingFlags.IgnoreCase | BindingFlags.Public);
if (fieldInfo != null)
return fieldInfo;
}
catch (AmbiguousMatchException)
{
return null;
}
return null;
}
IEnumerable<Type> AncestorsAndSelf(Type type)
{
for (; type != null; type = type.BaseType)
if (DerivedTypes.Contains(type))
yield return type;
}
Type FindUniqueTypeMatch(IDictionary<string, object> jsonProperties)
{
List<Type> matches = new List<Type>();
foreach (var type in DerivedTypes)
{
if (type.IsInterface)
continue; // Bug?
bool isMatch = true;
foreach (var name in jsonProperties.Keys)
{
if (FindMember(type, name) == null)
{
isMatch = false;
break;
}
}
if (isMatch)
{
matches.Add(type);
}
}
if (matches.Count == 0)
return null;
else if (matches.Count == 1)
return matches[0];
else
{
// Multiple matches.
// If there is a common base type to all matches, return it. Otherwise, give up.
var candidates = AncestorsAndSelf(matches[0]).Reverse();
foreach (var match in matches.Skip(1))
{
candidates = candidates.Zip(AncestorsAndSelf(match).Reverse(), (t1, t2) => (t1 == t2 ? t1 : null)).Where(t => t != null);
}
return candidates.LastOrDefault();
}
}
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
var subtype = FindUniqueTypeMatch(dictionary);
if (subtype == null)
throw new JsonSerializationException();
var method = serializer.GetType().GetMethod("ConvertToType");
var generic = method.MakeGenericMethod(subtype);
return generic.Invoke(serializer, new object [] { dictionary } );
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
// Should never be called.
throw new NotImplementedException();
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new Type[] { BaseType };
}
}
}
This only works when each object in your JSON array has properties that match one and only one type in the derived type array. If this cannot be guaranteed, because, for instance, null fields were not serialized leading to multiple matches, you will need to enhance the converter to make a best guess match.
Then call it like:
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new PolymorphicTypeConverter(typeof(IResponseItem), new Type[] { typeof(FamilyResponse), typeof(OptionsResponse) }) });
var responseArray = serializer.Deserialize<IResponseItem[]>(json);

Custom Validation Attribute is not called ASP.NET MVC

Hello everyone I have create custom validation attribute and assign it to class level validation. Unfortunately, it is not called. I try every way that it think it could be solve the problem. However, it take me for hours and I can't find the attribute is not called by validation mechanism.
For illustrate you I put the following code.
Attribute
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true, Inherited = true)]
public sealed class BooleanDependencyAttribute : ValidationAttribute
{
private const string _defaultErrorMessage = "กรุณากรอก{0}";
private readonly object _typeId = new object();
public string DependencyPropertyName { get; private set; }
public string DependentPropertyName { get; private set; }
public BooleanDependencyAttribute(string dependencyPropertyName, string dependentPropertyName)
: base(_defaultErrorMessage)
{
DependencyPropertyName = dependencyPropertyName;
DependentPropertyName = dependentPropertyName;
}
public override object TypeId
{
get
{
return _typeId;
}
}
public override string FormatErrorMessage(string name)
{
return String.Format(CultureInfo.CurrentUICulture, ErrorMessageString,name);
}
public override bool IsValid(object value)
{
PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value);
bool dependencyValue = (bool) properties.Find(DependencyPropertyName, true /* ignoreCase */).GetValue(value);
object dependentValue = properties.Find(DependentPropertyName, true /* ignoreCase */).GetValue(value);
if (dependencyValue)
{
return true;
}
else
{
if (dependentValue == null)
{
return false;
}
else
{
return true;
}
}
}
}
ViewModel
[BooleanDependency("ReleaseNow","ReleaseDate",ErrorMessage="Please enter release date")]
public class ContentCreate
{
public string Title { get; set; }
public DateTime? ReleaseDate { get; set; }
public string Details { get; set; }
public string Abstract { get; set; }
public string Tags { get; set; }
public bool ReleaseNow { get; set; }
}
Please could you help me to solve this problem.
I found the solution. In fact validation in class level is called after all property-level validations are valid. Therefore I need to complete other required property then BooleanDependencyAttribute will called and valid value.
Thanks for view, edit the title and tag.

Categories