2017-08-08 14 views
0

MVCで初めて作業していますが、CSVファイルの値をドロップダウンリストに入力するのに少し問題があります。 csvファイルは2つの列です。最初はロケーション名、2番目はisOpenだけが1と0です。MVCを使用したCSVファイルへのドロップダウンの実装

これが私の見解で私の最初の試みだった。今のよう

<div class="col-md-10"> 
    @{   
     List<SelectListItem> locations = new List<SelectListItem>(); 
     if (System.IO.File.Exists("~/Data/locations.csv")) 
     { 
      string[] lines = System.IO.File.ReadAllLines("~/Data/locations.csv"); 
      foreach (string line in lines) 
      { 
       string[] data = line.Split(','); 
       if (data[1] == "1") 
       { 
        locations.Add(new SelectListItem { Text = data[0], Value = data[0] }); 
       } 
      } 
     } 
     Html.DropDownListFor(m => m.location, locations, new { htmlAttributes = new { @class = "form-control" } }); 
     Html.ValidationMessageFor(model => model.location, "", new { @class = "text-danger" }); 
    } 
</div> 

、コードのどれもFile.Existsは、IIS Expressのフォルダに自動的にデフォルトは機能しているため実行しないとfalseを返します。私は調査したときに簡単な答えを見つけることができませんでしたが、プロジェクトフォルダに適切に向ける方法がありますか?または、私のコントローラーにこのコードを書いた方が良いでしょうか?

+1

System.IOは '〜/'構文を理解していません。 System.IOに渡す前にファイルパスを前処理する必要があります。さらに、この種のロジックはビューに属しません。代わりに、データソースからデータを読み取るクラスを作成する必要があります。コントローラは、そのクラスを使用して必要なデータを取得し、そのデータをビューモデルに追加してから、ビューモデルからその情報を表示する必要があります。最後に、手動でCSVファイルを解析しないでください。それは災害のレシピです。 CsvHelperのような、あなたのニュアンスを扱うライブラリを使用してください。 – mason

答えて

2
public class Location 
{ 
    //properties here that describe a location 
} 

public class CsvHelperLocationRepository : ILocationRepository 
{ 
    private readonly string _dataFileLocation; 

    public CsvHelperLocationRepository(string dataFileLocation) 
    { 
     _dataFileLocation = dataFileLocation; 
    } 

    public List<Location> GetLocations() 
    { 
     //use CsvHelper here to parse the CSV file and generate a list of Location objects to return 
    } 
} 

public interface ILocationRepository 
{ 
    List<Location> GetLocations(); 
} 

public HomeController : Controller 
{ 
    private readonly ILocationRepository _locationRepository; 

    public HomeController() 
    { 
     //you really should use dependency injection instead of direct dependency like below 
     _locationRepository = new CsvHelperLocationRepository(Server.MapPath("~/data/locations.csv"); 
    } 

    public ActionResult SomeAction() 
    { 
     var model = new MyViewModel(); 
     model.Locations = _locationRepository.GetLocations(); 
     return View(model); 
    } 
} 

あなたは、System.IOが理解できる絶対パスにアプリケーションルート相対URL(~/)から変換するために、Server.MapPathのを使用することができます。

System.IOは〜/構文を理解していません。 System.IOに渡す前にファイルパスを前処理する必要があります。それはServer.MapPathが入る場所です。さらに、この種のロジックはビューに属しません。代わりに、データソースからデータを読み取るクラスを作成する必要があります。コントローラは、そのクラスを使用して必要なデータを取得し、そのデータをビューモデルに追加し、ビューにそのビューモデルの情報を表示する必要があります。最後に、手動でCSVファイルを解析しないでください。それは災害のレシピです。 CsvHelperのようなニュアンスを扱うライブラリを使用してください。

私が記述したようにコードを実装すると、(単体責任原則に従う)より洗練されたものになり、より単体テスト可能で保守しやすいアプリケーションになります。

+0

これは非常に役に立ちました、ありがとう。私はモデルで定義されたファイルを解析し、コントローラから呼び出される関数を持つことでこれを実装し、完全に機能しました。 – shrug

+0

@mattpotter私の答えに示されているように、その関数を独自のファイルに移動することを強く検討する必要があります。 「スマートモデル」は一般的には避けなければなりません。それは単体責任原則に違反します。モデルクラスはデータのみを表す必要があります。データソースからデータを取り込む責任はありません。 – mason

1

Server.MapPathのような方法を使用して、ファイルの物理パスを取得する必要があります。 Dataディレクトリがアプリのルートにある場合は、ファイルの場所に接頭辞~を使用して、アプリのルートからのパスを取得することができます。

var loc = Server.MapPath("~/Data/locations.csv"); 
if (System.IO.File.Exists(loc)) 
{ 
    string[] lines = System.IO.File.ReadAllLines(loc); 
    foreach (string line in lines) 
    { 
     string[] data = line.Split(','); 
     if (data[1] == "1") 
     { 
      locations.Add(new SelectListItem { Text = data[0], Value = data[0] }); 
     } 
    } 
} 

これで問題は解決しますが、masonsのコメントを検討することを強くお勧めします。 CSVファイルを別のクラス(Single responsibility principle)に抽象化し、必要に応じてそのクラスを使用するだけです。インターフェイスでラップすると、多くのコードを変更することなく、後で簡単に堅牢な/テスト済みの実装で実装を簡単に切り替えることができます。

関連する問題