2

I have a JSON string e.g.

{
  "first_name": "Paul"
  "company": {
    "company_name": "Microsoft"
  }
}

and my class is in the following structure

[DataContract]
class User {
  [DataMember(Name = "first_name")]
  public string FirstName { get; set; }

  [DataMember(Name = "company")]
  public ICompany Company { get; set; }
}

interface ICompany {
  string CompanyName { get; set; }
}

[DataContract]
class Company : ICompany {
  [DataMember(Name = "company_name")]
  public string CompanyName { get; set; }
}

I use a custom auto resolver which just finds a implementation of a interface using autofac (pulled from json.net website)

public class AutofacContractResolver : DefaultContractResolver
    {
        private readonly IContainer _container;

        public AutofacContractResolver(IContainer container)
        {
            _container = container;
        }

        protected override JsonObjectContract CreateObjectContract(Type objectType)
        {
            JsonObjectContract contract = base.CreateObjectContract(objectType);

            // use Autofac to create types that have been registered with it
            if (_container.IsRegistered(objectType))
            {
                contract.DefaultCreator = () => _container.Resolve(objectType);
            }

            return contract;
        }
    }

I then deserialize the json string using

User user = JsonConvert.DeserializeObject<User>(json, new JsonSerializerSettings
                {
                    ContractResolver = _resolver,

                });

Now when I deserialize the json the first_name gets serialized into the FirstName property but the company_name does not, it just returns null. When I use the TraceWriter it states that it cannot find a member called company_name on the ICompany interface (which it obviously cannot as that is set on the Company object class)

Why is JSON.NET not using the DataMember name from the Company object to deserialize against? As it knows about the Compmany object from the custom resolver and it creates that object but just with no values inside.

How can I get it to use the implementation of the interface and not the interface itself?

FYI, this is not the whole object and I cannot just change my property to a class instead of an interface. This is just a slimmed down example of what is happening to all the interface objects.

Carl Thomas
  • 3,605
  • 6
  • 38
  • 50

1 Answers1

2

I just had the same problem and while searching for an answer I found your old question here. Actually the way you asked it got me on the right track and I solved the problem. The following works for me:

I don't use Autofac, so this is pseudocode. But it should be enough to understand it:

public class AutofacContractResolver : DefaultContractResolver
{
    private readonly IContainer _container;

    public AutofacContractResolver(IContainer container)
    {
        _container = container;
    }

    protected override JsonObjectContract CreateObjectContract(Type objectType)
    {
        JsonObjectContract contract;

        // use Autofac to create types that have been registered with it
        if (_container.IsRegistered(objectType))
        {
            //get the class that is mapped to the interface from autofac
            Type mappedType = _container.GetMappedTypeForRegisteredType(objectType);

            //so for example when objectType now contains 'ICompany'
            //then mappedType now should contain 'Company'

            //now use the mappedType to create the contract
            contract = base.CreateObjectContract(mappedType);

            //but still use the objectType for resolving
            contract.DefaultCreator = () => _container.Resolve(objectType);
        }
        else
            contract = base.CreateObjectContract(objectType);

        return contract;
    }
}

The contract should be created using the concrete implementation that is registered in the dependency container instead of the interface. Resolving the type from the container for the DefaultCreator obviously should still use the interface.

alex
  • 83
  • 1
  • 8