Custom JavaScriptConverter for DateTime?

前端 未结 10 639
走了就别回头了
走了就别回头了 2020-12-02 19:18

I have an object, it has a DateTime property... I want to pass that object from an .ashx handler back to a webpage via AJAX/JSON... I don\'t want to use 3rd party controls..

相关标签:
10条回答
  • 2020-12-02 19:36

    Here's an enhancement for the accepted answer.

    Using generics, passing a type and using reflection to determine the datetime properties.

    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;
        }
    }
    

    Usage is simple:

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

    Hope that helps someone.

    0 讨论(0)
  • 2020-12-02 19:38

    Actually there is an ugly way, create a JavaScriptConverter for the container (Person/Article/Whatever) class

    Container:

    public class Article
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public DateTime Date { get; set; }
    }
    

    Converter:

    public class ArticleJavaScriptConverter : JavaScriptConverter
    {
        public override IEnumerable<Type> SupportedTypes
        {
            get { return new Type[] { typeof(Article) }; }
        }
    
        public override object Deserialize(
            IDictionary<string, object> dictionary, 
            Type type, JavaScriptSerializer serializer)
        {
            DateTime date = 
                DateTime.ParseExact(dictionary["date"] as string, "s", null);
    
            return
                new Article()
                {
                    Id = (int)dictionary["id"],
                    Title = dictionary["title"] as string,
                    Date = date
                };
        }
    
        public override IDictionary<string, object> Serialize(
            object obj, JavaScriptSerializer serializer)
        {
            var article = obj as Article;
            var result = new Dictionary<string,object>();
    
            if (article != null)
            {
                this.SerializeInternal(article, result);
            }
    
            return result;
        }
    
        private void SerializeInternal(
            Article article, IDictionary<string, object> result)
        {
            result.Add("id", article.Id);
            result.Add("title", article.Title);
            result.Add("date", article.Date.ToString("s"));
        }
    }
    

    Happily ever after...

    var serializer = new JavaScriptSerializer();
    
    serializer.RegisterConverters(
        new JavaScriptConverter[] {
            new ArticleJavaScriptConverter() 
        });
    
    var expected = new Article()
    {
        Id = 3,
        Title = "test",
        Date = DateTime.Now
    };
    
    
    // {"id":3,"title":"test","date":"2009-12-02T05:12:00"}
    var json = serializer.Serialize(article);
    
    var actual = serializer.Deserialize<Article>(json);
    
    Assert.AreEqual(expected, actual);
    
    0 讨论(0)
  • 2020-12-02 19:42

    There is actually a nice clean way to do this without knowing the wrapper type or even needing a wrapper object.

    You use JavaScriptConverter to convert your object to a Uri that also implements IDictionary. JavaScriptSerializer will serialize this as a string.

    This hack is described here: Custom DateTime JSON Format for .NET JavaScriptSerializer

    0 讨论(0)
  • 2020-12-02 19:46

    link text This example works

    JavaScriptSerializer serializer = new JavaScriptSerializer();
    
    DateTime dt = DateTime.Now;
    DateTime dt1 = dt;
    
    string jsonDateNow = serializer.Serialize(dt1);
    
    0 讨论(0)
提交回复
热议问题