Automapper для создания объекта из XML - PullRequest
6 голосов
/ 01 июля 2011

Если у меня есть следующий класс:

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 с атрибутом для каждого свойства моего класса, например:

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

Есть ли способ использовать AutoMapper для сопоставления фрагмента XML с SPUser экземпляром класса?

Ответы [ 4 ]

9 голосов
/ 16 декабря 2014

Блог был удален - вот архив Bing сообщения @ DannyDouglass

Упрощение использования данных XML с помощью AutoMapper и Linq-to-Xml

Недавно я столкнулся с рабочим сценарием, который требовал ручного использования нескольких веб-сервисов SOAP, что, я уверен, вы можете себе представить, было довольно монотонным. Сотрудник (Сет Карни) и я попробовали несколько разных подходов, но мы, наконец, остановились на решении, которое упростило использование 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, недавно объявленную Microsoft систему управления пакетами, для установки любых зависимостей с открытым исходным кодом. Следующая команда была всем, что было необходимо для настройки AutoMapper в моем проекте MVC3 (подробнее о 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; }
}

Здесь нет ничего сумасшедшего - просто простая сущность. Это все поля, которые предоставляются в ответе от API Twitter с использованием другого имени для некоторых полей. В простых случаях, когда исходный и целевой объекты имеют одинаковые имена, вы можете очень быстро настроить карту, используя следующий синтаксис:

Mapper.CreateMap<SourceObj, DestinationObj>();

Однако AutoMapper не поддерживает Xml по умолчанию. Я должен указать поля, которые я буду отображать. Используя Fluent API в AutoMapper, я могу связать свои полевые отображения. Взгляните на один пример поля, отображенного в моем примере - тело твита:

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

Поначалу это может показаться сложным, но на самом деле все, что здесь происходит, это то, что мы предоставляем AutoMapper подробную информацию о том, какое значение использовать в моем исходном объекте и как сопоставить его со свойством целевого объекта. Есть одна конкретная строка, на которой я хотел бы остановиться в приведенном выше отображении поля Body:

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

XElementResolver - это пользовательский преобразователь значений (http://automapper.codeplex.com/wikipage?title=Custom%20Value%20Resolvers), который придумал Сет для обработки синтаксического объекта-источника 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")));
  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));
}
}

Этот универсальный XElementResolver позволяет легко передавать тип значения, полученного в нашем отображении выше. Например, следующий синтаксис используется для строгого ввода значения, извлеченного из XmlElement, в объявлении .ForMember () поля Id выше:

ResolveUsing<XElementResolver<ulong>>()

После того, как мое отображение полностью настроено и создано, я готов вызвать API Twitter и использовать AutoMapper для отображения этой последней общедоступной временной шкалы.

  1. Соединение частей

Я создал простой класс, отвечающий за получение ответа API Twitter:

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

GetPublicTМетод imeline - это простой метод, возвращающий, как вы уже догадались, публичную временную шкалу Twitter, используя карту, которую мы создали ранее:

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

В HomeController моего MVC3-сайта я могу быстро вызвать метод поиска, запросив последние 10 результатов:

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

И, наконец, после небольшого форматирования в моем View с использованием нового движка Razor View от Microsoft у меня отображается общедоступная временная шкала!

7 голосов
/ 01 июля 2011

Для этого вам нужно проверить сериализацию XML в .NET - это способ сериализации объекта в XML или десериализации его из XML.

Automapper может использоваться для установки свойств между двумя объектами - он вообще не работает с XML.

Дополнительные ресурсы:

4 голосов
/ 19 декабря 2011

Поздно, но кто-то использовал AutoMapper для сопоставления XML с POCO, а не по маршруту XMLSerialization.Я нашел следующую запись в блоге: - Упрощение использования данных XML с AutoMapper и Linq-to-Xml

Этого достаточно, чтобы вы приступили к реализации собственного настраиваемого распознавателя, еслиодного примера недостаточно.

РЕДАКТИРОВАТЬ: фиксированная ссылка РЕДАКТИРОВАТЬ: действительно фиксированная ссылка

1 голос
/ 01 июля 2011

Вы можете использовать десериализацию XML для этих целей.В .NET у нас есть XmlSerializer и DataContractSerializer

...