How to create auto mapper function between totally different classes - c#

How to create AutoMapper configuration when the source and destination classes are totally different ? I want to create a mapping between some external classes (which cannot be changed) and my classes which I'm gonna persist in the db. I could persist the entire external class , but I dont want to do that to save space. I'm using .net core 2.0.
For ex: I've an external class like below :
A
{
B {
b1;b2;b3;
}
C {
c1;c2;c3;
}
}
The above needs to be mapped to my class defined like below :
A
{
Optmized_BC{
b1;
b2;
c1;
}
c2;
}
What's the best way to create AutoMapper configuration in the above case ? Should I call CreateMap for every pair of source/destination variable ? Is there a way where I can map all variables inside one CreateMap call (using some clever linq maybe ?)

You could persist your data as JSON in the database, then it would be easy to deserialize it to the other class using Newtonsoft JSON library. You have to decide if it's easier than writing the mapper function for each case. The same structure/naming would be deserialized automatically, otherwise, you could use 'dynamic'.
Just to give you an idea:
var result = JsonConvert.DeserializeObject<dynamic>(json);
A a = new A();
a.Optmized_BC.b1 = result.B.ToObject<B>().b1;
I would suggest to use the explicit mapper and cover it with the unit tests

Related

How do I get AutoMapper to map classes whose type isn't known at compile time?

