简体   繁体   English

使用MVC使用CSV文件填充下拉列表

[英]Populating Dropdown with a CSV File using MVC

I'm working with MVC for the first time, and I'm having a little trouble populating a dropdown list with values from a csv file. 我是第一次使用MVC,在使用csv文件中的值填充下拉列表时遇到了一些麻烦。 The csv file is two columns, the first being location names, the second being isOpen containing only 1s and 0s. csv文件有两列,第一列是位置名称,第二列是仅包含1和0的isOpen。

This was my first attempt in my View: 这是我在View中的首次尝试:

<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>

As of now, none of the code runs because the File.Exists function automatically defaults to to IIS Express folder and returns false. 截至目前,这些代码均未运行,因为File.Exists函数自动默认为IIS Express文件夹并返回false。 I couldn't find a simple answer when I researched, but is there a way to properly direct to my project folder instead? 我进行研究时找不到简单的答案,但是有一种方法可以正确地直接定向到我的项目文件夹吗? Or would it be better practice to have this code in my Controller? 还是在我的控制器中包含此代码是更好的做法?

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

You can use Server.MapPath to convert from an application root relative URL ( ~/ ) to an absolute path that System.IO can understand. 您可以使用Server.MapPath从应用程序根目录相对URL( ~/ )转换为System.IO可以理解的绝对路径。

System.IO doesn't understand the ~/ syntax. System.IO无法理解〜/语法。 You'll need to pre-process the file path before handing it to System.IO. 您需要对文件路径进行预处理,然后再将其提交给System.IO。 That's where Server.MapPath comes in. Additionally, this sort of logic does not belong in a view. 这就是Server.MapPath的用处。此外,这种逻辑不属于视图。 Instead, you should have a class responsible for reading data from the data source. 相反,您应该拥有一个负责从数据源读取数据的类。 Your controller should then utilize that class to retrieve the data it needs, add that data to the view model, and then the view should display that information from the view model. 然后,您的控制器应利用该类检索所需的数据,然后将该数据添加到视图模型中,然后视图应显示该视图模型中的信息。 And lastly, don't parse CSV files manually yourself. 最后,不要自己手动解析CSV文件。 That's a recipe for disaster. 那是灾难的秘诀。 Use a library that handles the nuances for you, like CsvHelper . 使用像CsvHelper这样的库来为您处理细微差别。

Implementing the code as I have described will be cleaner (following the Single Responsibility Principle) and result in a more unit testable and easier to maintain application. 按照我所描述的那样执行代码将更加简洁(遵循“单一职责原则”),并且可以进行更多的单元测试并且更易于维护应用程序。

You should use a method like Server.MapPath to get the physical path of the file. 您应该使用类似Server.MapPath的方法来获取文件的物理路径。 If your Data directory is in your app root, you may use the ~ prefix with the file location, so that it gets the path from your app root. 如果您的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] });
        }
    }
}

While this will fix the problem, I strongly suggest you to contemplate on masons comment. 虽然这可以解决问题,但我强烈建议您考虑一下泥瓦匠的意见。 You should abstract reading the CSV file to another class ( Single responsibility principle ) and simply use that class as needed. 您应该将CSV文件读取为另一个类( 单一职责原则 ),然后根据需要简单地使用该类。 If you wrap it with an interface, you can easily switch your implementation with another robust/tested implementation later easily without changing a lot of code. 如果使用接口包装它,则以后可以轻松地将您的实现与另一个健壮/经过测试的实现轻松切换,而无需更改大量代码。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM