2014-02-18 7 views
12

Когда у меня есть класс без конструктора по умолчанию, то есть с помощью инъекции зависимостей для передачи его зависимостей, может ли Newtonsoft.Json создать такой объект?Как Json.NET может выполнять инъекцию зависимостей во время десериализации?

Например:

public class SomeFoo 
{ 
    private readonly IFooDependency _dependency; 

    public SomeFoo(IFooDependency dependency){ 
     if(dependency == null) 
      throw new ArgumentNullException("dependency"); 

     _dependency = dependency; 
    } 

    public string Data { get; set; } 
    public int MoreData { get; set; } 

    public void DoFoo(){ 
     Data = _dependency.GetFooData(); 
     MoreData = _dependency.GetMoreFooDate(); 
    } 
} 

Во время сериализации, я только заботиться о хранении данных и MoreData (и тип объекта, но давайте не усложнять на данный момент). Теперь десериализации, я могу назвать что-то вроде

var obj = JsonConvert.DeserializeObject<SomeFoo>(jsonText); 

Как я могу позволить JsonConvert знать о моей DI контейнера?

(Примечание. Обходной процесс должен состоять в том, чтобы всегда иметь конструкторы по умолчанию в моих классах и вызывать Service Locator там, чтобы получить любые зависимости, которые мне нужны. Я просто ищу еще более чистое решение без использования моих классов с такими конструкторами).

+0

Возможный дубликат [DI и JSON.NET] (http://stackoverflow.com/questions/2140978/di-and-json-net) – Steven

ответ

8

Я согласен с разделом проблем, поставленных Стивеном, и ответ Марк Seemann опубликовал here. Однако, если вы все еще хотите, чтобы идти по этому пути, вот это решение, которое может помочь:

унаследовать CustomCreationConverter<T>:

internal class NinjectCustomConverter<T> : CustomCreationConverter<T> where T : class 
{ 
    private readonly IResolutionRoot _serviceLocator; 

    public NinjectCustomConverter(IResolutionRoot serviceLocator) 
    { 
     _serviceLocator = serviceLocator; 
    } 

    public override T Create(Type objectType) 
    { 
     return _serviceLocator.Get(objectType) as T; 
    } 
} 

Затем убедитесь, что вы получить этот экземпляр преобразователя, а также с помощью вашего DI контейнера , Приведенный ниже код будет десериализации и выполнять DI на вашем объекте:

var ninjectConverter = kernel.Get<NinjectCustomConverter<SerializedObject>>(); 
var settings = new JsonSerializerSettings(); 
settings.Converters.Add(ninjectConverter); 

var instance = JsonConvert.DeserializeObject<SerializedObject>(json, settings); 

Here is a complete working example.

+0

Моя личная альтернатива - создать единый IContractResolver, который либо поддерживает собственное сопоставление для зависимостей, либо напрямую использует DI-резольвер. Таким образом вы можете просто ввести IContractResolver в типы, которые выполняют десериализацию, и IoC по-прежнему строго поддерживается. Это очень похожий подход, но устраняет «зависимость» от конкретного конвертера. –

7

Нельзя допустить, чтобы JsonConvert ничего не знал о вашем контейнере DI. Проблемы, которые вы испытываете, вызваны недостатком дизайна вашего приложения. Недостатком здесь является то, что вы данные и поведение смешивания.

Если вы отделите данные от поведения, ваша проблема (и многие другие проблемы) просто исчезнет. Вы можете сделать это, создав два класса: один для данных и один для поведения:

public class SomeFoo 
{ 
    public string Data { get; set; } 
    public int MoreData { get; set; } 
} 

public class SomeFooHandler 
{ 
    private readonly IFooDependency _dependency; 

    public SomeFooHandler(IFooDependency dependency) { 
     _dependency = dependency; 
    } 

    public void Handle(SomeFoo foo) { 
     foo.Data = _dependency.GetFooData(); 
     foo.MoreData = _dependency.GetMoreFooDate(); 
    } 
} 

Поскольку в настоящее время данные и поведение разделены, SomeFoo можно сериализовать без каких-либо проблем и SomeFooHandler может просто быть введен. SomeFoo становится Parameter Object.

+0

Кольца колокола для [шаблона посетителя] (http: // en .wikipedia.org/wiki/Visitor_pattern), что может быть очень полезно для достижения того, чего я хочу достичь, спасибо! –

+2

Ух! Дух, я не могу поверить, что не осознавал этого. Я делаю бегун выполнения задачи, и у меня были задачи, связанные с их зависимостями * вдоль * с параметрами. Я разберу их, чтобы это было намного чище. Спасибо за напоминание. – kamranicus

+1

Зачем вам ** всегда ** хотеть отделять данные и поведение? –

Смежные вопросы