Let's say that I have a class Schedule that contains a property called Event that's a nested class. Let's say that there are many types of events, so the actual value of the property would be some subclass (or descendant) of Event. The event could be a Conference or a ReligiousCeremony or yada yada yada.
Now let's say that all of these classes are in an "old" namespace and I'm using AutoMapper to convert these into updated version in a "new" namespace. (Ideal use case for AutoMapper.) v1.Schedule maps to v2.Schedule and v1.Conference maps to v2.Conference and so on.
The issue I have is that because Schedule.Event isn't of type v1.Conference, AutoMapper isn't identifying it as an object type it can map. Specifically, my class definitions are coming from an XSD and the Schedule.Event property is of type object.
Is there a way to get AutoMapper to inspect the actual type of an object and apply the appropriate mapping?
My current work-around (which another developer is testing right now) is as follows:
var v2Schedule = mapper.Map<v2.Schedule>(v1Schedule);
if (v2Schedule.Event is v1.Conference) { v2Schedule.Event = mapper.Map<v2.Conference>(v2Schedule.Event as v1.Conference); }
if (v2Schedule.Event is v1.ReligiousCeremony) { v2Schedule.Event = mapper.Map<v2.ReligiousCeremony>(v2Schedule.Event as v1.ReligiousCeremony); }
(I know about switching on object type, but that's a c#7 feature and I'm still in c#6.)
Looking at the docs, it seems you can tell AutoMapper about the inheritance like so:
var config = new MapperConfiguration(cfg =>
{
//Other mapping
cfg.CreateMap<v1.Event, v2.Event>() //or even <object, v2.Event>
.Include<v1.Conference, v2.Conference>()
.Include<v1.ReligiousCeremony, v2.ReligiousCeremony>();
cfg.CreateMap<v1.Conference, v2.Conference>();
cfg.CreateMap<v1.ReligiousCeremony, v2.ReligiousCeremony>();
});

Cannot convert type 'System.Collections.Generic.List<website.Class1>' to 'System.Collections.Generic.List<library.Class1>'

I'm using MVC on .net 4.5.
I have separated models from website into a class library, and have tt class file of .edmx replicated to my website so i can access model classes.
Though when I return some data from library like this,
List<website.Class1> a = objLibraryRef.GetFileLists1();
i get this error.
Cannot convert type 'System.Collections.Generic.List<website.Class1>'
to 'System.Collections.Generic.List<library.Class1>'
I don't want to reference to class library for accessing model classes.
Any help would be appreciated.
Thanks & Cheers.
Your DAL method is returning List<T> of type Class1 which is in library namespace while you are assigning it to of type Class1 but its namespace is different which is website1 not library.
You can use implicit type variable which will infer the type which is returned by DAL library method:
var list = objLibraryRef.GetFileLists1();
Or if you reall want List of type website.Class1 then you have to project on the List again as #adricadar suggested in his post.
You have to convert the library.Class1 to website.Class1. Even if they have same name the classes are different because they are in separate libraries.
List<website.Class1> a = objLibraryRef.GetFileLists1()
.Select(c => new website.Class1 {
property1 = c.property1,
...
propertyN = c.propertyN
}).ToList();
Note: Replace property1..N with your properties (i.e. Name). For this you don't have to reference the library where library.Class1 is created.
You can use AutoMapper to map those two objects. Even if your definition matches they are two different classes and you can not just directly convert those. Here is an example of how to map lists.

How to use the ConfigurationManager to store structured data?

I can use the .Net ConfigurationManager to store strings, but how can I store structured data?
For example, I can do this:
conf = ConfigurationManager.OpenExeConfiguration(...)
string s = "myval";
conf.AppSettings.Settings["mykey"].Value = s;
conf.Save(ConfigurationSaveMode.Modified);
And I would like to do this:
class myclass {
public string s;
int i;
... more elements
};
myclass c = new myclass(); c.s = "mystring"; c.i = 1234; ...
conf.AppSettings.Settings["mykey"] = cc;
conf.Save(ConfigurationSaveMode.Modified);
How do I store and retrieve structured data with the ConfigurationManager?
I implemented a solution as #sll suggested. But then difficulty was to create a new section to the configuration. Here is how this is done:
How to Write to a User.Config file through ConfigurationManager?
You can create own configuration section type by inheriting from ConfigurationSection class and use it to save/load any custom type information.
MSDN: How to: Create Custom Configuration Sections Using ConfigurationSection
BTW, One advice which might be helpful for you or others: One good thing is making custom configurations section class immutable (no public setters) so you can be sure that configuration cannot be changed on any stage of application life cycle, but then if you decide writing unit tests for code which relies on configuration section class and need section stub with some test values you might stuck with abilty to set property values since there is no setters. Solution is providing a new class which is inherited from your section class and specifying in constructor values using protected indexer like show below:
public class TestSectionClass: MyConfigurationSection
{
public TestSectionClass(string testUserName)
{
this["userName"] = testUserName;
}
}
Serialization.
There are numerous different ways of serializing data, so you'd need to pick one. But .NET provides a serialization API that suits a great many cases, and in working with web AJAX calls recently I find myself using JavaScriptSerializer heavily to turn things into JSON. However there are third party libraries such as protobuf-net, and so on.
The key here is to essentially turn your data into a byte or string representation that can later be deserialized back to its original structure at a later date, allowing you to store it in a medium between then, such as in configuration files or transmission over networks etc.
As per #sll's answer, .NET has another facet meaning it can handle serialization of data in and out of custom configuration sections; whether you want to begin specifying types explicitly for this purpose or not is your call. Bottom line is the same, serialize, somehow.

Returning object obtained from a WCF web service

I have a function that returns an entity obtained from a WCF web service. How should I return this entity as? I don't think I can return the original object (from the web service), because that would mean that the function's caller (from other assembly) will be forced to have a service reference to this web service (because the class is defined in the service reference) and I think I want to avoid that. And I don't think I can use interface either, since I can't modify the WCF entity to implement my interface.
On the other hand, I need to return precisely all properties that the original entity has, eg. all properties needed to be there, and there is no conversion/adjustment needed to any value or any property name and type.
Is it better to create a new class that duplicate the same properties from the original WCF class? How should I implement it, is it better to create a new object that copies all values from the original object, e.g.
return new Foo() { Id = original.Id, Name = original.Name, ... etc. }?
or just wrap it with get set methods like :
public int Id
{
get { return _original.Id; }
set { _original.Id = value; }
}
And any idea how to name the new class to avoid ambiguity with the original class name from the WCF reference?
as you have figured out, it is not a good idea to force the client to use the same types as the server. This would unnecessarily expose server application architecture to the client. The best option is to use Data Transfer Objects (DTOs).
You may have DTO for each of the entity you wish to expose to the client and the DTO will have properties to expose all the required fields of the entity. There are libraries such as value injector (valueinjecter.codeplex.com) or auto mapper as suggested by #stephenl to help you in copying the values from one object to another.
Place the DTOs in a separate namespace and assembly for best physical decoupling. You can use YourCompany.YourProduct.Data.Entities as the namespace for entities and YourCompany.YourProduct.Data.DTO for the DTOs
Actually, it depends on whether you are the consumer. If you are the consumer, reusing the type assembly is ok. However if you are not in control of the consuming services, it is better to use DTO objects with [DataContract] attributes.

Mapping two classes easily in C#

I've a web application and a service layer running in different places and both have their own business entities, means both have their own classes to represent an employee, order etc (ex. Emp in service layer and Employee in web app). When the web application invokes the service layer to get a list of employees I want to transform the list of employees returned by service to the list of web application's employee type.
I'm looking for a way to do this easily. Any ideas will be great. By the way I'm using ASP.NET and WCF.
Use AutoMapper.
AutoMapper is a simple little library built to solve a deceptively
complex problem - getting rid of code that mapped one object to
another. This type of code is rather dreary and boring to write, so
why not invent a tool to do it for us?
General Features
Flattening
Projection
Configuration Validation
Lists and Arrays
Nested Mappings
Custom Type Converters
Custom Value Resolvers
Custom Value Formatters
Null Substitution
Here's a sample from : wlegant Code
Before automapper
var meeting = _repository.GetMeetingById(meetingId);
var dto = new MeetingDto();
dto.Begins = meeting.Begins;
dto.End = meeting.End;
dto.Attendees = meeting.Attendees;
dto.AttendeesCount = meeting.Attendees.Count;
//do something meaningful
and using auto mapper
var meeting = _repository.GetMeetingById(meetingId);
var dto = Mapper.Map<Meeting, MeetingDto>(meeting);
You could use Automapper:
https://github.com/AutoMapper/AutoMapper
It helps you map one type to another. Your input objects (WCF) will be transformed into an object of another type (Web application). Automapper is able (for a large part) to figure this out automatically. Little configuration is needed.
To map two types:
Mapper.CreateMap<WcfEmployee, WebAppEmployee>();
To convert a type to another:
WebAppEmployee employee = Mapper.Map<WcfEmployee, WebAppEmployee>(employee);
For the most part Automapper uses name-based convention to map two types, but IIRC you can certainly tweak this. For this you need to inform Automapper of your convention rules. In other words, the rules for how it should map your types.
Personally I wouldn't recommend doing it in a simple way but rather in a very conscius way. Only map the things from the service to the application that the app actually need and only expose what is absolutely necesary to expose. In other words keeps as much, preferrably all of the data the service exposes internal to th eapp object.
Usually data from a service is used to base functionality upon. Expose the functionality instead of the data. That will make it possible for you to change the data structure completely (as long as it supports the same mental model/functional requirements) with out having to rewrite anything based on the Application side object. You'd of course need to rewrite the application side class.
If the class properties share the same names and typing the simplest way to do this is via the JsonSerializer:
using System.Text.Json;
public class MappingService
{
/// <summary>
/// Converts model from class F to class T
/// </summary>
/// <typeparam name="T">To Class</typeparam>
/// <typeparam name="F">From Class</typeparam>
/// <returns>model of type class T</returns>
public T Map<F, T>(F from)
{
var json = JsonSerializer.Serialize(from);
var to = JsonSerializer.Deserialize<T>(json);
return to;
}
}
receivedEmployesArray.Select(x => new MyWinFormsEmploeType(x)); // if you create intializaion in constructor
receivedEmployesArray.Select(x => new MyWinFormsEmploeType() {
Name = x.Name,
Position = x.Position
}); // trasfering property to property
Or the most progressive way - use automapper

Categories