I need some help transitioning from ValueInjecter to EmitMapper (I've decided so for performance reasons). My use case is one of the most common ones: mapping a Model object to a DTO, based on some rules.
One of this rules is: if a property's type is a subclass of DomainObject, then it should be mapped it to its correspondent DTO. With concrete types that's ok, but I also want it to work with abstract types. The problem is that I don't how to tell EmitMapper which DTO should be used, in a dynamic fashion.
In ValueInjecter code:
public bool IsDomainObjectAndTargetIsDto(ConventionInfo it)
{
return it.SourceProp.Value.IsNotNull()
&& typeof(DomainObject).IsAssignableFrom(it.SourceProp.Type)
&& it.TargetProp.Type.Name.EndsWith("DTO");
}
As all of my DTOs implements DTO<> interface, I thought I could use EmitMapper's DefaultMapConfig.ConvertGeneric method but I just can't figure out how.
Just for completeness, I include my current (not working) code:
public class ModelToDtoConventions()
{
public IMappingConfigurator GetConfig()
{
return new DefaultMapConfig()
.ConvertUsing<IdentificableObject, int>(o => o.Id)
.ConvertGeneric(
typeof (DomainObject),
typeof (DTO<>),
new DefaultCustomConverterProvider(
typeof (DomainObjectToDtoConverter<>)
)
);
}
}
public class DomainObjectToDtoConverter<TDomainObject>
{
public DTO<TDomainObject> Convert(TDomainObject from, object state)
{
return (DTO<TDomainObject>)this.CreateDtoFor(#from);
}
private object CreateDtoFor(object modelObject)
{
var modelType = modelObject.GetType();
var dtoInterface = typeof(DTO<>).MakeGenericType(modelType);
var dtoType = dtoInterface
.GetConcreteSubtypes()
.Single();
return Activator.CreateInstance(dtoType);
}
}
When I try to use this mapping on a test, I'm getting the following exception
'MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model' failed: System.ArgumentException : Cannot bind to the target method because its signature or security transparency is not compatible with that of the delegate type.
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method, Boolean throwOnBindFailure)
at System.Delegate.CreateDelegate(Type type, Object firstArgument, MethodInfo method)
at EmitMapper.MappingConfiguration.MapConfigBaseImpl.GetGenericConverter(Type from, Type to)
at EmitMapper.MappingConfiguration.MapConfigBaseImpl.FilterOperations(Type from, Type to, IEnumerable`1 operations)
at EmitMapper.MappingConfiguration.DefaultMapConfig.GetMappingOperations(Type from, Type to)
at EmitMapper.EmitBuilders.MappingBuilder.BuildCopyImplMethod()
at EmitMapper.ObjectMapperManager.BuildObjectsMapper(String MapperTypeName, Type from, Type to, IMappingConfigurator mappingConfigurator)
at EmitMapper.ObjectMapperManager.GetMapperInt(Type from, Type to, IMappingConfigurator mappingConfigurator)
at EmitMapper.ObjectMapperManager.GetMapperImpl(Type from, Type to, IMappingConfigurator mappingConfigurator)
at MyProject.WebApi.Adapters.DTOInjector.Transform[TDestination](IMappingConfigurator config, Object source, TDestination destination) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 56
at MyProject.WebApi.Adapters.DTOInjector.CreateDto[TDTO](Object entity) in c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs:line 47
at MyProject.WebApi.Test.Utils.DTOInjectorTest.Abstract_DTO_property_of_DTO_can_be_mapped_from_its_model() in c:\Users\faloi\Documents\GitHub\api\WebApi.Test\Utils\DTOInjectorTest.cs:line 334 c:\Users\faloi\Documents\GitHub\api\WebApi\Adapters\DTOInjector.cs 56
EDIT: this is an example of objects that I'd like to map.
//Domain objects
public class Game
{
public IEnumerable<Map> Maps { get; set; }
public Map MostPlayedMap { get; set; }
public Game()
{
this.Maps = new List<Map>();
}
}
public abstract class Map : DomainObject
{
public string Name { get; set; }
}
public class BombDefuseMap : Map
{
public Player BombHolder { get; set; }
}
public class HostageRescueMap : Map
{
public int QuantityOfHostages { get; set; }
}
//DTOs
public class GameDTO : DTOWithId<Game>
{
public List<MapDTO> Maps { get; set; }
public MapDTO MostPlayedMap { get; set; }
}
public abstract class MapDTO
{
public string Name { get; set; }
}
public class BombDefuseMapDTO : MapDTO, DTO<BombDefuseMap>
{
public int BombHolder { get; set; }
}
public class HostageRescueMapDTO : MapDTO, DTO<HostageRescueMap>
{
public int QuantityOfHostages { get; set; }
}
if you're concerned about performance have a look at this page:
http://valueinjecter.codeplex.com/wikipage?title=SmartConventionInjection
it's an injections that performs much better but you don't get the value in the matching algorithm,
most times you don't need it anyway
Related
I need to have something like this. So a class that implements this Interface needs to get a property with the same type as the class.
Is this even possible, ifso how? I'm using .net 6.
public interface IProperty
{
public typeof(this) parameter { get; } // doesn't work, can't use typeof()
}
public class clsResourceProperty : IProperty
{
public clsResourceProperty parameter { get; }
}
public class clsInterfaceProperty : IProperty
{
public clsInterfaceProperty parameter { get; }
}
I know how to use generic interfaces, and with the second example it works, but clsResourcePropertyGeneric: IPropertyGeneric looks strange. And doens't work for the application i need.
public interface IPropertyGeneric<T>
{
public T parameter { get; }
}
public class clsResourcePropertyGeneric: IPropertyGeneric<clsResourcePropertyGeneric>
{
public clsResourcePropertyGeneric parameter { get; }
}
public class clsInterfacePropertyGeneric: IPropertyGeneric<clsInterfacePropertyGeneric>
{
public clsInterfacePropertyGeneric parameter { get; }
}
In the application i need, i need to have a class containing a list of this interface. So something like this:
public class clsState
{
public List<IProperty> data {get; private set;}
public clsState(List<IProperty> data)
{
this.data = data;
}
public void logic()
{
foreach(var d in data)
{
//do something with d.parameters
}
}
}
But this doesn't work with the generic interface. I need to make a class containing a list of this interface, where i define the generic type T. But this list can't contain ALL classes which implement this interface
public class clsState<T>
// need to add T here to use it in the list, but the list needs to contain ALL implementing class types, not only 1
{
public List<IProperty<T>> data {get; private set;}
public clsState(List<IProperty<T>> data)
{
this.data = data;
}
public void logic()
{
foreach(var d in data)
{
//do something with d.parameters
}
}
}
I found this link, but this is from 7 years ago, so maybe there is some evolution in this aspect?
You can use the interface as your property type, as in:
public interface IProperty
{
public IProperty parameter { get; }
}
public class clsResourceProperty : IProperty
{
public IProperty parameter { get; }
}
public class clsInterfaceProperty : IProperty
{
public IProperty parameter { get; }
}
As for having a collection of the interfaces, it is possible to collect all of the classes for a particular type or interface. This is from a piece of code in one of my libraries. It doesn't do exactly what you're after, but it might be a step towards your final solution.
private static Type[] strategyTypes;
private readonly static Type[] obsoleteTypes = new Type[]
{
};
static StrategyRepository()
{
strategyTypes = Assembly.GetExecutingAssembly().GetTypes()
.Where(t => t.BaseType == typeof(Strategy))
.Except(obsoleteTypes)
.ToArray();
}
This question might be a more direct answer to that part of your question: Getting all types that implement an interface
I am looking for an elegant way of statically referencing a property attribute in C#. To give you an example, say I have this class:
public class A
{
[Attribute(Name="myAttributeName")]
public string Property1 { get; set; }
}
Now, I see the attribute as quite similar to a static member of a class, so in my mind, there should be an easy way to access the attribute from outside the class; e.g. through a similar operator to typeof or nameof (but it would return a list of attributes, since there may be multiple attributes to fetch). The way I would like to use this operator is as follows:
public class B
{
// Through an attribute definition
[Attribute2(attrof(A.Property1))]
public string Property2 { get; set; }
// In a method
public void method()
{
var attrs = attrof(A.property1);
}
}
I think I have found one way to make it work with two parameters like the example below - at least for the method invocation. Passing variables to attributes doesn't seem to work in C#, but that's nevertheless the way I'd like to construct my code.
public class C
{
public static object[] GetAttrs(Type type, string propertyName)
{
return type.GetProperty(propertyName).GetCustomAttributes(true);
}
}
public class A
{
[Attribute1(Name="myAttributeName")]
public string Property1 { get; set; }
}
public class B
{
// Through an attribute definition
// Unfortunately, passing variable to attrs not supported
// so this does not work
[Attribute2(C.GetAttrs(typeof(A), nameof(A.Property1)))]
public string Property2 { get; set; }
// In a method
public void method()
{
var attrs = C.GetAttrs(typeof(A), nameof(A.Property1));
}
}
However, it feels tedious to pass references to both the class and property, when syntactically, A.Property1 contains information about both - something a compiler should be able to draw information from. Therefore, I wonder if any such operator exists today, or if there are any other ideas on how this functionality could be achieved?
EDIT: I just thought about the B.Property2 attribute definition one more time and thought that it should still be possible to get this working, since I think attributes are constant. Or am I missing something here?
There is no default operator for such case, but you could implement something similar. Code to extract value from A.Property1 attribute is in Main function
using System;
using System.Reflection;
namespace ConsoleApp16
{
public class CustomAttribute : Attribute
{
public string Name { get; }
public CustomAttribute(string name)
{
Name = name;
}
}
public class ReferenceAttribute : Attribute
{
public string PropertyName { get; }
public Type Type { get; }
public ReferenceAttribute(Type type, string propertyName)
{
Type = type;
PropertyName = propertyName;
}
}
public class A
{
[Custom("text")]
public string Property1 { get; set; }
}
public class B
{
[Reference(typeof(A), nameof(A.Property1))]
public string Property { get; set; }
}
class Program
{
static void Main(string[] args)
{
var referenceAttribute = typeof(B).GetProperty(nameof(B.Property))
.GetCustomAttribute<ReferenceAttribute>();
var customAttribute = referenceAttribute.Type.GetProperty(referenceAttribute.PropertyName)
.GetCustomAttribute<CustomAttribute>();
Console.WriteLine(customAttribute.Name);
}
}
}
I'm still fairly new to programming and have been tasked with creating a WebHook consumer that takes in a raw JSON string, parses the JSON into an object, which will be passed into a handler for processing. The JSON is coming in like this:
{
"id":"1",
"created_at":"2017-09-19T20:41:23.093Z",
"type":"person.created",
"object":{
"id":"person1",
"created_at":"2017-09-19T20:41:23.076Z",
"updated_at":"2017-09-19T20:41:23.076Z",
"firstname":"First",
...
}
}
The inner object can be any object so I thought this would be a great opportunity to use generics and built my class as follows:
public class WebHookModel<T> where T : class, new()
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty(PropertyName = "type")]
public string Type { get; set; }
[JsonProperty(PropertyName = "object")]
public T Object { get; set; }
[JsonIgnore]
public string WebHookAction
{
get
{
return string.IsNullOrEmpty(Type) ? string.Empty : Type.Split('.').Last();
}
}
}
Then created the following interface:
public interface IWebHookModelFactory<T> where T : class, new()
{
WebHookModel<T> GetWebHookModel(string type, string jsonPayload);
}
What I'm failing to understand is how am I supposed to implement the Factory class without knowing what the type is at compile time?
Playing around with the Model a bit, I changed it to an abstract class with an abstract T object so that it could be defined by a derived class.
public abstract class WebHookModel<T> where T : class, new()
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "created_at")]
public DateTime CreatedAt { get; set; }
[JsonProperty(PropertyName = "type")]
public string Type { get; set; }
[JsonProperty(PropertyName = "object")]
public abstract T Object { get; set; }
[JsonIgnore]
public string WebHookAction
{
get
{
return string.IsNullOrEmpty(Type) ? string.Empty : Type.Split('.').Last();
}
}
}
public PersonWebHookModel : WebHookModel<Person>
{
public override Person Object { get; set; }
}
But I still run into the same issue of trying to implement an interface in which I don't know the type at runtime. From what I've found online, this is an example of covariance, but I haven't found any articles that explain how to resolve this issue. Is it best to skip generics and create a massive
case statement?
public interface IWebHookFactory<TModel, TJsonObject>
where TJsonObject : class, new()
where TModel : WebHookModel<TJsonObject>
{
TModel GetWebHookModel(string type, string jsonPayload);
}
I'm a bit partial to using the abstract class approach because it lets me define individual handlers based on which model I'm passing into my Service.
public interface IWebHookService<TModel, TJsonObject>
where TJsonObject : class, new()
where TModel : WebHookModel<TJsonObject>
{
void CompleteAction(TModel webHookModel);
}
public abstract class BaseWebhookService<TModel, TJsonObject> : IWebHookService<TModel, TJsonObject>
where TJsonObject : class, new()
where TModel : WebHookModel<TJsonObject>
{
public void CompleteAction(TModel webHookModel)
{
var self = this.GetType();
var bitWise = System.Reflection.BindingFlags.IgnoreCase
| System.Reflection.BindingFlags.Instance
| System.Reflection.BindingFlags.NonPublic;
var methodToCall = self.GetMethod(jsonObject.WebHookAction, bitWise);
methodToCall.Invoke(this, new[] { jsonObject });
}
protected abstract void Created(TModel webHookObject);
protected abstract void Updated(TModel webHookObject);
protected abstract void Destroyed(TModel webHookObject);
}
public class PersonWebHookService : BaseWebHookService<PersonWebHookModel, Person>
{
protected override void Created(PersonWebHookModel webHookModel)
{
throw new NotImplementedException();
}
protected override void Updated(PersonWebHookModel webHookModel)
{
throw new NotImplementedException();
}
protected override void Destroyed(PersonWebHookModel webHookModel)
{
throw new NotImplementedException();
}
}
Key points for the solution:
1. There needs to be some virtual call in there somewhere.
2. Somehow you need to map from your type tag in your JSON payload to your actual C# class.
IE, "person.created"," --> 'Person'.
If you control the serialization format, JSON.Net can inject its own type tag and do this for you. Assuming you can't go that route ...
So you'll need something like a Dictionary to contain the mapping.
Assuming your definitions is like:
abstract class WebhookPayload // Note this base class is not generic!
{
// Common base properties here
public abstract void DoWork();
}
abstract class PersonPayload : WebhookPayload
{
public override void DoWork()
{
// your derived impl here
}
}
And then you can deserialize like:
static Dictionary<string, Type> _map = new Dictionary<string, Type>
{
{ "person.created", typeof(PersonPayload)}
}; // Add more entries here
public static WebhookPayload Deserialize(string json)
{
// 1. only parse once!
var jobj = JObject.Parse(json);
// 2. get the c# type
var strType = jobj["type"].ToString();
Type type;
if (!_map.TryGetValue(strType, out type))
{
// Error! Unrecognized type
}
// 3. Now deserialize
var obj = (WebhookPayload) jobj.ToObject(type);
return obj;
}
Given the following:
public class Foo
{
public Int32 Foo_PK { get; set; }
public String SomeProperty { get; set; }
}
public class Bar
{
public Int32 Bar_PK { get; set; }
public Int32 Foo_FK { get; set; }
public String SomeOtherProperty { get; set; }
}
public class JoinResult<TEntity, TJoiningEntity>
{
public TEntity From { get; private set; }
public TEntity To { get; private set; }
public JoinResult(TEntity from, TEntity to)
{
this.From = from;
this.To = to;
}
}
public interface IFooResult
{
public String SomeProperty { get; set; }
}
public interface IBarResult : IFooResult
{
public String SomeOtherProperty { get; set; }
}
public class FooResultDTO : IFooResult, IBarResult
{
public String SomeProperty { get; set; }
public String SomeOtherProperty { get; set; }
}
The idea behind this is that we some method of dispensing foo's and foo's with other related records, e.g. if there are 4 bar's then 4 rows in a table with the additional fields.
public class FooDispensary
{
public IQueryable<T> Dispense<T>()
where T: IFooResult
{
using (var repository = new Repository())
{
// TODO: Handle mapping for Foo -> FooResult
// Project to
return repository.Foos.ProjectTo<FooResultDTO>();
}
}
public IQueryable<T> DispenseWithBars<T>()
where T : IFooResult, IBarResult
{
using (var repository = new Repository())
{
// TODO: Handle mapping for JoinResult.From (same as Foo -> FooResult) as well as to JoinResult.To
// Project to
return repository.Foos.Join((f) => f.Foo_PK,
(b) => b.Foo_FK,
(f, b) => new JoinResult<Foo, Bar>(f, b))
.ProjectTo<FooResultDTO>();
}
}
}
However, I would ideally like to only specify the base mapping once (Foo -> IFooResult) and then re-use this in the methods where we need to join to a child table.
There are multiple reasons behind wanting to do this which are specific to my project however no need to go into them, I am just wondering if this is possible as I have struggled with the syntax thus far?
Thanks
Create a Map between Foo and FooResult. Because the Property SomeProperty is named the same in both the source and target Automapper will be able to figure out the mapping implicitly.
// TODO: Handle mapping for Foo -> FooResult
AutoMapper.Mapper.CreateMap<Foo, FooResult>();
Then create a map between JoinResult<Foo, Bar> and FooResultDTO
// TODO: Handle mapping for JoinResult.From (same as Foo -> FooResult) as well as to JoinResult.To
AutoMapper.Mapper.CreateMap<JoinResult<Foo, Bar>, FooResultDTO>()
.ForMember(r => r.SomeProperty, opt => opt.MapFrom(f => f.From.SomeProperty)
.ForMember(r => r.SomeOtherProperty, opt => opt.MapFrom(f => f.To.SomeOtherProperty)
However, I would ideally like to only specify the base mapping once (Foo -> IFooResult) and then re-use this in the methods where we need to join to a child table.
You're not resusing the mapping between Foo and IFooResult anywhere in your example. Your second function needs to map between JoinResult<Foo, Bar> and FooResultDTO as shown above. If you need to reuse mappings I suggest you look into using an AutoMapper Profile and managing a singleton AutoMapper instance that can be shared between your functions: https://github.com/AutoMapper/AutoMapper/wiki/Configuration
I'm trying to implement the ITableEntity interface so that I can add [DataContract] attribute on it. But if I implement this interface myself, I'll have to give the ReadEntity and WriteEntity methods a body.
But there is a class that already implements the ITableEntity interface and gave ReadEntity and WriteEntity methods a body, which is the TableEntity.cs.
How can I make my implementation of the interface use the methods in the TableEntity class?
[Edit]
[DataContract]
public class SerializableTableEntity : ITableEntity
{
private TableEntity tableEntity;
public string ETag { get; set; }
public string PartitionKey { get; set; }
public string RowKey { get; set; }
public DateTimeOffset Timestamp { get; set; }
public SerializableTableEntity()
{
tableEntity = new TableEntity();
}
public void ReadEntity(IDictionary<string, EntityProperty> properties, Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
tableEntity.ReadEntity(properties, operationContext);
}
public IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
return tableEntity.WriteEntity(operationContext);
}
}
The reason that every property in your stored table is blank is because WriteEntity and ReadEntity use the blank object to store and write the data.
You're delegating serialization of your object to 'tableEntity' but none of your properties are there.
Suggestion: you will need to implement all of your SerializableTableEntity's properties inside a class that derives from TableEntity, contain a variable of that type inside the SerializableTableEntity entity, and delegate every member's property get/set from SerializableTableEntity to this new object.
Does this make sense?
EDIT: Code sample as requested (you're not going to enjoy it though)
[DataContract]
public class SerializableTableEntity : ITableEntity
{
private CustomEntity tableEntity;
public string ETag {
{
get
{
return tableEntity.ETag;
}
set
{
tableEntity.Etag = value;
}
}
public string PartitionKey
{
get
{
return tableEntity.PartitionKey;
}
set
{
tableEntity.PartitionKey = value;
}
}
public string RowKey
{
get
{
return tableEntity.RowKey;
}
set
{
tableEntity.RowKey = value;
}
}
public DateTimeOffset Timestamp
{
get
{
return tableEntity.Timestamp;
}
set
{
tableEntity.Timestamp = value;
}
}
public string PropertyOne
{
get
{
return tableEntity.PropertyOne;
}
set
{
tableEntity.PropertyOne = value;
}
}
public SerializableTableEntity()
{
tableEntity = new CustomEntity();
}
public void ReadEntity(IDictionary<string, EntityProperty> properties, Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
tableEntity.ReadEntity(properties, operationContext);
}
public IDictionary<string, EntityProperty> WriteEntity(Microsoft.WindowsAzure.Storage.OperationContext operationContext)
{
return tableEntity.WriteEntity(operationContext);
}
}
public class CustomEntity : TableEntity
{
public string PropertyOne { get; set; }
}
I ended up creating exact copy of these classes and made them Serializable. But being able to do some complex queries seems to be a challenge as well. So we moved to SQL Database.
Either delegate the "uninteresting" methods (a more realistic example is here):
class YourClass : Interface {
public void ReadEntity()
{
delegateTo.ReadEntity();
}
TableEntity delegateTo = new TableEntity();
}
or just throw an exception inside them (like NotImplementedException) - the latter will only work for you if those methods are not called.
You can create a class that contains the implementation of the TableEntity class, but also adds the functionality that you want. This is similar to the Decorator Pattern.
[Attributes...]
public class MyTableEntity : ITableEntity {
private TableEntity decoratedTableEntity;
public void ReadEntity(args...) {
decoratedTableEntity.ReadEntity(args...);
}
}
To make the solution more generic, change decoratedTableEntity to be an ITableEntity.