c# - Automapper to create object from XML -


if have following class:

class spuser {     public int id { get; set; }      public string name { get; set; }     public string loginname { get; set; }     public string email { get; set; }      public bool issiteadmin { get; set; }     public bool issiteauditor { get; set; }     public bool isdomaingroup { get; set; }      public list<spgroup> groups { get; set; } } 

and using sharepoint web services, return xml attribute each property on class, such as:

<users>     <user name="name" description="desc" ..... /> </users> 

is there way use automapper map xml fragment spuser class instance?

blog has been deleted - here's bing archive of post @dannydouglass

simplify using xml data automapper , linq-to-xml

i ran scenario @ work required manually consuming several soap web services, i’m sure can imagine rather monotonous. co-worker (seth carney) , tried few different approaches, settled on solution simplified consumption of xml , made code more testable. solution centered around leveraging automapper, open source object-object mapping tool, create link between xelements(http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.aspx) returned in soap messages , custom contracts created – in reusable manner.

i put quick demo shows how use same approach consume , display twitter public timeline (http://api.twitter.com/1/statuses/public_timeline.xml) (using api’s xml response type).

note: source code following example can found on github page: https://github.com/dannydouglass/automapperxmlmappingdemo

  1. getting project setup

after creating basic mvc3 (download beta) project , associated test project, first step automapper package installed. have been using nuget, microsoft’s announced package management system, install open source dependencies. following command needed setup automapper in mvc3 project (read more nuget here(http://weblogs.asp.net/scottgu/archive/2010/10/06/announcing-nupack-asp-net-mvc-3-beta-and-webmatrix-beta-2.aspx) , here(http://weblogs.asp.net/scottgu/archive/2010/10/06/announcing-nupack-asp-net-mvc-3-beta-and-webmatrix-beta-2.aspx)):

pm> add-package automapper 
  1. creating mapping

with automapper installed i’m ready started creating components necessary xml-to-object mapping. first step creating quick contract used in application represent tweet object:

public interface itweetcontract { ulong id { get; set; } string name { get; set; } string username { get; set; } string body { get; set; } string profileimageurl { get; set; } string created { get; set; } } 

nothing crazy here – simple entity. these fields provided in response twitter api using different name fields. in simple cases source , destination objects have same name can setup map using syntax:

mapper.createmap<sourceobj, destinationobj>(); 

however, automapper not support xml default have specify fields mapping. using fluent api in automapper i’m able chain field mappings. take @ 1 example field mapped in example – tweet’s body:

mapper.createmap<xelement, itweetcontract>() .formember(     dest => dest.body,     options => options.resolveusing<xelementresolver<string>>()         .frommember(source => source.element("text"))) 

it may complicated @ first, happening here providing details automapper on value use in source object , how map destination object’s property. there 1 particular line focus on in above body field mapping:

options => options.resolveusing<xelementresolver<ulong>>()                     .frommember(source => source.element("id")))   

the xelementresolver custom value resolver (http://automapper.codeplex.com/wikipage?title=custom%20value%20resolvers) seth came handle parsing xmlelement source object retrieve strongly-typed value use in mapping. i’ll detail more in moment, before move on take @ full mapping:

mapper.createmap<xelement, itweetcontract>() .formember(     dest => dest.id,     options => options.resolveusing<xelementresolver<ulong>>()         .frommember(source => source.element("id"))) .formember(     dest => dest.name,     options => options.resolveusing<xelementresolver<string>>()         .frommember(source => source.element("user")             .descendants("name").single())) .formember(     dest => dest.username,     options => options.resolveusing<xelementresolver<string>>()         .frommember(source => source.element("user")             .descendants("screen_name").single())) .formember(     dest => dest.body,     options => options.resolveusing<xelementresolver<string>>()         .frommember(source => source.element("text"))) .formember(     dest => dest.profileimageurl,     options => options.resolveusing<xelementresolver<string>>()         .frommember(source => source.element("user")             .descendants("profile_image_url").single())) .formember(     dest => dest.created,     options => options.resolveusing<xelementresolver<string>>()         .frommember(source => source.element("created_at"))); 
  1. the generic xelementresolver

this custom value resolver real key allowed these xelement-to-contract maps work in original solution. i’ve reused resolver in example saw above. necessary create custom resolver class:

public class xelementresolver<t> : valueresolver<xelement, t> { protected override t resolvecore(xelement source) {     if (source == null || string.isnullorempty(source.value))         return default(t);       return (t)convert.changetype(source.value, typeof(t)); } } 

this generic xelementresolver allows use pass type of value retrieved in our mapping above. example, following syntax used type value retrieved xmlelement in id field’s .formember() declaration above:

resolveusing<xelementresolver<ulong>>() 

with mapping configured , instantiated, i’m ready invoke twitter api , leverage automapper display latest public timeline.

  1. putting pieces together

i created simple class responsible retrieving twitter api response:

public class twittertimelineretriever { private readonly xdocument _twittertimelinexml;   public twittertimelineretriever() {     _twittertimelinexml = xdocument         .load("http://api.twitter.com/1/statuses/public_timeline.xml"); }   public ienumerable<itweetcontract> getpublictimeline(int numberoftweets) {     var tweets = _twittertimelinexml.descendants("status")         .take(numberoftweets);       return tweets.select(mapper.map<xelement, itweetcontract>).tolist(); } } 

the getpublictimeline method simple method returning, guessed it, twitter public timeline leveraging map created earlier:

return tweets.select(mapper.map<xelement, itweetcontract>).tolist(); 

in mvc3 site’s homecontroller can make quick call retrieval method, requesting last 10 results:

public class homecontroller : controller { private twittertimelineretriever _twittertimelineretriever;   public actionresult index() {     _twittertimelineretriever = new twittertimelineretriever();       viewmodel.message = "twitter public timeline";       return view(_twittertimelineretriever.getpublictimeline(10)); } } 

and finally, after little formatting in view using new razor view engine microsoft, have public timeline displaying!


Comments

Popular posts from this blog

c# - SharpSVN - How to get the previous revision? -

c++ - Is it possible to compile a VST on linux? -

url - Querystring manipulation of email Address in PHP -