自动映射从XML创建对象

如果我有以下课程:

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 Groups { get; set; } } 

我正在使用sharepoint Web服务,它返回一个带有我的类中每个属性的属性的XML,例如:

    

有没有办法使用AutoMapper将XML片段映射到SPUser类实例?

博客已被删除 – 这是@DannyDouglasspost的Bing档案

使用AutoMapper和Linq-to-Xml简化使用Xml数据

我最近遇到了需要手动使用多个SOAP Web服务的工作场景,我相信你可以想象它是相当单调的。 一位同事(Seth Carney)和我尝试了几种不同的方法,但我们最终确定了一种简化xml消耗的解决方案,并最终使代码更易于测试。 该解决方案主要围绕利用AutoMapper(一种开源对象 – 对象映射工具)在XElements之间创建链接( http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.aspx )在我们创建的SOAP消息和自定义合同中以可重用的方式返回。

我整理了一个快速演示,演示了如何使用相同的方法来使用和显示Twitter公共时间线( http://api.twitter.com/1/statuses/public_timeline.xml )(使用API​​的Xml响应类型) 。

注意:以下示例的源代码可以在我的GitHub页面上找到: https : //github.com/DannyDouglass/AutoMapperXmlMappingDemo

  1. 获得项目设置

在创建基本的MVC3(下载测试版)项目和相关的测试项目之后,第一步是安装AutoMapper软件包。 我一直在使用微软最近宣布的包管理系统NuGet来安装任何开源依赖项。 以下命令是在我的MVC3项目中设置AutoMapper所需的全部内容( 请在此处阅读有关NuGet的更多信息( http://weblogs.asp.net/scottgu/archive/2010/10/06/announcing-nupack-asp-net- mvc-3-beta-and-webmatrix-beta-2.aspx )和这里( 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. 创建映射

安装AutoMapper后,我就可以开始创建xml到对象映射所需的组件。 第一步是在我的应用程序中创建一个快速合约来表示Tweet对象:

 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; } } 

没有什么可以疯狂的 – 只是一个简单的实体。 这些是来自Twitter API的响应中使用某些字段的不同名称提供的所有字段。 在源和目标对象具有相同名称的简单情况下,您可以使用以下语法快速设置映射:

 Mapper.CreateMap(); 

但是,AutoMapper默认情况下不支持Xml我必须指定要映射的字段。 在AutoMapper中使用Fluent API我可以链接我的字段映射。 看看我的例子中映射的一个示例字段 – 推文的正文:

 Mapper.CreateMap() .ForMember( dest => dest.Body, options => options.ResolveUsing>() .FromMember(source => source.Element("text"))) 

一开始可能看起来很复杂,但这里真正发生的一切是我们向AutoMapper提供有关在源对象中使用什么值以及如何将其映射到目标对象属性的详细信息。 我想在上面的Body字段映射中关注一条特定的行:

 options => options.ResolveUsing>() .FromMember(source => source.Element("id"))) 

XElementResolver是一个自定义值解析器( http://automapper.codeplex.com/wikipage?title=Custom%20Value%20Resolvers),Seth用它来处理解析XmlElement源对象以检索强类型值以供在映射。 我将在稍后详细介绍,但在我们继续之前,请先查看我的完整映射:

 Mapper.CreateMap() .ForMember( dest => dest.Id, options => options.ResolveUsing>() .FromMember(source => source.Element("id"))) .ForMember( dest => dest.Name, options => options.ResolveUsing>() .FromMember(source => source.Element("user") .Descendants("name").Single())) .ForMember( dest => dest.UserName, options => options.ResolveUsing>() .FromMember(source => source.Element("user") .Descendants("screen_name").Single())) .ForMember( dest => dest.Body, options => options.ResolveUsing>() .FromMember(source => source.Element("text"))) .ForMember( dest => dest.ProfileImageUrl, options => options.ResolveUsing>() .FromMember(source => source.Element("user") .Descendants("profile_image_url").Single())) .ForMember( dest => dest.Created, options => options.ResolveUsing>() .FromMember(source => source.Element("created_at"))); 
  1. 通用XElementResolver

此自定义值解析程序是允许这些XElement-to-Contract映射在原始解决方案中工作的真正密钥。 正如我们在上面看到的那样,我在这个例子中重用了这个解析器。 这就是创建自定义解析程序类所需的全部内容:

 public class XElementResolver : ValueResolver { protected override T ResolveCore(XElement source) { if (source == null || string.IsNullOrEmpty(source.Value)) return default(T); return (T)Convert.ChangeType(source.Value, typeof(T)); } } 

此通用XElementResolver允许使用轻松传递上面映射中检索的值的类型。 例如,以下语法用于在上面的Id字段的.ForMember()声明中强类型化从XmlElement检索的值:

 ResolveUsing>() 

在我的映射完全配置和实例化后,我准备调用Twitter API并利用AutoMapper显示最新的公共时间线。

  1. 把碎片放在一起

我创建了一个负责检索Twitter API响应的简单类:

 public class TwitterTimelineRetriever { private readonly XDocument _twitterTimelineXml; public TwitterTimelineRetriever() { _twitterTimelineXml = XDocument .Load("http://api.twitter.com/1/statuses/public_timeline.xml"); } public IEnumerable GetPublicTimeline(int numberOfTweets) { var tweets = _twitterTimelineXml.Descendants("status") .Take(numberOfTweets); return tweets.Select(Mapper.Map).ToList(); } } 

GetPublicTimeline方法是一个简单的方法,通过利用我们之前创建的地图,返回,你猜对了Twitter公共时间轴:

 return tweets.Select(Mapper.Map).ToList(); 

在我的MVC3站点的HomeController中,我可以快速调用检索方法,请求最后10个结果:

 public class HomeController : Controller { private TwitterTimelineRetriever _twitterTimelineRetriever; public ActionResult Index() { _twitterTimelineRetriever = new TwitterTimelineRetriever(); ViewModel.Message = "Twitter Public Timeline"; return View(_twitterTimelineRetriever.GetPublicTimeline(10)); } } 

最后,在使用Microsoft的新Razor视图引擎在我的View中进行一些格式化后,我显示了公共时间线!

您需要在.NET中检查XML序列化 – 这是将对象序列化为XML或从XML反序列化的方法。

Automapper可用于设置两个对象之间的属性 – 它根本不处理XML。

更多资源:

  • C#教程 – XML序列化

在当天晚些时候,有人使用AutoMapper将XML映射到POCO而不是沿着XMLSerialization路线。 我找到了以下博客条目: – 使用AutoMapper和Linq-to-Xml简化使用Xml数据

这足以让您开始实现自己的通用自定义解析器,如果示例还不够。

编辑:固定链接编辑:真正固定的链接

您可以为此目的使用XML反序列化。 在.NET中,我们有XmlSerializer和DataContractSerializer