あなたの質問には本当に2つの部分があります。XML解析部分(厳密にはASP.NET MVCとは関係ありません)とASP.NETMVC部分。あなたの質問はでタグ付けされているので、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.NETMVCの部分が質問の最後になります。次に、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>
有効な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();
}
OK、ブランドで必要な操作を指定しました。これで、コントローラーを次のように表示できます。
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を使用しています。これは軽量のフレームワークであり、異なるクラス間のマッピングを流暢に定義し、ソースタイプのインスタンスを渡すだけで、ターゲットタイプのインスタンスを吐き出すことができます。
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フレームワークを構成することです。.NET用のDIフレームワークの群れのようなものがあります。1つ選んでください。それは本当に重要ではありません。Ninject.MVC3NuGetを試してください。ちょっとクールでセットアップも簡単です。または、サードパーティのDIフレームワークを使用したくない場合は、カスタムの依存関係リゾルバーを作成するだけです。