I need to map a xml property to c# properties.
var src = new Source(); src.Id = 1; src.Name = "Test"; src.Address = "<Country>MyCountry</Country><Prefecture>MyPrefecture</Prefecture><City>MyCity</City>"; class Source { public string ID{ get; set; } public string Name{ get; set; } public string Address{ get; set; } } Class Destination { public string ID{ get; set; } public string Name{ get; set; } public string Country { get; set;} public string Prefecture { get; set;} public string City { get; set;} }
Is it possible to achieve it through AutoMapper?
You can do the following. Considering your source type.
var src = new Source(); src.ID = 1; src.Name = "Test"; src.Address = "<Country>MyCountry</Country><Prefecture>MyPrefecture</Prefecture><City>MyCity</City>";
Since your source type (src.Address) doesn't have a root element, let's add one and parse the xml to a XDocument.
XDocument xdoc = new XDocument(); xdoc = XDocument.Parse($"<Root>{src.Address}</Root>");
Now during Initializing of Automapper, you need to map fields.
Mapper.Initialize(cfg => cfg.CreateMap<XElement, Destination>() .ForMember(dest => dest.Country, opt => opt.MapFrom(x=>x.Element(nameof(Destination.Country)).Value)) .ForMember(dest => dest.City, opt => opt.MapFrom(x => x.Element(nameof(Destination.City)).Value)) .ForMember(dest => dest.Prefecture, opt => opt.MapFrom(x => x.Element(nameof(Destination.Prefecture)).Value)));
Now you can resolve it as following.
Destination result = Mapper.Map<XElement, Destination>(xdoc.Root);
Update
You can using ConstructUsing as well for the purpose, that would hide away the Xml related code away from your other codes.
var src = new Source(); src.ID = "1"; src.Name = "Test"; src.Address = "<Country>MyCountry</Country><Prefecture>MyPrefecture</Prefecture><City>MyCity</City>"; XDocument xdoc = new XDocument(); xdoc = XDocument.Parse($"<Root>{src.Address}</Root>"); Mapper.Initialize(cfg => cfg.CreateMap<Source, Destination>() .ConstructUsing(x=>ConstructDestination(x)) );
Where ConstructDestination is defined as
static Destination ConstructDestination(Source src) { XDocument xdoc = new XDocument(); xdoc = XDocument.Parse($"<Root>{src.Address}</Root>"); return new Destination { Country = xdoc.Root.Element(nameof(Destination.Country)).Value, City = xdoc.Root.Element(nameof(Destination.City)).Value, Prefecture = xdoc.Root.Element(nameof(Destination.Prefecture)).Value, }; }
Your client code looks much cleaner now.
Destination result = Mapper.Map<Source, Destination>(src);
One option could be to wrap it with a root node and use a serializeable class.
The class would look like this:
[Serializable] public class Address { public string Country { get; set; } public string Prefecture { get; set; } public string City { get; set; } }
Deserialize would looke like the following:
string xml = "<Country>MyCountry</Country><Prefecture>MyPrefecture</Prefecture><City>MyCity</City>"; string wrapped = $"<Address>{xml}</Address>"; XmlSerializer serializer = new XmlSerializer(typeof(Address)); Address addr = (Address)serializer.Deserialize(new StringReader(wrapped));