【问题标题】:Read file from model asp.net core 1.1从模型 asp.net core 1.1 读取文件
【发布时间】:2017-07-22 18:24:04
【问题描述】:

我需要从 Asp.net Core 1.1 中的一个类中读取一个 json 文件。该文件位于我的 mvc 项目的“wwwroot”中。 我知道我可以在控制器中对 IHostingEnvironment 进行依赖注入,将其传递给我的类,然后访问 WebRootPath,但我希望能够在控制器之外实例化我的类,例如,在另一个类中。 如何读取班级内 wwwroot 文件夹中的文件? 目标文件夹示例:

wwwroot/keywords/keywords.json.

如果我尝试在我的类的构造函数中注入 IHostingEnvironment,我将需要在实例化我的类时传递一个 HostingEnvironment 实例。

public class AppTweet
{
  private readonly IHostingEnvironment _hostingEnvironment;
  public AppTweet(ITweet tweet, ICollection<string> keyWords, IHostingEnvironment hostingEnvironment)
  {
     _hostingEnvironment = hostingEnvironment;
  }
}

我在传递hostingEnvironment 的控制器中调用我的类,但我想解耦这种行为,因为我需要在控制器之外实例化这个类。例如:

public class Article()
{
  public Article()
  {
    var appTweet = new AppTweet(new Tweet(), new List<string>, new HostingEnvironment()); 
  }
}

如果我这样做,HostingEnvironment.WebRootPath 为空

编辑

也许我不需要依赖注入。我只想读取 wwwroot 文件夹中的文件,但我不知道如何在开发和服务器中访问此路径 当我尝试

`var file = System.IO.File.ReadAllText(@"..\wwwroot\keywords\keywords.json")`;

文件 var 不读取我的开发机器中的项目文件夹。我要读取表单的路径类似于 E:\SOLUTION_FOLDER\PROJECT_FOLDER\wwwroot\keywords,但它从 E:\SOLUTION_FOLDER\wwwroot\keywords 读取,并且不包括项目文件夹。

编辑 2

我认为 DI 不适合这种情况。 这是我自己的个人项目。我想要做的是在这个类中填充一些属性。例如:我的班级总结:

public class AppTweet
{
  public AppTweet (ITweet tweet, ICollection<string> keyWords)
  {
    //Read a json file from wwwroot and populate NotDesiredKeyWords property
  }
  [NotMapped]
  public IEnumerable<string> NotDesiredKeyWords { get; set; }
 }

这个类AppTweet必须有权访问这个json文件,就像一个配置文件,因为它总是要读取这些值。我知道我可以对类中的值进行硬编码(它会更快),但我更喜欢在 json 文件中进行,所以如果我添加一些值,我就不必编译项目。 从我读到的here 来看,依赖注入负责实例化您的类,并且您的构造函数中不能有没有默认值的参数。 我需要(不需要,但对我来说这是更合理的方式)自己实例化这个类。也许在控制器之外的另一个类中实例化这个类。所以,我唯一想要的就是访问网络根文件夹wwwroot(或其他一些文件夹),我可以在其中放置这个 json 文件,并且它必须在我的机器和服务器中都可以工作。我可以将哪个path 传递给System.IO.File.ReadAllText(path) 以读取此文件?

【问题讨论】:

  • 为什么不只传递路径本身,甚至是完整的文件名,如果 AppTweet 只需要知道这些的话?
  • 或者只使用Dependency Injection作为你的AppTweet并传入HostingEnvironment而不是实例化一个新的
  • @PeterB,我如何才能通过开发和生产工作的路径?如果我执行 var file = System.IO.File.ReadAllText(@"..\wwwroot\keywords\keywords.json");,那么它会跳过路径中的项目文件夹,而只是读取解决方案文件夹。我没有在生产中测试这个。能行吗?
  • “但我想解耦这种行为,因为我需要在控制器之外实例化这个类” – 误解:如果你自己实例化它,你实际上是在耦合它,因为您不再使用依赖注入。
  • 模型不应该对其他组件有这样的依赖。考虑吃点别的东西,例如一种服务,其目的是用 JSON 文件中的数据填充模型。

标签: c# asp.net-core


【解决方案1】:

ASP.NET Core 为这种情况提供了File Provider。在您的场景中,您需要 PhysicalFileProvider 类的实例(它用于访问系统的实际或物理文件)。它可以直接创建为

IFileProvider provider = new PhysicalFileProvider("root path");

或者如果您需要访问wwwroot 中的文件,可以使用IHostingEnvironment.WebRootFileProvider 扩展属性:

//
// Summary:
//     /// Gets or sets an Microsoft.Extensions.FileProviders.IFileProvider pointing
//     at Microsoft.AspNetCore.Hosting.IHostingEnvironment.WebRootPath. ///
IFileProvider WebRootFileProvider { get; set; }

读取文件的可能方式:

// using System.IO;
// using Microsoft.AspNetCore.Hosting;

// IHostingEnvironment env
...

var fileProvider = env.WebRootFileProvider;

// here you define only subpath
var fileInfo = fileProvider.GetFileInfo("keywords\keywords.json"); 

var fileStream = fileInfo.CreateReadStream();

using (var reader = new StreamReader(fileStream))
{
    string data = reader.ReadToEnd();
}

另外,请注意,您需要添加 Microsoft.Extensions.FileProviders.Physical 包作为依赖项。


如果你想手动创建实例,那么你需要以级联方式传递依赖...(YourService 的实例应该以相同的方式创建或通过构造函数使用 DI 作为依赖传递到另一个类...)

public class YourService
{
    private IHostingEnvironment _env;

    public YourService(IHostingEnvironment env)
    {
        _env = env;
    }
    public Article CreateArticle()
    {
        return new Article(_env);
    }
}

public class AppTweet
{
  public AppTweet(ITweet tweet, ICollection<string> keyWords, IHostingEnvironment hostingEnvironment)
  {
     // read file here for example
  }
}

public class Article()
{
  public Article(IHostingEnvironment hostingEnvironment)
  {
    var appTweet = new AppTweet(new Tweet(), new List<string>, hostingEnvironment); 
  }
}

【讨论】:

  • 但是当我的类有一个接收另一个参数的构造函数时,我如何在我的类中接收这个 IHostingEnvironment env?对不起,我对 DI 缺乏了解。
  • 其实 ASP.NET Core 中的default DI implementation 只支持通过构造函数注入依赖
  • 那么,如果我理解正确的话,我只能在一个类中注入依赖项,而我没有调用一个构造函数?如果我想在需要实例化自己的类中接收 FileProvider(即,通过“新”词)怎么办?我不能吗?我的类是一个模型,需要从系统读取文件以填充一些属性,而不是硬编码属性(它们是 List),我决定将它们放在一个文件中。我怎样才能实现它?
  • @Porkopek 我已经更新了答案,但无论如何,建议您阅读更多关于什么是 DI 以及它是如何工作的......
  • 感谢您的更新。所以,考虑到这一点,我认为 DI 不适合这种情况,因为我认为它为这种简单的情况增加了很多开销。最后,它就像一条咬尾巴的鳕鱼,我需要让控制器或服务为我实例化该类。我做了一个 EDIT 2。请您阅读并提出建议吗?
猜你喜欢
  • 2017-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-30
  • 2021-08-15
  • 2018-12-17
相关资源
最近更新 更多