填充MVC中的下拉列表

Gol*_*ser 1 c# asp.net asp.net-mvc jquery

在我的MVC应用程序中,我有一个服务调用(http://dev-service.test.com/api/brands?active=true),它返回以下XML

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

  <Brand>
  <BrandId>2</BrandId>
  <BrandNo>30</BrandNo>
  <BrandName>XYZ</Domain>
  </Brand>
<Brands>
Run Code Online (Sandbox Code Playgroud)

在我的一个用户控件中,我想使用BrandName值填充下拉列表.我已经有一个包含一堆属性的ViewModel.如何使用此XML的值填充下拉列表?

PS:我是MVC的新手,还在学习视图模型的基础知识等.

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

然后控制器动作:

public ActionResult Index()
{
    BrandsViewModel model = ...
    return View(model);
}
Run Code Online (Sandbox Code Playgroud)

最后是视图部分:

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

好的,这是ASP.NET MVC部分在你的问题中结束的地方.现在是XML解析部分.有几种方法可以在C#中解析XML.例如,您可以使用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>
Run Code Online (Sandbox Code Playgroud)

现在您已经拥有了有效的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
    };
Run Code Online (Sandbox Code Playgroud)

现在让我们共同努力:

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

在这里我们可以看到,我们已经将控制器动作逻辑与XML解析逻辑强烈耦合,这很糟糕.您可以引入一个抽象(接口),它将被注入控制器的构造函数,然后由操作使用.然后,您可以提供此抽象的特定实现,该实现将执行实际的XML解析并配置您的依赖注入框架以将其传递给控制器​​.

所以,让我们这样做.让我们定义一个代表我们品牌的领域模型:

public class Brand
{
    public string Id { get; set; }
    public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

凉.现在我们想对这些品牌做些什么?检索它们的列表.让我们来定义我们的合同:

public interface IBrandsRepository
{
    Brand[] Get();
}
Run Code Online (Sandbox Code Playgroud)

好的,我们已经指定了我们的品牌需要哪些操作.现在我们可以让我们的控制器看起来像这样:

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

此控制器操作仍有改进的余地.请注意,我们正在查询存储库并获取域模型列表(Brand)并将此域模型转换为视图模型.这很麻烦,污染了我们的控制器逻辑.最好将此映射外部化为单独的层.就个人而言,我使用AutoMapper.它是一个轻量级框架,允许您以流畅的方式定义不同类之间的映射,然后简单地传递源类型的实例,它将吐出目标类型的实例:

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

所以我们在这里取得进展.现在我们可以实现合同:

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

这个难题的最后一步是配置一些DI框架,将合同的正确实现注入控制器.有一个用于.NET的DI框架的gazzilion.选择一个.这并不重要.试试Ninject.MVC3 NuGet.它有点酷,易于设置.或者,如果您不想使用第三方DI框架,只需编写自定义依赖项解析程序.