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

查看:136
本文介绍了Automapper从XML创建对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有下面的类:

 类SPUser 
{
公众诠释ID {得到;组; }

公共字符串名称{;组; }
公共字符串的LoginName {搞定;组; }
公共字符串电子邮件{获得;组; }

公共BOOL IsSiteAdmin {搞定;组; }
公共BOOL IsSiteAuditor {搞定;组; }
公共BOOL IsDomainGroup {搞定;组; }

公开名单< SPGroup>论坛{搞定;组; }
}

和我使用的SharePoint Web服务,这与返回XML属性上我的课每个属性,如:

 <用户> 
<使用者名称=名称描述=降序..... />
< /用户>



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


解决方案

博客已被删除? - 这里的职位由@DannyDouglass的兵档案



可以简化使用XML数据AutoMapper和LINQ到XML



最近,我遇到了一个在工作场景所需耗费手工几个SOAP Web服务,这一点我敢肯定,你能想象是相当单调。一位同事(赛斯卡尼),我尝试了一些不同的方法,但我们终于上简化了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,微软最近推出的包管理系统,安装任何开源的依赖关系。下面的命令是,需要设置AutoMapper在我MVC3项目中的所有(阅读更多有关的NuGet这里(的 http://weblogs.asp.net/scottgu/archive/2010/10/06/announcing-nupack-asp-net- MVC-3-β-和WebMatrix中-β-2.aspx )和这里(的 http://weblogs.asp.net/scottgu/archive/2010/10/06/announcing-nupack-asp-net -mvc-3-β-和WebMatrix中-β-2.aspx )):

  PM>加上封装AutoMapper 




  • 创建映射



  • 使用AutoMapper安装我已经准备好开始创建必要的XML到对象映射的组件。第一步是建立在我的应用程序用来表示鸣叫对象的快速合约:

     公共接口ITweetContract 
    {
    ULONG标识{搞定;组; }
    字符串名称{;组; }
    字符串username {搞定;组; }
    绳体{搞定;组; }
    串ProfileImageUrl {搞定;组; }
    字符串创建{搞定;组; }
    }



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

     映射。 CreateMap< SourceObj,DestinationObj>(); 



    不过,AutoMapper默认情况下不支持XML我指定我将映射的字段。使用流利的API中AutoMapper我能链我字段映射。看看一个例子场在我的例子映射 - 鸣叫的身体:

      Mapper.CreateMap<的XElement,ITweetContract>() 
    .ForMember(
    DEST => dest.Body,
    选项=> options.ResolveUsing< XElementResolver<串>>()
    .FromMember(来源=> source.Element(文本)))

    这可以看第一个复杂,但所有这些都是真的发生在这里的是,我们在我的源对象使用的值提供细节AutoMapper以及如何将其映射到目标对象的属性。有一种独特的线,我想专注于上述主体字段映射:

     选项= GT; options.ResolveUsing< XElementResolver< ULONG>>()
    .FromMember(来源=> source.Element(ID)))

    该XElementResolver是一个自定义值解析器(的http:// automapper.codeplex.com/wikipage?title=Custom%20Value%20Resolvers )塞特想出了以处理解析的XmlElement源对象检索在映射使用强类型的值。我会细节,更在瞬间,但在此之前我们继续来看看我的全力映射:

      Mapper.CreateMap< ;的XElement,ITweetContract>()
    .ForMember(
    DEST => dest.Id,
    选项=> options.ResolveUsing< XElementResolver< ULONG>>()
    .FromMember(来源= GT; source.Element(ID)))
    .ForMember(
    DEST => dest.Name,
    选项=> options.ResolveUsing< XElementResolver<字符串>>()
    .FromMember(来源=方式> source.Element(用户)
    .Descendants(name)的单()))
    .ForMember(
    DEST => dest.UserName,
    选项=> options.ResolveUsing< XElementResolver<串>>()
    .FromMember(来源=> source.Element(用户)
    .Descendants(SCREEN_NAME)单()))
    .ForMember(
    DEST =方式> dest.Body,
    选项=> options.ResolveUsing< XElementResolver<字符串>>()
    .FromMember(来源= GT; source.Element(文本)))
    .ForMember(
    DEST => dest.ProfileImageUrl,
    选项=> options.ResolveUsing< XElementResolver<串>>()
    .FromMember(来源=方式> source.Element(用户)
    .Descendants(profile_image_url)单()))
    .ForMember(
    DEST => dest.Created,
    选项=> options.ResolveUsing< XElementResolver<串GT;>()
    .FromMember(来源= GT; source.Element(created_at)));




  • 的通用XElementResolver



  • 这自定义值解析器是让这些的XElement到合同映射在原来的解决方案的工作真正的关键。就像我们上面看到我这个重用解析器在这个例子中。这是所有有必要创建自定义解析类:

     公共类XElementResolver< T> :ValueResolver<的XElement,T> 
    {
    保护覆盖牛逼ResolveCore(源的XElement)
    {
    如果(来源== NULL || string.IsNullOrEmpty(source.Value))
    返回默认( T);
    回报率(T)Convert.ChangeType(source.Value的typeof(T));
    }
    }

    这个通用XElementResolver允许使用轻松过关类型值在我们的映射检索的上方。例如,下面的语法用于强类型在ID字段的.ForMember()声明的上方从XmlElement的检索到的值:

      ResolveUsing< XElementResolver< ULONG>>()

    使用我的映射完全配置和初始化,我已经准备好来调用Twitter的API,并充分利用AutoMapper以显示最新的公共时间轴。




  • 把拼在一起



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

     公共类TwitterTimelineRetriever 
    {
    私人只读的XDocument _twitterTimelineXml;
    公共TwitterTimelineRetriever()
    {
    _twitterTimelineXml =的XDocument
    .Load(http://api.twitter.com/1/statuses/public_timeline.xml);
    }
    公开的IEnumerable< ITweetContract> GetPublicTimeline(INT numberOfTweets)
    {
    VAR鸣叫= _twitterTimelineXml.Descendants(身份)
    。取(numberOfTweets);
    返回tweets.Select(Mapper.Map<的XElement,ITweetContract>)了ToList();
    }
    }



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

     返回tweets.Select(Mapper.Map<的XElement,ITweetContract> ;)了ToList()。 

    在我MVC3网站的HomeController中我能迅速调用的检索方法,要求在过去10个结果

     公共类HomeController的:控制器
    {
    私人TwitterTimelineRetriever _twitterTimelineRetriever;
    公众的ActionResult指数()
    {
    _twitterTimelineRetriever =新TwitterTimelineRetriever();
    ViewModel.Message =Twitter的公共时间线;
    返回查看(_twitterTimelineRetriever.GetPublicTimeline(10));
    }
    }



    最后,在我看来有点格式化后使用微软新的Razor视图引擎,我有我的公开时间表显示!


    If I have the 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 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>
    

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

    解决方案

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

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

    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.

    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).

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

    1. Getting the Project Setup

    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. Creating the Mapping

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

    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>();
    

    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")))
    

    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")))  
    

    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. The Generic XElementResolver

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

    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>>()
    

    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. Putting the Pieces Together

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

    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();
    

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

    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天全站免登陆