DataContractJsonSerializer - share an object instance for the whole graph? - c#

I am using a DataContractJsonSerializer to serialize an object graph. When I construct the objects, each receives a reference to an instance of a utility object (it's a factory, for creating instances of subclasses of an abstract contract class) - which works great until the graph is serialized and then deserialized again, whereupon the objects no longer have a reference to the utility object any more. I need this reference. How would you recommend I implement this (singletons don't work because separate graphs need their own instance of the object)?

Another way to accomplish is to introduce a thread static or thread local factory object, then populate your classes with it using an [OnDeserializing] callback.
Thus, if you define your types as follows:
public interface IFactory
{
}
public class Factory : IFactory
{
}
public interface IHasFactory
{
IFactory Factory { get; }
}
[DataContract]
public abstract class HasFactoryBase : IHasFactory
{
[ThreadStatic]
static IFactory deserializedFactory;
static IFactory DeserializedFactory
{
get
{
return deserializedFactory;
}
set
{
deserializedFactory = value;
}
}
public static IDisposable SetDeserializedFactory(IFactory factory)
{
return new PushValue<IFactory>(factory, () => DeserializedFactory, val => DeserializedFactory = val);
}
IFactory factory;
public IFactory Factory { get { return factory; } }
public HasFactoryBase(IFactory factory)
{
this.factory = factory;
}
[OnDeserializing]
void OnDeserializing(StreamingContext context)
{
this.factory = DeserializedFactory;
}
}
public struct PushValue<T> : IDisposable
{
Action<T> setValue;
T oldValue;
public PushValue(T value, Func<T> getValue, Action<T> setValue)
{
if (getValue == null || setValue == null)
throw new ArgumentNullException();
this.setValue = setValue;
this.oldValue = getValue();
setValue(value);
}
#region IDisposable Members
// By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
public void Dispose()
{
if (setValue != null)
setValue(oldValue);
}
#endregion
}
[DataContract]
public class Foo : HasFactoryBase
{
public Foo(IFactory factory)
: base(factory)
{
this.Bars = new List<Bar>();
}
[DataMember]
public List<Bar> Bars { get; set; }
}
[DataContract]
public class Bar : HasFactoryBase
{
public Bar(IFactory factory) : base(factory) { }
}
You can serialize and deserialize as follows:
var factory = new Factory();
var test = new Foo(factory)
{
Bars = { new Bar(factory) },
};
var serializer = new DataContractJsonSerializer(test.GetType());
byte [] json;
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, test);
json = stream.ToArray();
}
Foo test2;
using (HasFactoryBase.SetDeserializedFactory(factory))
using (var stream = new MemoryStream(json))
{
test2 = (Foo)serializer.ReadObject(stream);
}
if (test2.Factory != test.Factory)
throw new InvalidOperationException();
And the JSON will look like:
{
"Bars": [
{}
]
}
Some notes:
The factory object does not appear at all in the JSON.
The factory objects no longer need to inherit from some abstract base class, they can simply implement a common IFactory interface.

One way to accomplish this is with a data contract surrogate. Using surrogates, you can replace your "real" factory with a dummy stub during serialization. Then, during deserialization, replace the dummy with the desired factory.
Thus, if your classes look something like:
public abstract class FactoryBase
{
}
public class Factory : FactoryBase
{
}
public interface IHasFactory
{
FactoryBase Factory { get; }
}
[DataContract]
public abstract class HasFactoryBase : IHasFactory
{
[DataMember(IsRequired = true)]
FactoryBase factory;
public FactoryBase Factory { get { return factory; } }
public HasFactoryBase(FactoryBase factory)
{
this.factory = factory;
}
}
[DataContract]
public class Foo : HasFactoryBase
{
public Foo(FactoryBase factory)
: base(factory)
{
this.Bars = new List<Bar>();
}
[DataMember]
public List<Bar> Bars { get; set; }
}
[DataContract]
public class Bar : HasFactoryBase
{
public Bar(FactoryBase factory) : base(factory) { }
}
You define an IDataContractSurrogate to replace all occurrences of FactoryBase with a surrogate as follows:
public class FactorySurrogateSelector : IDataContractSurrogate
{
[DataContract]
class FactorySurrogate
{
}
readonly FactoryBase factory;
public FactorySurrogateSelector(FactoryBase factory)
{
this.factory = factory;
}
#region IDataContractSurrogate Members
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
throw new NotImplementedException();
}
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
{
throw new NotImplementedException();
}
public Type GetDataContractType(Type type)
{
if (typeof(FactoryBase).IsAssignableFrom(type))
return typeof(FactorySurrogate);
return type;
}
public object GetDeserializedObject(object obj, Type targetType)
{
if (obj is FactorySurrogate)
return factory;
return obj;
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
throw new NotImplementedException();
}
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj is FactoryBase)
{
return new FactorySurrogate();
}
return obj;
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
throw new NotImplementedException();
}
public System.CodeDom.CodeTypeDeclaration ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration, System.CodeDom.CodeCompileUnit compileUnit)
{
throw new NotImplementedException();
}
#endregion
}
Then, serialize and deserialize as follows:
var factory = new Factory();
var test = new Foo(factory)
{
Bars = { new Bar(factory) },
};
var surrogate = new FactorySurrogateSelector(factory);
var serializer = new DataContractJsonSerializer(test.GetType(), Enumerable.Empty<Type>(), int.MaxValue, false, surrogate, false);
byte[] json;
using (var stream = new MemoryStream())
{
serializer.WriteObject(stream, test);
json = stream.ToArray();
}
Foo test2;
using (var stream = new MemoryStream(json))
{
test2 = (Foo)serializer.ReadObject(stream);
}
if (test2.Factory != test.Factory)
throw new InvalidOperationException();
Notice that the desired factory was passed directly into the constructor of the FactorySurrogateSelector, then eventually set inside each type that contains instances of the factory type.
The resulting JSON will look like:
{
"factory": {},
"Bars": [
{
"factory": {}
}
]
}
Some qualifications:
Your factory must inherit from some common base class, here FactoryBase. The data contract serializers will never serialize an interface member, e.g. IFactory factory where IFactory is your factory interface, even when there is an applicable surrogate.
The empty "factory": {} objects must appear in the JSON in order for the surrogate to inject the correct "real" factory value during deserialization. Hence the [DataMember(IsRequired = true)].

Related

Deserializing a a dynamic type with custom object creation with Newtonsoft.Json

So let's say I have a:
List<IInterface> list;
that has been serialized with TypeNameHandling.Auto, so it has "dynamic" type information. I can deserialize it fine as Newtonsoft.Json can recognize the type from the $type and Json can use the correct constructor. So far so good.
Now say I want to override the creation converter with a mehtod:
CustomCreationConverter<IInterface>
that overrides the creation of the object:
public override IInterface Create(Type objectType)
At this point objectType will always be IInterface and not a derived implementation, so I have no way to create the correct object. The meta-information of $type is now lost.
Is there an elegant way to fix this?
Here would be an attempt that does not work:
public class CustomConverter : CustomCreationConverter<Example.IInterface> {
public override Example.IInterface Create(Type objectType) {
return Example.MakeObject(objectType); // this won't work, objectType will always be IInterface
}
}
public class Example {
public interface IInterface { };
public class A : IInterface { public int content; };
public class B : IInterface { public float data; };
public static IInterface MakeObject(Type t) {
if (t == typeof(IInterface)) {
throw new Exception();
}
return t == typeof(A) ? new A() : new B();
}
public static void Serialize() {
var settings = new JsonSerializerSettings() {
TypeNameHandling = TypeNameHandling.Auto
};
JsonSerializer serializer = JsonSerializer.Create(settings);
// serializer.Converters.Add(new CustomConverter()); // ?? can't have both, either CustomConverter or $type
List<IInterface> list = new() { MakeObject(typeof(A)), MakeObject(typeof(B)) };
using (StreamWriter sw = new("example.json")) {
serializer.Serialize(sw, list);
}
// Now read back example.json into a List<IInterface> using MakeObject
// Using CustomConverter won't work
using (JsonTextReader rd = new JsonTextReader(new StreamReader("example.json"))) {
List<IInterface> list2 = serializer.Deserialize<List<IInterface>>(rd);
}
}
}
Once you provide a custom converter such as CustomCreationConverter<T> for a type, the converter is responsible for all the deserialization logic including logic for type selection logic that would normally be implemented by TypeNameHandling. If you only want to inject a custom factory creation method and leave all the rest of the deserialization logic unchanged, you could create your own custom contract resolver and inject the factory method as JsonContract.DefaultCreator.
To implement this, first define the following factory interface and contract resolver:
public interface IObjectFactory<out T>
{
bool CanCreate(Type type);
T Create(Type type);
}
public class ObjectFactoryContractResolver : DefaultContractResolver
{
readonly IObjectFactory<object> factory;
public ObjectFactoryContractResolver(IObjectFactory<object> factory) => this.factory = factory ?? throw new ArgumentNullException(nameof(factory));
protected override JsonContract CreateContract(Type objectType)
{
var contract = base.CreateContract(objectType);
if (factory.CanCreate(objectType))
{
contract.DefaultCreator = () => factory.Create(objectType);
contract.DefaultCreatorNonPublic = false;
}
return contract;
}
}
Next, refactor your IInterface class hierarchy to make use of an IObjectFactory as an object creation factory:
public class InterfaceFactory : IObjectFactory<IInterface>
{
public InterfaceFactory(string runtimeId) => this.RuntimeId = runtimeId; // Some value to inject into the constructor
string RuntimeId { get; }
public bool CanCreate(Type type) => !type.IsAbstract && typeof(IInterface).IsAssignableFrom(type);
public IInterface Create(Type type) => type switch
{
var t when t == typeof(A) => new A(RuntimeId),
var t when t == typeof(B) => new B(RuntimeId),
_ => throw new NotImplementedException(type.ToString()),
};
}
public interface IInterface
{
public string RuntimeId { get; }
}
public class A : IInterface
{
[JsonIgnore] public string RuntimeId { get; }
internal A(string id) => this.RuntimeId = id;
public int content { get; set; }
}
public class B : IInterface
{
[JsonIgnore] public string RuntimeId { get; }
internal B(string id) => this.RuntimeId = id;
public float data { get; set; }
}
(Here RuntimeId is some value that needs to be injected during object creation.)
Now you will be able to construct your list as follows:
var valueToInject = "some value to inject";
var factory = new InterfaceFactory(valueToInject);
List<IInterface> list = new() { factory.Create(typeof(A)), factory.Create(typeof(B)) };
And serialize and deserialize as follows:
var resolver = new ObjectFactoryContractResolver(factory)
{
// Set any necessary properties e.g.
NamingStrategy = new CamelCaseNamingStrategy(),
};
var settings = new JsonSerializerSettings
{
ContractResolver = resolver,
TypeNameHandling = TypeNameHandling.Auto,
};
var json = JsonConvert.SerializeObject(list, Formatting.Indented, settings);
var list2 = JsonConvert.DeserializeObject<List<IInterface>>(json, settings);
Notes:
Newtosoft recommends that you cache and reuse your contract resolvers for best performance.
Newtonsoft also recommends that
TypeNameHandling should be used with caution when your application deserializes JSON from an external source. Incoming types should be validated with a custom SerializationBinder when deserializing with a value other than None.
For why, see e.g. TypeNameHandling caution in Newtonsoft Json or External json vulnerable because of Json.Net TypeNameHandling auto?.
Demo fiddle here.

