MVC 3 doesn't bind nullable long

前端 未结 5 1452
执笔经年
执笔经年 2021-02-03 10:04

I made a test website to debug an issue I\'m having, and it appears that either I\'m passing in the JSON data wrong or MVC just can\'t bind nullable longs. I\'m using the latest

5条回答
  •  执念已碎
    2021-02-03 10:52

    I wanted to incorporate the solution presented by Edgar but still have the features of the DefaultModelBinder. So instead of creating a new model binder I went with a different approach and replaced the JsonValueProviderFactory with a custom one. There's only a minor change in the code from the original MVC3 source code:

    public sealed class NumericJsonValueProviderFactory : ValueProviderFactory
    {
    
        private static void AddToBackingStore(Dictionary backingStore, string prefix, object value)
        {
            IDictionary d = value as IDictionary;
            if (d != null)
            {
                foreach (KeyValuePair entry in d)
                {
                    AddToBackingStore(backingStore, MakePropertyKey(prefix, entry.Key), entry.Value);
                }
                return;
            }
    
            IList l = value as IList;
            if (l != null)
            {
                for (int i = 0; i < l.Count; i++)
                {
                    AddToBackingStore(backingStore, MakeArrayKey(prefix, i), l[i]);
                }
                return;
            }
    
            // primitive
            backingStore[prefix] = value;
        }
    
        private static object GetDeserializedObject(ControllerContext controllerContext)
        {
            if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
            {
                // not JSON request
                return null;
            }
    
            StreamReader reader = new StreamReader(controllerContext.HttpContext.Request.InputStream);
            string bodyText = reader.ReadToEnd();
            if (String.IsNullOrEmpty(bodyText))
            {
                // no JSON data
                return null;
            }
    
            JavaScriptSerializer serializer = new JavaScriptSerializer();
    
            // below is the code that Edgar proposed and the only change to original source code
            bodyText = Regex.Replace(bodyText, @"(?<=:)\s{0,4}(?[\d\.]+)\s{0,4}(?=[,|\]|\}]+)", "\"${num}\""); 
    
            object jsonData = serializer.DeserializeObject(bodyText);
            return jsonData;
        }
    
        public override IValueProvider GetValueProvider(ControllerContext controllerContext)
        {
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
    
            object jsonData = GetDeserializedObject(controllerContext);
            if (jsonData == null)
            {
                return null;
            }
    
            Dictionary backingStore = new Dictionary(StringComparer.OrdinalIgnoreCase);
            AddToBackingStore(backingStore, String.Empty, jsonData);
            return new DictionaryValueProvider(backingStore, CultureInfo.CurrentCulture);
        }
    
        private static string MakeArrayKey(string prefix, int index)
        {
            return prefix + "[" + index.ToString(CultureInfo.InvariantCulture) + "]";
        }
    
        private static string MakePropertyKey(string prefix, string propertyName)
        {
            return (String.IsNullOrEmpty(prefix)) ? propertyName : prefix + "." + propertyName;
        }
    }
    
    
    

    Then to register the new value provider you need to add the following lines to your Global.asax:

    ValueProviderFactories.Factories.Remove(ValueProviderFactories.Factories.OfType().FirstOrDefault());
    ValueProviderFactories.Factories.Add(new NumericJsonValueProviderFactory());
    

    提交回复
    热议问题