2014-08-30 3 views
2
나는 문제가 다음과 같은 데이터 구조에 대한 예상대로 기본 모델 바인더가 작동하도록 점점 보내고 있습니다

:ModelBinder를 직렬화 해 임의의 JSON

JSON :

{ 
    template: "path/to/template", 
    slides: [{ 
     index: 0, 
     context: { 
      foo: "bar" 
     } 
    }, { 
     index: 1, 
     context: { 
      foo: 'bar!', 
      table: [ 
       ['Price', 'Revenue', 'Profit'], 
       [$5', 100, 20], 
       ['$10', 320, 4], 
       ['$7', 50, 2] 
      ] 
     } 

    }] 
} 

IPresentationData 모델 :

public interface IPresentationData 
{ 
    public string Template { get; set; } 

    public ICollection<SlideData> Slides { get; set; } 
} 

ISlideData 모델 :

public interface ISlideData 
{ 
    public int Index { get; set; } 

    public IContext Context { get; set; } 
} 

IContext 모델 :

public interface IContext : IDictionary<string, dynamic> 
{ 
} 

기본 모델 바인더가 임의의 큰/깊은 객체가 될 수 SlideData.Context를 제외하고, 함께 잘 작동합니다. 난 그냥 SlideData.Context 속성에 대한 System.Web.Mvc.DefaultModelBinder#BindModel를 오버라이드 (override) 할 필요가 생각하고

{ 
    'table': [ 
    [...] 
    ] 
} 

,하지만 난 정말 아니에요 대신의

{ 
    'table[0][0]': 'Price', 
    'table[0][1]': 'Revenue', 
    ... 
} 

: 예를 들어

json.context.table는로 역 직렬화 어디에서 시작해야하는지.

여기에 도움을 주시면 감사하겠습니다.

+0

[이 사이트] (http://json2csharp.com/)를 보았습니까? –

+0

꽤 멋지지만 컨텍스트 속성은 완전히 동적입니다. –

+0

그러면 Json.Net에서'dynamic'을 사용할 수 있습니다. 그냥 SO를 검색하십시오. –

답변

4

ExpandoObject을 지원하는 IModelBinder이 필요한 것으로 나타났습니다.

HttpApplication#Application_Start에서 :

ModelBinders.Binders.Add(typeof(Context), new DynamicDictionaryModelBinder()); 
ModelBinders.Binders.Add(typeof(ExpandoObject), new DynamicDictionaryModelBinder()); 

사용자 정의 바인더 :

는 JSON 이미 IValueProvider 스택에 내장하여 제대로 연재되고 있었다
public class DynamicDictionaryModelBinder : DefaultModelBinder 
{ 
    public override object BindModel(
     ControllerContext controllerContext, 
     ModelBindingContext bindingContext) 
    { 
     var model = bindingContext.Model; 
     var modelType = bindingContext.ModelType; 

     if (model == null) 
     { 
      model = this.CreateModel(controllerContext, bindingContext, modelType); 
     } 

     var dictionaryBindingContext = new ModelBindingContext() 
             { 
              ModelMetadata = 
               ModelMetadataProviders.Current 
               .GetMetadataForType(() => model, modelType), 
              ModelName = bindingContext.ModelName, 
              ModelState = bindingContext.ModelState, 
              PropertyFilter = bindingContext.PropertyFilter, 
              ValueProvider = bindingContext.ValueProvider 
             }; 

     return this.UpdateDynamicDictionary(controllerContext, dictionaryBindingContext); 
    } 

    private static KeyValuePair<string, object> CreateEntryForModel(
     ControllerContext controllerContext, 
     ModelBindingContext bindingContext, 
     Type valueType, 
     IModelBinder valueBinder, 
     string modelName, 
     string modelKey) 
    { 
     var valueBindingContext = new ModelBindingContext() 
     { 
      ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, valueType), 
      ModelName = modelName, 
      ModelState = bindingContext.ModelState, 
      PropertyFilter = bindingContext.PropertyFilter, 
      ValueProvider = bindingContext.ValueProvider 
     }; 

     var thisValue = valueBinder.BindModel(controllerContext, valueBindingContext); 

     return new KeyValuePair<string, object>(modelKey, thisValue); 
    } 

    private object UpdateDynamicDictionary(
     ControllerContext controllerContext, 
     ModelBindingContext bindingContext) 
    { 
     var modelList = new List<KeyValuePair<string, object>>(); 

     var enumerableValueProvider = bindingContext.ValueProvider as IEnumerableValueProvider; 
     if (enumerableValueProvider != null) 
     { 
      var keys = enumerableValueProvider.GetKeysFromPrefix(bindingContext.ModelName); 
      var groups = keys.GroupBy((k) => k.Key.Split('[')[0]); 

      foreach (var group in groups) 
      { 
       if (group.Count() > 1) 
       { 
        var valueType = typeof(ICollection<ExpandoObject>); 

        modelList.Add(
         CreateEntryForModel(
          controllerContext, 
          bindingContext, 
          valueType, 
          Binders.GetBinder(valueType), 
          bindingContext.ModelName + '.' + group.Key, 
          group.Key)); 
       } 
       else 
       { 
        var item = group.Single(); 
        var value = bindingContext.ValueProvider.GetValue(item.Value); 
        var valueType = value != null && value.RawValue != null ? 
          typeof(object) : typeof(ExpandoObject); 

        modelList.Add(
         CreateEntryForModel(
          controllerContext, 
          bindingContext, 
          valueType, 
          Binders.GetBinder(valueType), 
          item.Value, 
          item.Key)); 
       } 
      } 

     } 

     var dictionary = (IDictionary<string, object>)bindingContext.Model; 

     foreach (var kvp in modelList) 
     { 
      dictionary[kvp.Key] = kvp.Value; 
     } 

     return dictionary; 
    } 
} 

, 그냥 있었다 여기

코드입니다 Binder#GetBinder(Type)과 적절한 접근 자에 적절한 유형을 제공해야합니다. 예를 들어 ICollection<ExpandoObject> + revenueobject + revenue[0][0]입니다.