Json.NET serialize by depth and attribute

For example we have two classes
class FooA
{
[SomeSpecialAttribute]
public int SomeValueA { get; set; }
public int SomeValueB { get; set; }
public int SomeValueC { get; set; }
}
class FooB
{
public FooA FooA { get; set; }
}
I use Json.NET, max depth is 1. While serializing FooA it should output all properties as usual, but while serializing FooB it should output only one FooA's property which has special attribute. So only while resolving nested reference properties (Depth > 0) we should get a single field.
Output should be: { "FooA": { "SomeValueA": "0" } }
Any ideas?
The basic difficulty here is that Json.NET is a contract-based serializer which creates a contract for each type to be serialized, then serializes according to the contract. No matter where a type appears in the object graph, the same contract applies. But you want to selectively include properties for a given type depending on its depth in the object graph, which conflicts with the basic "one type one contract" design and thus requires some work.
One way to accomplish what you want would be to create a JsonConverter that performs a default serialization for each object, then prunes undesired properties, along the lines of Generic method of modifying JSON before being returned to client. Note that this has problems with recursive structures such as trees, because the converter must disable itself for child nodes to avoid infinite recursion.
Another possibility would be to create a custom IContractResolver that returns a different contract for each type depending on the serialization depth. This must needs make use of serialization callbacks to track when object serialization begins and ends, since serialization depth is not made known to the contract resolver:
[System.AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
public class JsonIncludeAtDepthAttribute : System.Attribute
{
public JsonIncludeAtDepthAttribute()
{
}
}
public class DepthPruningContractResolver : IContractResolver
{
readonly int depth;
public DepthPruningContractResolver()
: this(0)
{
}
public DepthPruningContractResolver(int depth)
{
if (depth < 0)
throw new ArgumentOutOfRangeException("depth");
this.depth = depth;
}
[ThreadStatic]
static DepthTracker currentTracker;
static DepthTracker CurrentTracker { get { return currentTracker; } set { currentTracker = value; } }
class DepthTracker : IDisposable
{
int isDisposed;
DepthTracker oldTracker;
public DepthTracker()
{
isDisposed = 0;
oldTracker = CurrentTracker;
currentTracker = this;
}
#region IDisposable Members
public void Dispose()
{
if (0 == Interlocked.Exchange(ref isDisposed, 1))
{
CurrentTracker = oldTracker;
oldTracker = null;
}
}
#endregion
public int Depth { get; set; }
}
abstract class DepthTrackingContractResolver : DefaultContractResolver
{
static DepthTrackingContractResolver() { } // Mark type with beforefieldinit.
static SerializationCallback OnSerializing = (o, context) =>
{
if (CurrentTracker != null)
CurrentTracker.Depth++;
};
static SerializationCallback OnSerialized = (o, context) =>
{
if (CurrentTracker != null)
CurrentTracker.Depth--;
};
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
var contract = base.CreateObjectContract(objectType);
contract.OnSerializingCallbacks.Add(OnSerializing);
contract.OnSerializedCallbacks.Add(OnSerialized);
return contract;
}
}
sealed class RootContractResolver : DepthTrackingContractResolver
{
// As of 7.0.1, Json.NET suggests using a static instance for "stateless" contract resolvers, for performance reasons.
// http://www.newtonsoft.com/json/help/html/ContractResolver.htm
// http://www.newtonsoft.com/json/help/html/M_Newtonsoft_Json_Serialization_DefaultContractResolver__ctor_1.htm
// "Use the parameterless constructor and cache instances of the contract resolver within your application for optimal performance."
static RootContractResolver instance;
static RootContractResolver() { instance = new RootContractResolver(); }
public static RootContractResolver Instance { get { return instance; } }
}
sealed class NestedContractResolver : DepthTrackingContractResolver
{
static NestedContractResolver instance;
static NestedContractResolver() { instance = new NestedContractResolver(); }
public static NestedContractResolver Instance { get { return instance; } }
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
var property = base.CreateProperty(member, memberSerialization);
if (property.AttributeProvider.GetAttributes(typeof(JsonIncludeAtDepthAttribute), true).Count == 0)
{
property.Ignored = true;
}
return property;
}
}
public static IDisposable CreateTracker()
{
return new DepthTracker();
}
#region IContractResolver Members
public JsonContract ResolveContract(Type type)
{
if (CurrentTracker != null && CurrentTracker.Depth > depth)
return NestedContractResolver.Instance.ResolveContract(type);
else
return RootContractResolver.Instance.ResolveContract(type);
}
#endregion
}
Then mark your classes as follows:
class FooA
{
[JsonIncludeAtDepthAttribute]
public int SomeValueA { get; set; }
public int SomeValueB { get; set; }
public int SomeValueC { get; set; }
}
class FooB
{
public FooA FooA { get; set; }
}
And serialize as follows:
var settings = new JsonSerializerSettings { ContractResolver = new DepthPruningContractResolver(depth), Formatting = Formatting.Indented };
using (DepthPruningContractResolver.CreateTracker())
{
var jsonB = JsonConvert.SerializeObject(foob, settings);
Console.WriteLine(jsonB);
var jsonA = JsonConvert.SerializeObject(foob.FooA, settings);
Console.WriteLine(jsonA);
}
The slightly awkward CreateTracker() is needed to ensure that, in the event an exception is thrown partway through serialization, the current object depth gets reset and does not affect future calls to JsonConvert.SerializeObject().
This solution assumes you don't want to change all serialization of the FooA class. If this is the case, you should create your own JsonConverter.
public class FooConverter : JsonConverter
{
public FooConveter(params Type[] parameterTypes)
{
}
public override bool CanConvert(Type objectType)
{
return objectType.IsAssignableFrom(typeof(FooA));
}
public override object ReadJson(JsonReader reader, Type objectType)
{
//Put your code to deserialize FooA here.
//You probably don't need it based on the scope of your question.
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
//Code to serialize FooA.
if (value == null)
{
writer.WriteNull();
return;
}
//Only serialize SomeValueA
var foo = value as FooA;
writer.WriteStartObject();
writer.WritePropertyName("FooA");
writer.Serialize(writer, foo.SomeValueA);
writer.WriteEndObject();
}
}
And use your converter in your code as
class FooB
{
[FooConverter]
public FooA FooA { get; set; }
}
Otherwise, you can use the JsonIgnore attribute to ignore the fields in FooA that you don't want serialized. Keep in mind, the tradeoff there is that whenever you convert FooA to Json, it will always ignore fields marked with that attribute.

