How can Json.NET perform dependency injection during deserialization? - c#

When I have a class with no default constructor, i.e. using dependency injection to pass its dependencies, can Newtonsoft.Json create such an object?
For example:
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();
}
}
During serialization, I only care of storing Data and MoreData (and the type of the object, but let's don't complicate things for the moment). Now, to deserialize, can I call something like
var obj = JsonConvert.DeserializeObject<SomeFoo>(jsonText);
How can I let JsonConvert know about my DI container?
(Note: A work-around would be to always have default constructors in my classes, and call Service Locator in there to get any dependencies I need. I'm just looking for some more clean solution without poluting my classes with such constructors).

You shouldn't let JsonConvert know anything about your DI container. The problems you're experiencing are caused by a flaw in the design of your application. The flaw here is that you mix data and behavior.
If you separate the data from the behavior your problem (and many other problems) will simply go away. You can do this by creating two classes: one for the data, and one for the behavior:
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();
}
}
Since now data and behavior are separated, SomeFoo can be serialized without any problem and SomeFooHandler can simply be injected. SomeFoo has becomes a Parameter Object.

I agree with the separation of concerns posted by Steven, and the answer Mark Seemann has posted here. However, if you still want to go this way, here is a solution that may help:
Inherit a 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;
}
}
Then make sure you retrieve this converter instance via your DI container as well. The code below will deserialize and perform DI on your object:
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.

If your objective is to use the injected dependency to modify the data, then you can create a custom Converter.
With this, you should be able to inject your dependency. Similar to the code below:
var settings = new JsonSerializerSettings
{
Converters = { new FooConverter<T>(injectedDependency) }
};
return JsonConvert.DeserializeObject<Dto>(json, settings);
There're many samples of how to create a custom Converters, so you can refer to them.

Related

ASP.NET Core how to pass parameter in service builder

I've read a very useful article from Michael McKenna blog about creating a multi-tenant application but I've a couple of issues.
The first one in the TenantMiddleware class as Constants.HttpContextTenantKey is undefined, it's likely due to some missing code, I've set a constant string in the meantime.
The main issue is that I'd like to pass the tenants array in the InMemoryTenantStore class when I call the service at startup. I've modified the InMemoryTenantStore class
public class InMemoryTenantStore : ITenantStore<Tenant>
{
private readonly Tenant[] _tenants;
public InMemoryTenantStore(Tenant[] tenants)
{
_tenants = tenants;
}
but I don't have idea how to pass the array in the calling service. I guess I need to tweak this code
public TenantBuilder<T> WithStore<V>(ServiceLifetime lifetime = ServiceLifetime.Transient) where V : class, ITenantStore<T>
{
_services.Add(ServiceDescriptor.Describe(typeof(ITenantStore<T>), typeof(V), lifetime));
return this;
}
But I can't find any example about this and unfortunately I can't reach the author blog.
For creating object instances through ServiceDescriptor with parameters you must to provide implementation factory to it, not just implementation type.
You can do this two ways:
Just create instance directly before WithStore method.
Create implementation factory for build TenantBuilder (using lambda or separate method)
// Creating instance outside
public TenantBuilder<T> WithStore<V>(V store, ServiceLifetime lifetime = ServiceLifetime.Transient) where V : class, ITenantStore<T>
{
_services.Add(ServiceDescriptor.Describe(typeof(ITenantStore<T>), provider => store, lifetime));
return this;
}
// Implementation factory
public TenantBuilder<T> WithStore<V>(Func<IServiceProvider, V> implementationFactory, ServiceLifetime lifetime = ServiceLifetime.Transient) where V : class, ITenantStore<T>
{
_services.Add(ServiceDescriptor.Describe(typeof(ITenantStore<T>), implementationFactory, lifetime));
return this;
}
this is what I did
public class Constants
{
public static Dictionary<string, object> HttpContextTenantKey { get; private set; } = new Dictionary<string, object>();
}

How to initialize abstract base constructor when client calls new on DataContract?

I'm trying to come up with a workaround that would accommodate an abstract base class's constructor being initialized when a client consuming my WCF service performs a new() over a DataContract object. I'm aware that the DataContract objects are created as raw, uninitialized objects thus no constructors are called. I ran across the user of the [OnSerializing], [OnSerialized], [OnDeserializing], and [OnDeserialized] attributes, and I've discovered that they are not honored by the serialization engine of WCF unless you explicitly force it to use XML, which is not desired in this specific case. Here's a very simplified coding example of what I'm trying to use.
[DataContract(Namespace = "http://somenamespace/Data/ContractBase/v1")]
public abstract ContractBase
{
[DataMember(IsRequired = true)]
public SomeDataContract BaseClassObject { get; set; }
public string Name { get; set; }
public ContractBase()
{
BaseClassObject = new SomeDataContract("randomConstructorArgument");
Name = "Ezra";
}
}
[DataContract(Namespace = "http://somenamespace/Data/TheClass/v1")]
[KnownType(typeof(ContractBase))]
public sealed class TheClass : ContractBase
{
[DataMember]
public PetDataContract MyPet { get; set; }
[DataMember]
public int SomeIntProperty { get; set; }
public TheClass()
: base()
{
MyPet = new PetDataContract ("Fido");
SomeIntProperty = -1;
}
}
I'm aware that the client performing TheClass myClass = new TheClass(); will not initialize the base constructor since the constructor of TheClass is never called. I attempted to add in methods such as the following to trigger when serialization occurs without any success.
private void Initialize()
{
MyPet = new PetDataContract ("Fido");
SomeIntProperty = -1;
base.Initialize();
}
[OnSerializing]
private void OnSerializing(StreamingContext c)
{
Initialize();
}
The base class would have the Initialize method as well so that the "constructors" would be chained. The constructors themselves would be updated to include the Initialize(); call to use the same common source of code.
Is there a way to handle this without forcing the serialization to be done through the XmlSerializer? My current workaround is to provide a method in the WCF service to create the object on the server and return the post-constructor version.
public TheClass CreateTheClass(TheClass contract)
{
// Calls the constructor of TheClass and its base constructor.
return new TheClass();
}
This does work as expected, but it's an extra service call that I'd rather avoid because of the network I/O cost. Any help would be extremely appreciated.
Thanks!
According to this article the attributes you mentioned should work nicely with DataContractSerializer. Your last example is a little bit strange - you are trying to use OnSerializing attribute while saying that constructors are not called during deserialization by WCF.
I would suggest to use your approach with Initialize methods marked by OnDeserializing (or OnDeserialized if you wish to call your code after deserialization was completed) attribute.

Structuremap all instances of abstract

Using Net 4.5.1 and StructureMap 3.1.4
I have services that extending an abstract class:
public abstract class Charting<T> {
protected readonly String baseConfigurationString;
public Charting(String baseConfigurationString)
{
this.baseConfigurationString = baseConfigurationString;
}
...
}
For every concrete service I want to set the baseConfigurationString. Right now I am doing it individually per service:
public class MyRegistry : Registry
{
public MyRegistry()
{
Profile("Development", x => {
ForConcreteType<AveragePartySizeChart>().Configure.Ctor<String>("baseConfigurationString").Is(MyDbConfiguration.getBaseConnectionString());
...next service....about 6 total
});
}
}
Is there anyway to do this generally acting against the abstract class despite it having a generic qualifier?
My suggestion, and what we did with StructureMap for configuration within FubuMVC, is to create a class something like:
public class ConnectionSettings
{
public string Connection {get;set;}
}
and resolve that through StructureMap as a singleton. Then in any class that needs the connection string, just do:
public abstract class DatabaseConnectionUser
{
public DatabaseConnectionUser(ConnectionSettings settings){}
}
Autowiring will connect your ConnectionSettings object to all the class objects that take in
that object in their constructor function.
You could try using a custom IPluginGraphConfiguration class in StructureMap 3 to set the ctor argument explicitly on all Instance's that build a subclass, but I think that would be more work.
This does not solve your abstract constructor argument setting via Profile problem but I would like to suggest that you avoid taking dependencies on primitive types like System.String and use an abstraction instead.
You could have an type IDatabaseSettings which gets the connection settings you desire for either environment variables or application settings.
public interface IDatabaseSettings
{
string DbConnectionString { get; set; }
}
public class DatabaseSettings : IDatabaseSettings
{
public string DbConnectionString { get; set; }
}
public class DatabaseRegistry : Registry
{
public DatabaseRegistry()
{
For<IDatabaseSettings>().Use(c =>
{
var setting = c.GetInstance<DatabaseSettings>();
setting.DbConnectionString =
System.Configuration.ConfigurationManager.AppSettings["DatabaseSettings.DBConnectionString"];
return setting;
});
}
}
Important: Your project will need to reference System.Configuration.
If you have a lot of settings you may want to conventionalize this pattern. We use the SettingsProvider out of FubuCore to make this a breeze. You simply have objects that end in Settings which get their properties automatically populated out of application settings. Chad Myers has a nice blog post on it.

Providing Ninject with constructor dependencies it can't resolve?

Disclaimer: I'm quite new to DI and IoC, please forgive any drastic misunderstandings.
Consider a ClassB that requires a object implementing IClassA. Ninject should be able to inject instances of ClassA into the constructor of ClassB, assuming it can construct instances of ClassA:
public class ClassA : IClassA
{
public ClassA(string runtimeDependency) { /* ... */ }
}
public class ClassB : IClassB
{
public ClassB(IClassA depA) { /* ... */ }
}
public sealed class TestBootstrapModule : NinjectModule
{
public override void Load()
{
Bind<IClassA>().To<ClassA>();
Bind<IClassB>().To<ClassB>();
}
}
Now, let's say some runtime logic is involved in deriving the string runtimeDependency provided to ClassA. How should I provide Ninject with runtimeDependency so that it can provide ClassB with instances of ClassA?
The string will only be determined once, so I don't need to worry about injecting a new value into each instance.
One way to do it is to provide the ClassA via a method. Also keep in mind that with Ninject 2, you don't need modules and can do bindings directly in the Kernel.
Bind<IClassA>().ToMethod(_ =>
{
// do something interesting with a runtimeDependancy
return new ClassA(someInterestingVariable);
});
I'm really taking a stab as to when your runtime variable is available and it's scope.
There are a few options here depending on your design, and specific problem. The first, easiest solution is to just provide the value when you request your service from Ninject
Kernel.Get<IClassA>("runtimeDependencyValue");
If this is not possible however, things get a bit more interesting. The way I've solved this previously is to actually create contextual bindings to System.String itself.
Say if I want to bind a connection string, I'll create a custom attribute:
[AttributeUsage(AttributeTargets.Parameter | AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
public class ConnectionStringAttribute : Attribute
{
/// <summary>
/// Denotes the setting that you want to populate the given property with.
/// </summary>
public string SettingName { get; private set; }
public ConnectionStringAttribute(string configSettingName = "")
{
SettingName = configSettingName;
}
}
and then I decorate my service constructor like this:
public class ClassA : IClassA
{
public ClassA([ConnectionString("AppDB")] string runtimeDependency) { /* ... */ }
}
Finally, my binding will look something like this:
Bind<string>()
.ToMethod(ctx =>
{
var attr = (ConnectionStringAttribute)context.Request.Target.GetCustomAttributes(typeof(ConnectionStringAttribute), true).First();
string settingName = string.IsNullOrEmpty(attr.SettingName) ? context.Request.Target.Name : attr.SettingName;
return ConfigurationManager.ConnectionStrings[settingName].ConnectionString;
})
.WhenTargetHas<ConnectionStringAttribute>();
You get the idea. Hope this helps :)

How can one use an existing instance to select a type to create in an IoC container

this is probably just a newbie question, but I have the following:
public class FooSettings {}
public class BarSettings {}
public class DohSettings {}
// There might be many more settings types...
public interface IProcessor { ... }
public class FooProcessor
: IProcessor
{
public FooProcessor(FooSettings) { ... }
}
public class BarProcessor
: IProcessor
{
public BarProcessor(BarSettings) { ... }
}
public class DohProcessor
: IProcessor
{
public DohProcessor(DohSettings) { ... }
}
// There might be many more processor types with matching settings...
public interface IProcessorConsumer {}
public class ProcessorConsumer
: IProcessorConsumer
{
public ProcessorConsumer(IProcessor processor) { ... }
}
An instance of either FooSettings or BarSettings is provided from an external source i.e.:
object settings = GetSettings();
And now I would like to resolve ProcessorConsumer based on injecting the existing instance of settings e.g.:
container.RegisterAssemblyTypes(...); // Or similar
container.Inject(settings);
var consumer = container.Resolve<IProcessorConsumer>();
That is if an instance of FooSettings is provided then a FooProcessor is created and injected into the ProcessorConsumer which is then the instance resolved.
I haven't been able to figure out how to do this in either StructureMap, Ninject nor Autofac... probably because I am a newbie when it comes to IoC containers. So answers for all of these or other containers so they can be compared would be highly appreciated.
UPDATE: I am looking for a solution which easily allows for new settings and processors to be added. Also there will be a one-to-on mapping from settings type to processor type. But which also allows for other instances/services to be injected in a given processor type, based on its constructor parameters. I.e. some processor might need a IResourceProvider service or similar. Just an example here.
Ideally, I would like something like
container.For<IProcessor>.InjectConstructorParameter(settings)
or similar. Thereby, guiding the IoC container to use the processor type matching the injected constructor parameter instance.
You don't want dependency injection for this. You want a factory (which, of course, you can build using your container). The factory would know how to take, say, an IProcessorSettings and return the appropriate IProcessor. In short, you can build a factory that uses the concrete type of an object that implements IProcessorSettings and the container to resolve an instance of the appropriate type.
I think what you are looking for is the ForObject() method in StructureMap. It can close an open generic type based on a given object instance. The key change you need to make to your design is to introduce the generic type:
public interface IProcessor { }
public interface IProcessor<TSettings> : IProcessor{}
All of the important stuff is still declared on IProcessor, the generic IProcessor<TSettings> is really just a marker interface. Each of your processors will then implement the generic interface, to declare which settings type they expect:
public class FooProcessor : IProcessor<FooSettings>
{
public FooProcessor(FooSettings settings) { }
}
public class BarProcessor : IProcessor<BarSettings>
{
public BarProcessor(BarSettings settings) { }
}
public class DohProcessor : IProcessor<DohSettings>
{
public DohProcessor(DohSettings settings) { }
}
Now, given an instance of a settings object, you can retrieve the correct IProcessor:
IProcessor processor = container.ForObject(settings).
GetClosedTypeOf(typeof(IProcessor<>)).
As<IProcessor>();
Now you can tell StructureMap to use this logic whenever it resolves an IProcessor:
var container = new Container(x =>
{
x.Scan(scan =>
{
scan.TheCallingAssembly();
scan.WithDefaultConventions();
scan.ConnectImplementationsToTypesClosing(typeof(IProcessor<>));
});
x.For<IProcessor>().Use(context =>
{
// Get the settings object somehow - I'll assume an ISettingsSource
var settings = context.GetInstance<ISettingsSource>().GetSettings();
// Need access to full container, since context interface does not expose ForObject
var me = context.GetInstance<IContainer>();
// Get the correct IProcessor based on the settings object
return me.ForObject(settings).
GetClosedTypeOf(typeof (IProcessor<>)).
As<IProcessor>();
});
});
StructureMap containers expose the Model property which allows you to query for the instances it contains.
var container = new Container(x =>
{
x.For<IProcessorConsumer>().Use<ProcessorConsumer>();
x.For<IProcessor>().Use(context =>
{
var model = context.GetInstance<IContainer>().Model;
if (model.PluginTypes.Any(t => typeof(FooSettings).Equals(t.PluginType)))
{
return context.GetInstance<FooProcessor>();
}
return context.GetInstance<BarProcessor>();
});
});
In Autofac given:
public class AcceptsTypeConstructorFinder
: IConstructorFinder
{
private readonly Type m_typeToAccept;
public AcceptsTypeConstructorFinder(Type typeToAccept)
{
if (typeToAccept == null) { throw new ArgumentNullException("typeToAccept"); }
m_typeToAccept = typeToAccept;
}
public IEnumerable<ConstructorInfo> FindConstructors(Type targetType)
{
return targetType.GetConstructors()
.Where(constructorInfo => constructorInfo.GetParameters()
.Select(parameterInfo => parameterInfo.ParameterType)
.Contains(m_typeToAccept));
}
}
the following works:
// Load
var settings = new BarSettings();
var expectedProcessorType = typeof(BarProcessor);
// Register
var constructorFinder = new AcceptsTypeConstructorFinder(settings.GetType());
var builder = new ContainerBuilder();
var assembly = Assembly.GetExecutingAssembly();
builder.RegisterInstance(settings);
builder.RegisterAssemblyTypes(assembly)
.Where(type => type.IsAssignableTo<IProcessor>() && constructorFinder.FindConstructors(type).Any())
.As<IProcessor>();
builder.RegisterAssemblyTypes(assembly)
.As<IProcessorConsumer>();
using (var container = builder.Build())
{
// Resolve
var processorConsumer = container.Resolve<IProcessorConsumer>();
Assert.IsInstanceOfType(processorConsumer, typeof(ProcessorConsumer));
Assert.IsInstanceOfType(processorConsumer.Processor, expectedProcessorType);
// Run
// TODO
}
However, I find this to be rather cumbersome and was hoping for something more built into an IoC container.
Now, I'm not saying this is the right way to do this. However, it may be another option if you are using Autofac. This assumes that you are happy for the registration delegate to call GetSettings at the point you try and resolve the IProcessorConsumer. If you are able to do that, you can do what you want in the registration, as below:
var cb = new ConatainerBuilder();
cb.Register(c =>
{
var settings = GetSettings();
if(settings is FooSettings)
return new FooProcessor((FooSettings)settings);
else if(settings is BarSettings)
return new BarProcessor((BarSettings)settings);
else
throw new NotImplementedException("Hmmm. Got some new fangled settings.");
}).As<IProcessor>();
//Also need to register IProcessorConsumer
Note: This code may be wrong as I can't try it right now.
Here is as close as you can get to a proper factory method. But there are some issues. First, here's the code; then we'll talk.
public class FooSettings
{
public int FooNumber { get; set; }
public string FooString { get; set; }
}
public class BarSettings
{
public int BarNumber { get; set; }
public string BarString { get; set; }
}
public interface IProcessor
{
void Process();
}
public class FooProcessor : IProcessor
{
public FooProcessor(FooSettings settings) { }
public void Process() { }
}
public class BarProcessor : IProcessor
{
public BarProcessor(BarSettings settings) { }
public void Process() { }
}
public interface IProcessorFactory
{
IProcessor GetProcessor(object settings);
}
public interface IProcessorConsumer { }
public class ProcessorConsumer : IProcessorConsumer
{
private IProcessorFactory _processorFactory;
private object _settings;
public ProcessorConsumer(IProcessorFactory processorFactory, object settings)
{
_processorFactory = processorFactory;
_settings = settings;
}
public void MyLogic()
{
IProcessor processor = _processorFactory.GetProcessor(_settings);
processor.Process();
}
}
public class ExampleProcessorFactory : IProcessorFactory
{
public IProcessor GetProcessor(object settings)
{
IProcessor p = null;
if (settings is BarSettings)
{
p = new BarProcessor(settings as BarSettings);
}
else if (settings is FooSettings)
{
p = new FooProcessor(settings as FooSettings);
}
return p;
}
}
So what's the issue? It's the different types of settings that you're giving to your factory method. Sometimes it's FooSettings and sometimes it's BarSettings. Later, it might be xxxSettings. Each new type will force a recompilation. If you had a common Settings class, this would not be the case.
The other issue? Your consumer gets passed the factory and the settings and uses that to get the correct processor. If you have someone passing these to your consumer, just have that entity call GetProcessor on the Factory and pass the resulting IProcessor to the consumer.
I think the issue is that you haven't actually specified in any structured way how to resolve a processor from a settings instance. How about making the settings object return the processor? That seems to be the right place to put this information:
public interface ISettings
{
IProcessor GetProcessor();
}
Each implementation must resolve its own processor implementation:
public class FooSettings : ISettings
{
//this is where you are linking the settings type to its processor type
public IProcessor GetProcessor() { return new FooProcessor(this); }
}
And any code needing a processor gets it from the settings object, which you can reference from the consumer constructor:
var consumer = new ProcessorConsumer(Settings.GetProcessor());

Categories

Resources