为DateTime定制JavaScriptConverter?

我有一个对象,它有一个DateTime属性...我想通过AJAX / JSON将该对象从.ashx处理程序传递回网页...我不想使用第三方控件...

当我这样做时:

  new JavaScriptSerializer().Serialize(DateTime.Now);

我得到这个:

  "/Date(1251385232334)/"

但我想要“2009年8月26日”(从不知道本地化......我的应用程序是非常本地化的,所以我的日期格式假设不适合在这个问题上辩论)。 如果我制作/注册一个自定义转换器

public class DateTimeConverter : JavaScriptConverter
{
    public override IEnumerable<Type> SupportedTypes
    {
        get { return new List<Type>() { typeof(DateTime), typeof(DateTime?) }; }
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        Dictionary<string, object> result = new Dictionary<string, object>();
        if (obj == null) return result;
        result["DateTime"] = ((DateTime)obj).ToShortDateString();
        return result;
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary.ContainsKey("DateTime"))
            return new DateTime(long.Parse(dictionary["DateTime"].ToString()), DateTimeKind.Unspecified);
        return null;
    }
}

那么我得到这个结果(因为自定义序列化方法的返回值是一个字典):

{"DateTime":"8/27/2009"}

所以现在在我的Javascript中,而不是做

somePerson.Birthday

我要做

somePerson.Birthday.DateTime 

  or

somePerson.Birthday["DateTime"]

我如何使自定义转换器返回一个直接的字符串,以便我可以有干净的Javascript?


JavaScriptSerializer绝对可以做你想做的事。

可以通过创建自定义转换器并将其注册到序列化程序来自定义JavaScriptSerializer为任何类型执行的序列化。 如果你有一个名为Person的类,我们可以像这样创建一个转换器:

public class Person
{
    public string Name { get; set; }
    public DateTime Birthday { get; set; }
}

public class PersonConverter : JavaScriptConverter
{
    private const string _dateFormat = "MM/dd/yyyy";

    public override IEnumerable<Type> SupportedTypes
    {
        get
        {
            return new[] { typeof(Person) };
        }
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        Person p = new Person();
        foreach (string key in dictionary.Keys)
        {
            switch (key)
            {
                case "Name":
                    p.Name = (string)dictionary[key];
                    break;

                case "Birthday":
                    p.Birthday = DateTime.ParseExact(dictionary[key] as string, _dateFormat, DateTimeFormatInfo.InvariantInfo);
                    break;
            }
        }
        return p;
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        Person p = (Person)obj;
        IDictionary<string, object> serialized = new Dictionary<string, object>();
        serialized["Name"] = p.Name;
        serialized["Birthday"] = p.Birthday.ToString(_dateFormat);
        return serialized;
    }
}

并像这样使用它:

JavaScriptSerializer serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new[] { new PersonConverter() });

Person p = new Person
            {
                Name = "User Name",
                Birthday = DateTime.Now
            };

string json = serializer.Serialize(p);
Console.WriteLine(json);
// {"Name":"User Name","Birthday":"12/20/2010"}

Person fromJson = serializer.Deserialize<Person>(json);
Console.WriteLine(String.Format("{0}, {1}", fromJson.Name, fromJson.Birthday)); 
// User Name, 12/20/2010 12:00:00 AM

以下是对接受答案的改进。

使用泛型,传递一个类型并使用反射来确定日期时间属性。

public class ExtendedJavaScriptConverter<T> : JavaScriptConverter where T : new()
{
    private const string _dateFormat = "dd/MM/yyyy";

    public override IEnumerable<Type> SupportedTypes
    {
        get
        {
            return new[] { typeof(T) };
        }
    }

    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        T p = new T();

        var props = typeof(T).GetProperties();

        foreach (string key in dictionary.Keys)
        {
            var prop = props.Where(t => t.Name == key).FirstOrDefault();
            if (prop != null)
            {
                if (prop.PropertyType == typeof(DateTime))
                {
                    prop.SetValue(p, DateTime.ParseExact(dictionary[key] as string, _dateFormat, DateTimeFormatInfo.InvariantInfo), null);

                }
                else
                {
                    prop.SetValue(p, dictionary[key], null);
                }
            }
        }                  

        return p;
    }      

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        T p = (T)obj;
        IDictionary<string, object> serialized = new Dictionary<string, object>();

        foreach (PropertyInfo pi in typeof(T).GetProperties())
        {
            if (pi.PropertyType == typeof(DateTime))
            {
                serialized[pi.Name] = ((DateTime)pi.GetValue(p, null)).ToString(_dateFormat);
            }
            else
            {
                serialized[pi.Name] = pi.GetValue(p, null);
            }

        }

        return serialized;
    }

    public static JavaScriptSerializer GetSerializer() 
    {
        JavaScriptSerializer serializer = new JavaScriptSerializer();
        serializer.RegisterConverters(new[] { new ExtendedJavaScriptConverter<T>() });

        return serializer;
    }
}

用法很简单:

 JavaScriptSerializer serialiser = ExtendedJavaScriptConverter<Task>.GetSerializer();

希望能帮助别人。


实际上有一个很好的干净的方法来做到这一点,而不知道包装类型,甚至不需要包装对象。

您使用JavaScriptConverter将您的对象转换为也实现了IDictionary的Uri。 JavaScriptSerializer会将其串行化为一个字符串。

这里描述了这种攻击:

http://blog.calyptus.eu/seb/2011/12/custom-datetime-json-serialization/

链接地址: http://www.djcxy.com/p/1263.html

上一篇: Custom JavaScriptConverter for DateTime?

下一篇: How do I format a Microsoft JSON date?