AutoFixture.AutoMoq supply a known value for one constructor parameter

I've just started to use AutoFixture.AutoMoq in my unit tests and I'm finding it very helpful for creating objects where I don't care about the specific value. After all, anonymous object creation is what it is all about.
What I'm struggling with is when I care about one or more of the constructor parameters. Take ExampleComponent below:
public class ExampleComponent
{
public ExampleComponent(IService service, string someValue)
{
}
}
I want to write a test where I supply a specific value for someValue but leave IService to be created automatically by AutoFixture.AutoMoq.
I know how to use Freeze on my IFixture to keep hold of a known value that will be injected into a component but I can't quite see how to supply a known value of my own.
Here is what I would ideally like to do:
[TestMethod]
public void Create_ExampleComponent_With_Known_SomeValue()
{
// create a fixture that supports automocking
IFixture fixture = new Fixture().Customize(new AutoMoqCustomization());
// supply a known value for someValue (this method doesn't exist)
string knownValue = fixture.Freeze<string>("My known value");
// create an ExampleComponent with my known value injected
// but without bothering about the IService parameter
ExampleComponent component = this.fixture.Create<ExampleComponent>();
// exercise component knowning it has my known value injected
...
}
I know I could do this by calling the constructor directly but this would no longer be anonymous object creation. Is there a way to use AutoFixture.AutoMock like this or do I need to incorporate a DI container into my tests to be able to do what I want?
EDIT:
I probably should have been less absract in my original question so here is my specific scenario.
I have an ICache interface which has generic TryRead<T> and Write<T> methods:
public interface ICache
{
bool TryRead<T>(string key, out T value);
void Write<T>(string key, T value);
// other methods not shown...
}
I'm implementing a CookieCache where ITypeConverter handles converting objects to and from strings and lifespan is used to set the expiry date of a cookie.
public class CookieCache : ICache
{
public CookieCache(ITypeConverter converter, TimeSpan lifespan)
{
// usual storing of parameters
}
public bool TryRead<T>(string key, out T result)
{
// read the cookie value as string and convert it to the target type
}
public void Write<T>(string key, T value)
{
// write the value to a cookie, converted to a string
// set the expiry date of the cookie using the lifespan
}
// other methods not shown...
}
So when writing a test for the expiry date of a cookie, I care about the lifespan but not so much about the converter.
So I'm sure people could work out the generalized implementation of Mark's suggestion but I thought I'd post it for comments.
I've created a generic ParameterNameSpecimenBuilder based on Mark's LifeSpanArg:
public class ParameterNameSpecimenBuilder<T> : ISpecimenBuilder
{
private readonly string name;
private readonly T value;
public ParameterNameSpecimenBuilder(string name, T value)
{
// we don't want a null name but we might want a null value
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentNullException("name");
}
this.name = name;
this.value = value;
}
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null)
{
return new NoSpecimen(request);
}
if (pi.ParameterType != typeof(T) ||
!string.Equals(
pi.Name,
this.name,
StringComparison.CurrentCultureIgnoreCase))
{
return new NoSpecimen(request);
}
return this.value;
}
}
I've then defined a generic FreezeByName extension method on IFixture which sets the customization:
public static class FreezeByNameExtension
{
public static void FreezeByName<T>(this IFixture fixture, string name, T value)
{
fixture.Customizations.Add(new ParameterNameSpecimenBuilder<T>(name, value));
}
}
The following test will now pass:
[TestMethod]
public void FreezeByName_Sets_Value1_And_Value2_Independently()
{
//// Arrange
IFixture arrangeFixture = new Fixture();
string myValue1 = arrangeFixture.Create<string>();
string myValue2 = arrangeFixture.Create<string>();
IFixture sutFixture = new Fixture();
sutFixture.FreezeByName("value1", myValue1);
sutFixture.FreezeByName("value2", myValue2);
//// Act
TestClass<string> result = sutFixture.Create<TestClass<string>>();
//// Assert
Assert.AreEqual(myValue1, result.Value1);
Assert.AreEqual(myValue2, result.Value2);
}
public class TestClass<T>
{
public TestClass(T value1, T value2)
{
this.Value1 = value1;
this.Value2 = value2;
}
public T Value1 { get; private set; }
public T Value2 { get; private set; }
}
You have to replace:
string knownValue = fixture.Freeze<string>("My known value");
with:
fixture.Inject("My known value");
You can read more about Inject here.
Actually the Freeze extension method does:
var value = fixture.Create<T>();
fixture.Inject(value);
return value;
Which means that the overload you used in the test actually called Create<T> with a seed: My known value resulting in "My known value4d41f94f-1fc9-4115-9f29-e50bc2b4ba5e".
You could do something like this. Imagine that you want to assign a particular value to the TimeSpan argument called lifespan.
public class LifespanArg : ISpecimenBuilder
{
private readonly TimeSpan lifespan;
public LifespanArg(TimeSpan lifespan)
{
this.lifespan = lifespan;
}
public object Create(object request, ISpecimenContext context)
{
var pi = request as ParameterInfo;
if (pi == null)
return new NoSpecimen(request);
if (pi.ParameterType != typeof(TimeSpan) ||
pi.Name != "lifespan")
return new NoSpecimen(request);
return this.lifespan;
}
}
Imperatively, it could be used like this:
var fixture = new Fixture();
fixture.Customizations.Add(new LifespanArg(mySpecialLifespanValue));
var sut = fixture.Create<CookieCache>();
This approach can be generalized to some degree, but in the end, we're limited by the lack of a strongly typed way to extract a ParameterInfo from a particular constructor or method argument.
I fee like #Nick was almost there. When overriding the constructor argument, it needs to be for the given type and have it limited to that type only.
First we create a new ISpecimenBuilder that looks at the "Member.DeclaringType" to keep the correct scope.
public class ConstructorArgumentRelay<TTarget,TValueType> : ISpecimenBuilder
{
private readonly string _paramName;
private readonly TValueType _value;
public ConstructorArgumentRelay(string ParamName, TValueType value)
{
_paramName = ParamName;
_value = value;
}
public object Create(object request, ISpecimenContext context)
{
if (context == null)
throw new ArgumentNullException("context");
ParameterInfo parameter = request as ParameterInfo;
if (parameter == null)
return (object)new NoSpecimen(request);
if (parameter.Member.DeclaringType != typeof(TTarget) ||
parameter.Member.MemberType != MemberTypes.Constructor ||
parameter.ParameterType != typeof(TValueType) ||
parameter.Name != _paramName)
return (object)new NoSpecimen(request);
return _value;
}
}
Next we create an extension method to allow us to easily wire it up with AutoFixture.
public static class AutoFixtureExtensions
{
public static IFixture ConstructorArgumentFor<TTargetType, TValueType>(
this IFixture fixture,
string paramName,
TValueType value)
{
fixture.Customizations.Add(
new ConstructorArgumentRelay<TTargetType, TValueType>(paramName, value)
);
return fixture;
}
}
Now we create two similar classes to test with.
public class TestClass<T>
{
public TestClass(T value1, T value2)
{
Value1 = value1;
Value2 = value2;
}
public T Value1 { get; private set; }
public T Value2 { get; private set; }
}
public class SimilarClass<T>
{
public SimilarClass(T value1, T value2)
{
Value1 = value1;
Value2 = value2;
}
public T Value1 { get; private set; }
public T Value2 { get; private set; }
}
Finally we test it with an extension of the original test to see that it will not override similarly named and typed constructor arguments.
[TestFixture]
public class AutoFixtureTests
{
[Test]
public void Can_Create_Class_With_Specific_Parameter_Value()
{
string wanted = "This is the first string";
string wanted2 = "This is the second string";
Fixture fixture = new Fixture();
fixture.ConstructorArgumentFor<TestClass<string>, string>("value1", wanted)
.ConstructorArgumentFor<TestClass<string>, string>("value2", wanted2);
TestClass<string> t = fixture.Create<TestClass<string>>();
SimilarClass<string> s = fixture.Create<SimilarClass<string>>();
Assert.AreEqual(wanted,t.Value1);
Assert.AreEqual(wanted2,t.Value2);
Assert.AreNotEqual(wanted,s.Value1);
Assert.AreNotEqual(wanted2,s.Value2);
}
}
This seems to be the most comprehensive solution set here. So I'm going to add mine:
The first thing to create ISpecimenBuilder that can handle multiple constructor parameters
internal sealed class CustomConstructorBuilder<T> : ISpecimenBuilder
{
private readonly Dictionary<string, object> _ctorParameters = new Dictionary<string, object>();
public object Create(object request, ISpecimenContext context)
{
var type = typeof (T);
var sr = request as SeededRequest;
if (sr == null || !sr.Request.Equals(type))
{
return new NoSpecimen(request);
}
var ctor = type.GetConstructors(BindingFlags.Instance | BindingFlags.Public).FirstOrDefault();
if (ctor == null)
{
return new NoSpecimen(request);
}
var values = new List<object>();
foreach (var parameter in ctor.GetParameters())
{
if (_ctorParameters.ContainsKey(parameter.Name))
{
values.Add(_ctorParameters[parameter.Name]);
}
else
{
values.Add(context.Resolve(parameter.ParameterType));
}
}
return ctor.Invoke(BindingFlags.CreateInstance, null, values.ToArray(), CultureInfo.InvariantCulture);
}
public void Addparameter(string paramName, object val)
{
_ctorParameters.Add(paramName, val);
}
}
Then create extension method that simplifies usage of created builder
public static class AutoFixtureExtensions
{
public static void FreezeActivator<T>(this IFixture fixture, object parameters)
{
var builder = new CustomConstructorBuilder<T>();
foreach (var prop in parameters.GetType().GetProperties())
{
builder.Addparameter(prop.Name, prop.GetValue(parameters));
}
fixture.Customize<T>(x => builder);
}
}
And usage:
var f = new Fixture();
f.FreezeActivator<UserInfo>(new { privateId = 15, parentId = (long?)33 });
Good thread, I added another twist based on many of the aswers already posted:
Usage
Example:
var sut = new Fixture()
.For<AClass>()
.Set("value1").To(aInterface)
.Set("value2").ToEnumerableOf(22, 33)
.Create();
Test classes:
public class AClass
{
public AInterface Value1 { get; private set; }
public IEnumerable<int> Value2 { get; private set; }
public AClass(AInterface value1, IEnumerable<int> value2)
{
Value1 = value1;
Value2 = value2;
}
}
public interface AInterface
{
}
Full test
public class ATest
{
[Theory, AutoNSubstituteData]
public void ATestMethod(AInterface aInterface)
{
var sut = new Fixture()
.For<AClass>()
.Set("value1").To(aInterface)
.Set("value2").ToEnumerableOf(22, 33)
.Create();
Assert.True(ReferenceEquals(aInterface, sut.Value1));
Assert.Equal(2, sut.Value2.Count());
Assert.Equal(22, sut.Value2.ElementAt(0));
Assert.Equal(33, sut.Value2.ElementAt(1));
}
}
Infrastructure
Extension method:
public static class AutoFixtureExtensions
{
public static SetCreateProvider<TTypeToConstruct> For<TTypeToConstruct>(this IFixture fixture)
{
return new SetCreateProvider<TTypeToConstruct>(fixture);
}
}
Classes participating in the fluent style:
public class SetCreateProvider<TTypeToConstruct>
{
private readonly IFixture _fixture;
public SetCreateProvider(IFixture fixture)
{
_fixture = fixture;
}
public SetProvider<TTypeToConstruct> Set(string parameterName)
{
return new SetProvider<TTypeToConstruct>(this, parameterName);
}
public TTypeToConstruct Create()
{
var instance = _fixture.Create<TTypeToConstruct>();
return instance;
}
internal void AddConstructorParameter<TTypeOfParam>(ConstructorParameterRelay<TTypeToConstruct, TTypeOfParam> constructorParameter)
{
_fixture.Customizations.Add(constructorParameter);
}
}
public class SetProvider<TTypeToConstruct>
{
private readonly string _parameterName;
private readonly SetCreateProvider<TTypeToConstruct> _father;
public SetProvider(SetCreateProvider<TTypeToConstruct> father, string parameterName)
{
_parameterName = parameterName;
_father = father;
}
public SetCreateProvider<TTypeToConstruct> To<TTypeOfParam>(TTypeOfParam parameterValue)
{
var constructorParameter = new ConstructorParameterRelay<TTypeToConstruct, TTypeOfParam>(_parameterName, parameterValue);
_father.AddConstructorParameter(constructorParameter);
return _father;
}
public SetCreateProvider<TTypeToConstruct> ToEnumerableOf<TTypeOfParam>(params TTypeOfParam[] parametersValues)
{
IEnumerable<TTypeOfParam> actualParamValue = parametersValues;
var constructorParameter = new ConstructorParameterRelay<TTypeToConstruct, IEnumerable<TTypeOfParam>>(_parameterName, actualParamValue);
_father.AddConstructorParameter(constructorParameter);
return _father;
}
}
Constructor parameter relay from other answers:
public class ConstructorParameterRelay<TTypeToConstruct, TValueType> : ISpecimenBuilder
{
private readonly string _paramName;
private readonly TValueType _paramValue;
public ConstructorParameterRelay(string paramName, TValueType paramValue)
{
_paramName = paramName;
_paramValue = paramValue;
}
public object Create(object request, ISpecimenContext context)
{
if (context == null)
throw new ArgumentNullException(nameof(context));
ParameterInfo parameter = request as ParameterInfo;
if (parameter == null)
return new NoSpecimen();
if (parameter.Member.DeclaringType != typeof(TTypeToConstruct) ||
parameter.Member.MemberType != MemberTypes.Constructor ||
parameter.ParameterType != typeof(TValueType) ||
parameter.Name != _paramName)
return new NoSpecimen();
return _paramValue;
}
}

