2012-04-11 8 views
1

В моей MVC приложения, у меня есть вызов службы (http://dev-service.test.com/api/brands?active=true), который возвращает следующий XMLPopulate выпадающий список в MVC

<Brands> 
    <Brand> 
    <BrandId>1</BrandId> 
    <BrandNo>20</BrandNo> 
    <BrandName>ABC</Domain> 
    </Brand> 

    <Brand> 
    <BrandId>2</BrandId> 
    <BrandNo>30</BrandNo> 
    <BrandName>XYZ</Domain> 
    </Brand> 
<Brands> 

В одном из моих пользовательских элементов управления я хотел бы заполнить выпадающий список значениями BrandName. У меня уже есть ViewModel, который содержит кучу свойств. Как я могу заполнить раскрывающийся список значениями из этого XML?

P.S: Я новичок в MVC и до сих пор изучают основы ViewModels и т.д.

ответ

10

Там действительно 2 части в вашем вопросе. Часть анализа XML (которая не имеет ничего общего с ASP.NET MVC) и частью ASP.NET MVC. Так как ваш вопрос помечен asp.net-mvc, давайте сначала ответим на эту часть. Таким образом, вы указываете модель представления. Что-то вроде этого:

public class BrandsViewModel 
{ 
    public string Brand { get; set; } 
    public IEnumerable<SelectListItem> Brands { get; set; } 
} 

затем действие контроллера:

public ActionResult Index() 
{ 
    BrandsViewModel model = ... 
    return View(model); 
} 

и, наконец, вид части:

@model BrandsViewModel 
@using (Html.BeginForm()) 
{ 
    @Html.DropDownListFor(x => x.Brand, Model.Brands)  
    <button type="submit">OK</button> 
} 

Хорошо, это где ASP.NET MVC часть заканчивается в вашем вопрос. Теперь идет парсинг XML. Существует несколько способов анализа XML на C#. Например, вы можете использовать класс XDocument.

Конечно, перед анализом XML вы должны иметь XML. То, что вы показали в своем вопросе, - это не XML. Это строка. Вы должны сначала исправить это и иметь действительный XML. Пример:

<Brands> 
    <Brand> 
    <BrandId>1</BrandId> 
    <BrandNo>20</BrandNo> 
    <BrandName>ABC</BrandName> 
    </Brand> 

    <Brand> 
    <BrandId>2</BrandId> 
    <BrandNo>30</BrandNo> 
    <BrandName>XYZ</BrandName> 
    </Brand> 
</Brands> 

Теперь, когда у вас есть действительный XML, переходим к использованию и используем синтаксический анализатор XML.

var brands = 
    from brand in XDocument.Load("brands.xml").Descendants("Brand") 
    select new SelectListItem 
    { 
     Value = brand.Element("BrandId").Value, 
     Text = brand.Element("BrandName").Value 
    }; 

и теперь давайте сделаем 2 работать вместе:

public ActionResult Index() 
{ 
    var brandsFile = Server.MapPath("~/app_data/brands.xml"); 
    var brands = 
     from brand in XDocument.Load(brandsFile).Descendants("Brand") 
     select new SelectListItem 
     { 
      Value = brand.Element("BrandId").Value, 
      Text = brand.Element("BrandName").Value 
     }; 


    var model = new BrandsViewModel 
    { 
     Brands = brands 
    }; 
    return View(model); 
} 

Здесь мы можем видеть, что мы сильно связаны из логики действий контроллера с XML разбора логики, которая плохо. Вы можете ввести абстракцию (интерфейс), которая будет введена в конструктор контроллера, а затем использована действием. Затем вы можете предоставить конкретную реализацию этой абстракции, которая будет выполнять фактический синтаксический анализ XML и настроить инфраструктуру инъекции зависимостей, чтобы передать ее контроллеру.

Так что давайте сделаем это. Давайте определим модель домена, которая будет представлять наши бренды:

public class Brand 
{ 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 

Прохладный. Теперь, что мы хотим делать с этими брендами? Извлеките их список. Давайте определим наш контракт:

public interface IBrandsRepository 
{ 
    Brand[] Get(); 
} 

ОК, мы указали, какие операции нам нужны с нашими брендами. Теперь у нас может быть наш контроллер таким образом:

public class BrandsController: Controller 
{ 
    private readonly IBrandsRepository _repository; 
    public BrandsController(IBrandsRepository repository) 
    { 
     _repository = repository; 
    } 

    public ActionResult Index() 
    { 
     var brands = _repository.Get().Select(b => new SelectListItem 
     { 
      Value = b.Id, 
      Text = b.Name 
     }); 
     var model = new BrandsViewModel 
     { 
      Brands = brands 
     }; 
     return View(model); 
    } 
} 

По-прежнему существует возможность для улучшения этого действия контроллера. Обратите внимание, что мы запрашиваем репозиторий и получаем список доменных моделей (Brand) и преобразуем эту модель домена в модель представления.Это громоздко и загрязняет нашу логику контроллера. Было бы лучше экстернализировать это сопоставление в отдельный слой. Лично я использую для этого AutoMapper. Это основа lightwight, которая позволяет определить отображения между различными классами в беглом пути, а затем просто передать его экземпляры типа источника и плюнет вам экземпляры типа мишени:

public class BrandsController: Controller 
{ 
    private readonly IBrandsRepository _repository; 
    public BrandsController(IBrandsRepository repository) 
    { 
     _repository = repository; 
    } 

    public ActionResult Index() 
    { 
     var brands = _repository.Get(); 
     var model = new BrandsViewModel 
     { 
      Brands = Mapper.Map<IEnumerable<Brand>, IEnumerable<SelectListItem>>(brands) 
     }; 
     return View(model); 
    } 
} 

Так мы делаем прогресс здесь. Теперь мы могли бы реализацию нашего контракта:

public class BrandsRepositoryXml: IBrandsRepository 
{ 
    private readonly string _brandsFile; 
    public BrandsRepositoryXml(string brandsFile) 
    { 
     _brandsFile = brandsFile; 
    } 

    public Brand[] Get() 
    { 
     return 
      (from brand in XDocument.Load(_brandsFile).Descendants("Brand") 
      select new Brand 
      { 
       Id = brand.Element("BrandId").Value, 
       Name = brand.Element("BrandName").Value 
      }) 
      .ToArray(); 
    } 
} 

И последний шаг головоломки настроить некоторые DI рамок, чтобы придать надлежащую реализацию нашего договора в контроллер. Есть как gazzilion каркасов DI для .NET. Просто выберите один. Это не имеет большого значения. Попробуйте Ninject.MVC3 NuGet. Это классно и легко настроить. Или, если вы не хотите использовать сторонние рамки DI, просто напишите обычай dependency resolver.

+0

Я не понимаю, что часть «не XML, это строка». Может быть, я плотный, но как ваш XML отличается от OP? –

+0

@CharlieKilian, смотрите внимательнее. Вы видите это ' XYZ'? Также вы видите закрывающий тег '' в XML OP? Я не. –

+0

Ах. Нет, я этого не делал, но сейчас. Хороший улов с вашей стороны. Мои извинения. –

0

Для разбора Xml вы могли бы использовать этот быстрый и грязный пример:

string xml = @" 
     <Brands> 
      <Brand> 
       <BrandId>1</BrandId> 
       <BrandNo>20</BrandNo> 
       <BrandName>ABC</BrandName> 
      </Brand> 
      <Brand> 
       <BrandId>2</BrandId> 
       <BrandNo>30</BrandNo> 
       <BrandName>XYZ</BrandName> 
      </Brand> 
     </Brands> "; 

     System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); 
     doc.LoadXml(xml); 

     var brands = (
      from node in doc.SelectNodes("//Brands/Brand").Cast<System.Xml.XmlNode>() 
      select new 
      { 
       BrandId = node.SelectSingleNode("BrandId").InnerText, 
       BrandNo = node.SelectSingleNode("BrandNo").InnerText, 
       BrandName = node.SelectSingleNode("BrandName").InnerText 

      }).ToList(); 

Если бы это было мне, я бы создать строго типизированный класс называется марка и придать ему свойства, которые соответствуют тому, что вы разбираете и их проанализировать узлы.

Смежные вопросы