自动映射从XML创建对象

Dar*_*bio 6 c# sharepoint linq-to-xml automapper

如果我有以下课程:

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; }
}
Run Code Online (Sandbox Code Playgroud)

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

<Users>
    <User Name="name" Description="desc" ..... />
</Users>
Run Code Online (Sandbox Code Playgroud)

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

OzB*_*Bob 9

博客已被删除 - 这是@DannyDouglass帖子的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
Run Code Online (Sandbox Code Playgroud)
  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; }
}
Run Code Online (Sandbox Code Playgroud)

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

Mapper.CreateMap<SourceObj, DestinationObj>();
Run Code Online (Sandbox Code Playgroud)

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

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

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

options => options.ResolveUsing<XElementResolver<ulong>>()
                    .FromMember(source => source.Element("id")))  
Run Code Online (Sandbox Code Playgroud)

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

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")));
Run Code Online (Sandbox Code Playgroud)
  1. 通用XElementResolver

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

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));
}
}
Run Code Online (Sandbox Code Playgroud)

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

ResolveUsing<XElementResolver<ulong>>()
Run Code Online (Sandbox Code Playgroud)

完全配置和实例化我的映射后,我就可以调用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<ITweetContract> GetPublicTimeline(int numberOfTweets)
{
    var tweets = _twitterTimelineXml.Descendants("status")
        .Take(numberOfTweets);  
    return tweets.Select(Mapper.Map<XElement, ITweetContract>).ToList();
}
}
Run Code Online (Sandbox Code Playgroud)

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

return tweets.Select(Mapper.Map<XElement, ITweetContract>).ToList();
Run Code Online (Sandbox Code Playgroud)

在我的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));
}
}
Run Code Online (Sandbox Code Playgroud)

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

  • 如何使用AutoMapper这样"自动"然后手动使用XML直接进入POCO? (7认同)

mar*_*c_s 7

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

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

更多资源: