Automapper 从 XML 创建对象 [英] Automapper to create object from XML

查看:15
本文介绍了Automapper 从 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<SPGroup> Groups { get; set; }
}

我正在使用 sharepoint 网络服务,它返回一个 XML,其中包含我类中每个属性的属性,例如:

And I am using the sharepoint web services, which return an XML with an attribute for each property on my class, such as:

<Users>
    <User Name="name" Description="desc" ..... />
</Users>

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

Is there any way to use AutoMapper to map the XML fragment to an SPUser class instance?

推荐答案

博客已被删除 - 这是@DannyDouglass 帖子的 Bing 存档

Blog has been deleted - here's the Bing archive of the post by @DannyDouglass

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

Simplify Using Xml Data With AutoMapper and Linq-to-Xml

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

I recently ran into a scenario at work that required manually consuming several SOAP web services, which I’m sure you can imagine was rather monotonous. A co-worker (Seth Carney) and I tried a few different approaches, but we finally settled on a solution that simplified consumption of the xml and ultimately made the code more testable. That solution centered around leveraging AutoMapper, an open source object-object mapping tool, to create a link between the XElements(http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.aspx) returned in the SOAP messages and custom contracts we created – in a reusable manner.

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

I put together a quick demo that shows how you could use the same approach to consume and display the Twitter Public Timeline (http://api.twitter.com/1/statuses/public_timeline.xml) (using the API’s Xml response type).

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

Note: The source code for the following example can be found on my GitHub page: https://github.com/DannyDouglass/AutoMapperXmlMappingDemo

  1. 获取项目设置

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

After creating a basic MVC3 (download beta) project and the associated test project, the first step was to get the AutoMapper package installed. I have been using NuGet, Microsoft’s recently announced package management system, to install any open source dependencies. The following command was all that was needed to setup AutoMapper in my MVC3 project (read more about NuGet here(http://weblogs.asp.net/scottgu/archive/2010/10/06/announcing-nupack-asp-net-mvc-3-beta-and-webmatrix-beta-2.aspx) and 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. 创建映射

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

With AutoMapper installed I’m ready to get started creating the components necessary for the xml-to-object mapping. The first step is creating a quick contract used in my application to represent the 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; }
}

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

Nothing crazy here – just a simple entity. These are all fields that are provided in the response from the Twitter API using a different name for some fields. In simple cases where the source and destination objects have the same name you can setup a map very quickly using this syntax:

Mapper.CreateMap<SourceObj, DestinationObj>();

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

However, AutoMapper does not support Xml by default I have to specify the fields that I will be mapping. Using the Fluent API in AutoMapper I’m able to chain my field mappings. Take a look at one example field mapped in my example – the tweet’s Body:

Mapper.CreateMap<XElement, ITweetContract>()
.ForMember(
    dest => dest.Body,
    options => options.ResolveUsing<XElementResolver<string>>()
        .FromMember(source => source.Element("text")))

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

It may look complicated at first, but all that is really happening here is that we are providing details to AutoMapper on what value to use in my source object and how to map it to the destination object’s property. There is one particular line I would like to focus on in the above Body field mapping:

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

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

The XElementResolver is a custom value resolver (http://automapper.codeplex.com/wikipage?title=Custom%20Value%20Resolvers) that Seth came up with to handle parsing the XmlElement source object to retrieve a strongly-typed value for use in the mapping. I’ll detail that more in a moment, but before we move on take a look at my 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. 通用 XElementResolver

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

This custom value resolver is the real key that allowed these XElement-to-Contract maps to work in the original solution. I’ve reused this resolver in this example as we saw above. This was all that was necessary to create the 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));
}
}

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

This generic XElementResolver allows use to easily pass the type of the value retrieved in our mapping above. For example, the following syntax is used to strongly type the value retrieved from the XmlElement in the Id field’s .ForMember() declaration above:

ResolveUsing<XElementResolver<ulong>>()

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

With my mapping completely configured and instantiated, I’m ready to invoke the Twitter API and leverage AutoMapper to display that latest Public Timeline.

  1. 将各个部分放在一起

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

I created a simple class responsible for retrieving the 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();
}
}

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

The GetPublicTimeline method is a simple method returning, you guessed it, the Twitter Public Timeline by leveraging the map we created earlier:

return tweets.Select(Mapper.Map<XElement, ITweetContract>).ToList();

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

In my MVC3 site’s HomeController I can make a quick call to the retrieval method, requesting the 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));
}
}

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

And finally, after a little formatting in my View using the new Razor view engine from Microsoft, I have my public timeline displaying!

这篇关于Automapper 从 XML 创建对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