How to define which class is taken if an interface property is deserialized within a class?

Just imagine you have the following class
[DataContract]
public class NamedList
{
[DataMember]
public string Name { get; set; }
[DataMember]
public IList<string> Items { get; private set; }
public DumpList(string name)
{
Name = name;
Items = new List<string>();
}
}
If you serialize this into a file, it is quite easy, cause the concrete class behind the IList is known and can be serialized.
But what happens if you try to deserialize this file back into memory?
It works without any direct error occuring.
The problem comes if you try to add or remove something from the list. In that case you'll get an exception. And the root of this exception comes from the case that the deserialized object uses as concrete implementation for the IList an Array.
To avoid this problem in this simple example is easy. Just serialize the concrete backing store instead of the public property and make the change in the constructor:
[DataMember(Name = "Items")]
private List<string> _Items;
public IList<string> Items
{
get
{
return _Items;
}
}
public DumpList(string name)
{
Name = name;
_Items = new List<string>();
}
But the more interesting question is:
Why chooses the Deserializer the Array type as concrete implementation of the IList interface?
Is it possible to change the settings which class should be taken for each interface?
If i have a self defined interface and several implementations of this interface, is it possible to tell the Deserializer which concrete class should be taken for a given interface?
You can solve this using a DataContractSurrogate for the deserialization, that replaces IList with List.
public class CustomDataContractSurrogate : IDataContractSurrogate
{
// The only function you should care about here. The rest don't do anything, just default behavior.
public Type GetDataContractType(Type type)
{
if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(ICollection<>)))
{
return (typeof(List<>).MakeGenericType(type.GetGenericArguments().Single()));
}
return type;
}
public object GetObjectToSerialize(object obj, Type targetType)
{
return obj;
}
public object GetDeserializedObject(object obj, Type targetType)
{
return obj;
}
public object GetCustomDataToExport(MemberInfo memberInfo, Type dataContractType)
{
return null;
}
public object GetCustomDataToExport(Type clrType, Type dataContractType)
{
return null;
}
public void GetKnownCustomDataTypes(Collection<Type> customDataTypes)
{
}
public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object customData)
{
return null;
}
public CodeTypeDeclaration ProcessImportedType(CodeTypeDeclaration typeDeclaration, CodeCompileUnit compileUnit)
{
return typeDeclaration;
}
}
Basically that's it, you just need to create your DataContractSerializer instance with that surrogate and use it for deserialization (for serialization it won't matter), for example:
var serializer = new DataContractSerializer(type, new Type[]{}, Int32.MaxValue, false, true, new CustomDataContractSurrogate());
Or any of the other constructors that take a surrogate.
Or, (as a bonus to the answer) if you're working with app/web.config-defined services, you can define a custom behavior that creates a data contract serializer with the above surrogate:
public class CustomDataContractSerializerBehavior : DataContractSerializerOperationBehavior
{
public CustomDataContractSerializerBehavior(OperationDescription operation)
: base(operation)
{
}
public CustomDataContractSerializerBehavior(OperationDescription operation, DataContractFormatAttribute dataContractFormatAttribute)
: base(operation, dataContractFormatAttribute)
{
}
public override XmlObjectSerializer CreateSerializer(Type type, string name, string ns,
IList<Type> knownTypes)
{
return new DataContractSerializer(type, knownTypes, Int32.MaxValue, false, true, new CustomDataContractSurrogate());
}
public override XmlObjectSerializer CreateSerializer(Type type, XmlDictionaryString name,
XmlDictionaryString ns, IList<Type> knownTypes)
{
return new DataContractSerializer(type, knownTypes, Int32.MaxValue, false, true, new CustomDataContractSurrogate());
}
}
Finally you can use this behavior:
public static IMyDataServiceContract CreateService()
{
var factory = new ChannelFactory<IMyDataServiceContract>("MyServiceName");
SetDataContractSerializerBehavior(factory.Endpoint.Contract);
return factory.CreateChannel();
}
private static void SetDataContractSerializerBehavior(ContractDescription contractDescription)
{
foreach (OperationDescription operation in contractDescription.Operations)
{
ReplaceDataContractSerializerOperationBehavior(operation);
}
}
private static void ReplaceDataContractSerializerOperationBehavior(OperationDescription description)
{
DataContractSerializerOperationBehavior dcsOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsOperationBehavior != null)
{
description.Behaviors.Remove(dcsOperationBehavior);
description.Behaviors.Add(new CustomDataContractSerializerBehavior(description));
}
}
To finish the job, call the above CreateService somewhere to create the channel.
If you use the NetDataContractSerializer, which stores type information along with the serialized object, your problem should be solved. However, it does at the same time reduce interoperability to non-.NET clients.

Constraint parameters, new()

Is there any way to move the Parse method into the abstract class ? I tried multiple ways (links at the bottom), but I am still hitting one or another roadblock.
public class AnimalEntityId : EntityId<AnimalEntityId>
{
public AnimalEntityId()
: base()
{
}
private AnimalEntityId(string value)
: base(value)
{
}
public static AnimalEntityId Parse(string value)
{
return new AnimalEntityId(value);
}
}
public abstract class EntityId<TEntityId>
{
private readonly System.Guid value;
protected EntityId(string value)
{
this.value = System.Guid.Parse(value);
}
protected EntityId()
{
this.value = System.Guid.NewGuid();
}
}
Tried these suggestions with no luck:
Passing arguments to C# generic new() of templated type
Is there a generic constructor with parameter constraint in C#?
https://social.msdn.microsoft.com/Forums/en-US/fd43d184-0503-4d4a-850c-999ca58e1444/creating-generic-t-with-new-constraint-that-has-parameters?forum=csharplanguage
http://www.gamedev.net/topic/577668-c-new-constraint--is-it-possible-to-add-parameters/
Thanks in advance!
If you don't mind using reflection, you can move Parse into the abstract type like this:
public static TEntityId Parse(string val) {
var constr = typeof(TEntityId).GetConstructor(
// Since the constructor is private, you need binding flags
BindingFlags.Instance | BindingFlags.NonPublic
, null
, new[]{ typeof(string) }
, null);
if (constr == null) {
throw new InvalidOperationException("No constructor");
}
return (TEntityId)constr.Invoke(new object[] {val});
}
Demo.
No, you cannot write a template constraint such as new(string) instead of simply new(). You'll have to leverage reflection to get it to work:
public abstract class EntityId<TEntityId>
where TEntityId : EntityId<TEntityId>
{
private readonly System.Guid value;
protected EntityId(string value)
{
this.value = System.Guid.Parse(value);
}
protected EntityId()
{
this.value = System.Guid.NewGuid();
}
public static TEntityId Parse(string value)
{
return (TEntityId)Activator.CreateInstance(typeof(TEntityId), new object[] { value });
}
}
Assuming you make the constructor accessible (instead of it currently being private). Note the constraint where TEntityId : EntityId<TEntityId> - which will ensure we'll only return subclasses of EntityId
How about making value a private mutable field/property and actually setting it from the Parse method?
(Curiously recurring generic parameter removed from EntityId for simplicity)
public class SimpleAnimalEntityId : EntityId
{
// Implicit parameterless constructor.
}
public class ParametrizedAnimalEntityId : EntityId
{
// Parametrized constructor only.
public ParametrizedAnimalEntityId(int ignored)
{
}
}
public abstract class EntityId
{
// Simple scenario: derived type has a parameterless constructor.
public static TEntity Parse<TEntity>(string value)
where TEntity : EntityId, new()
{
Guid id = Guid.Parse(value);
return new TEntity { value = id };
}
// Advanced scenario: derived type constructor needs parameters injected.
public static TEntity Parse<TEntity>(string value, Func<TEntity> constructor)
where TEntity : EntityId
{
Guid id = Guid.Parse(value);
TEntity entity = constructor();
entity.value = id;
return entity;
}
private Guid value;
protected EntityId()
{
value = Guid.NewGuid();
}
}
Now you can handle any constructor from your Parse method:
string id = Guid.NewGuid().ToString();
SimpleAnimalEntityId simple = EntityId.Parse<SimpleAnimalEntityId>(id);
ParametrizedAnimalEntityId parametrized = EntityId.Parse(id, () => new ParametrizedAnimalEntityId(42));

Categories