Reading files in a folder one by one in C# - c#

I have a simple question, but that it's driving me crazy.
I have a folder with a lot of JSON files inside, I need just to open those files one by one and do things.
So, I need to open the first one, read it and do something then go to the second one etc. until the last.
Here the code I tried, searching on web:
string folderpath = #"C:\Users\rfo\Desktop\MM\VM DB\nv - master\nvd";
var fixedfolderpath = Environment.ExpandEnvironmentVariables(folderpath);
string [] filesnumber = Directory.GetFiles(fixedfolderpath, "*.json");
foreach (string filename in filesnumber)
{
var jsonFull = System.IO.File.ReadAllText(filename);
But I keep gettin error DirectoryNotFoundException: Could not find a part of the path on the browser.
I'm using asp.net CORE 3 and visual studio 2019.

If you want to get the files from your desktop, you could use this instead:
string path = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
#"MM\VM DB\nv - master\nvd");
But you probably got access right problems

As others suggest, it's better to move the files inside the solution. For example, you could copy those files into the project folder:
├───YourApp.csproj # your `*.csproj`
├───Controllers/
├───Models/
├───Views/
├───wwwroot/
├───MM/ # your target folder
│ └───VM/
│ └───VM DB/
│ └───nv - master/
│ └───nvd/
| └─── *.json
Apart from that, don't forget to add a configuration in your *.csproj file such that your json files will be copied automatically when you build/publish the app:
<ItemGroup>
<None Update="MM\**\*.*">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
Also, it seems that you're using the ASP.NET Core instead of ASP.NET. If that's the case, you could reference this folder by injecting an IWebHostEnvironment so that you invoke webHostEnv.ContentRootPath to get root directory (i.e., the project file direction in source code, and the directory of YourAssembly.dll when published).
For example, you could inject an IWebHostEnviroment instance in the controller:
public class HomeController : Controller
{
private readonly IWebHostEnvironment _env;
public HomeController(IWebHostEnvironment env)
{
this._env = env;
}
public IActionResult Privacy()
{
var dir = Path.Combine( this._env.ContentRootPath, #"MM\VM\VM DB\nv - master\nvd");
string[] filesnumber = Directory.GetFiles(dir, "*.json");
foreach (string filename in filesnumber)
{
var jsonFull = System.IO.File.ReadAllText(filename);
...
}
return Ok("hello,world");
}
}
Finally, in case you don't like dependency injection, or cannot use dependency injection, you could use a path relative to current assembly as below:
var assemDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var dir = Path.Combine(assemDir, #"MM\VM\VM DB\nv - master\nvd");
string[] filesnumber = Directory.GetFiles(dir, "*.json");
Be careful this is not the safest way. It is suggested that we should use the DI approach (IWebHostEnviroment) if possible.

Related

Access to path denied for files in WWWRoot folder

I am trying to access two folders that resides inside wwwRoot. The folders are "BlankPDFFiles" and "FilledPDFFiles". I am trying to get the blank PDF files that resides inside BlankPDFFiles folder and write some data inside the file and then save it to the folder FilledPDFFiles. This is the structure of my solution:
when I am trying to access the blank PDF file, I am getting below error:
Below is my code
public class PDFController : Controller
{
private readonly IEmployeeService _employeeService;
public readonly IConfiguration _configuration;
public readonly ILogger _logger;
private readonly IWebHostEnvironment _environment;
public PDFController(IEmployeeService employeeService, IConfiguration configuration, ILogger<PDFController> logger, IWebHostEnvironment environment)
{
_employeeService = employeeService;
_configuration = configuration;
_logger = logger;
_environment = environment;
}
public async Task<IActionResult> Index()
{
await PopulatePDFDoc();
return View();
}
public async Task PopulatePDFDoc()
{
AckPackage.Data.PDFPopulate.DocPDF doc = new Data.PDFPopulate.DocPDF();
string pdfLic = _configuration["PDFLicense"].ToString();
string filledPDF = Path.Combine(_environment.WebRootPath, "FilledPDFFiles");
string blankPDF = Path.Combine(_environment.WebRootPath, "BlankPDFFiles");
EmployeeInfo employee = await _employeeService.GetEmployeeByEmployeeNumber(up.EmployeeId);
await doc.popolatePDFDoc(pdfLic, filledPDF, blankPDF, employee);
}
This is what I have in populatePDFDoc method:
public async Task popolatePDFDoc(string PDFLic, string filledPDF, string blankPDF, EmployeeInfo employee)
{
string pathToFile = filledPDF + "_Package"+ "_" + employee.EmployeeNumber;
bool validLicense = BitMiracle.Docotic.LicenseManager.HasValidLicense;
**using (PdfDocument pdf = new PdfDocument(blankPDF))**
{
foreach (PdfControl control in pdf.GetControls())
{
switch (control.Name)
{
case "EmpID":
((PdfTextBox)control).Text = employee.EmployeeNumber;
break;
case "Last Name":
((PdfTextBox)control).Text = employee.LastName;
break;
}
}
pdf.Save(pathToFile);
}
I am getting an error at this line in popolatePDFDoc
using (PdfDocument pdf = new PdfDocument(blankPDF))
I am using third party vendor tool to populate PDF file.
This has nothing to do with the PDF library vendor, and is probably because your web application's exe is running from a directory outside of the path that blankPDF points to.
You can see the directory your application is running from by putting a call to Environment.CurrentDirectory somewhere before the exception occurs and putting a breakpoint on it to see it.
If you are developing locally and getting this error, your application is probably running in the folder C:\AllITProjects\AckPackage\bin\Debug\net7.0.
The wwwroot folder is not always writable from the application, depending on how you are running the application. However, the project folder is always writable, since the project folder is where your application's exe resides. So, here are steps to move your PDF folders into the project folder, which will ensure they remain writable:
1. Move both the BlankPDFFiles and FilledPDFFiles folders out of the wwwroot folder, and into the project folder (the folder where your .csproj file is located).
2. Open the .csproj file in notepad, and add the following line that tells the compiler to copy your PDF folders whenever you compile:
<ItemGroup>
<None Include="BlankPDFFiles\**" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always" />
<None Include="FilledPDFFiles\**" CopyToOutputDirectory="Always" CopyToPublishDirectory="Always" />
</ItemGroup>
3. Change filledPDF and blankPDF to use _environment.ContentRootPath:
string filledPDF = Path.Combine(_environment.ContentRootPath, "FilledPDFFiles");
string blankPDF = Path.Combine(_environment.ContentRootPath, "BlankPDFFiles");
4. You will have to create an action in a controller that specifically serves the PDF from the filledPDF path, as it will no longer reside in the wwwroot folder.
Let me know if you need more help, especially with Step #4.

Using log4net With Visual Studio Debugger

I'm having trouble getting my log4net.config file to load when using Visual Studio in debug mode for an Excel VSTO Plugin. The config file is in the top level directory of my project. I have the property "Copy to Output Directory" set to "Copy Always". This ensures the file is copied to bin/Debug/log4net.config. I can verify this is the case when I build.
However, the file won't load when I run in Debug mode. I gave up on trying to get the file to load automatically and decided to do it by code, as per the OP's code at the bottom of this question.
However, I realised that I needed to use an absolute path to the config file, as relative paths weren't picking it up. On further investigation, I realised that the executing DLL wasn't actually the DLL in the debug/bin folder. It was in the following location:
C:\Users\cbhandal\AppData\Local\assembly\dl3\MO52QQWP.9ZL\K36XZHGN.1PB\230751e6\d09b7fb2_19f6d401
Also the current working directory, as found by System.IO.Directory.GetCurrentDirectory(); was set to "C:\\Users\\cbhandal\\Documents".
Hard-coding the path as an absolute path works as in the following code:
var log4netConfig = "C:\\" + path + "\\Log4net.config";
var log4netInfo = new FileInfo(log4netConfig);
log4net.Config.XmlConfigurator.ConfigureAndWatch(log4netInfo);
But that's not a solution I can deploy. I'm stuck here. Wondering if there's a way to either force Visual studio to copy the .config file to that appdata/temp location, or if there's a way to programatically reference the folder where the original DLL lay- the one that was built. Or if anyone had any other solution?
For me the easiest solution was to use this:
https://stackoverflow.com/a/6963420/4754981
But there are several other solutions on that link for different approaches, each with their caveats.
So mine looks like this:
using System.Reflection;
using System.IO;
using System;
public static class Extensions {
private static string GetDirectory(this Assembly a) {
string codeBase = a.CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
private static void AlterLogPath(this log4net.Repository.ILoggerRepository repo, string newPath, string directory="") {
log4net.Repository.Hierarchy.Hierarchy h = (log4net.Repository.Hierarchy.Hierarchy) repo;
foreach (log4net.Appender.IAppender a in h.Root.Appenders) {
if (a is log4net.Appender.FileAppender) {
var fa = (log4net.Appender.FileAppender)a;
var fileName = Path.GetFileName(fa.File);
fa.File = newPath + (String.IsNullOrEmpty(directory)?"":(directory + Path.DirectorySeparatorChar.ToString())); // edit: filename is attached after next line automatically.
fa.ActivateOptions();
break;
}
}
}
}
and in the bootup (via [assembly: System.Web.PreApplicationStartMethod] or otherwise for asp), or main app..
static void Main() {
var PATH = Assembly.GetExecutingAssembly().GetDirectory() + Path.DirectorySeparatorChar.ToString();
log4net.Config.XmlConfigurator.ConfigureAndWatch(new FileInfo(PATH + "log4net.config"));
log4net.LogManager.GetRepository().AlterLogPath(PATH, "Logs");
}

How do I read in a file from disc during runtime in my WebAPI .NET Core [duplicate]

This question already has answers here:
How do I read a local file in my ASP.NET Core project?
(2 answers)
Closed 4 years ago.
In my solution I have a file called beep.png directly in the root, right next to Startup.cs file. I changed its properties to always copy. I activated UseFileServer and opted in to browse the directory structure to be sure.
However, when I run the code Image.FromFile("beep.png");, I only get the error that the file isn't found.
System.IO.FileNotFoundException
Message=C:\Program Files\IIS Express\beep.png
How can I enable the file to be accessible?
Use IWebHostEnvirounment to get the root content path (technicaly the project folder), or to get the web root path (the wwwroot folder under project folder).
_hostingEnvirounment.ContentRootPath will return:
D:\Hosting\ProjectFolder
_hostingEnvirounment.WebRootPath will rturn:
D:\Hosting\ProjectFolder\wwwroot
So in your case; inject IWebHostEnvirounment to your controller then get the content root folder as below:
public class MyApiController : ControllerBase {
private readonly IWebHostEnvirounment _hostingEnvirounment;
public MyApiController(IWebHostEnvironment hostingEnvironment)
{
_hostingEnvironment = hostingEnvironment;
}
// get image from project root folder \ProjectFolder\
public Image GetImageFromContentRoot(string name) {
// e.g.: imgPath = "D:\\Hosting\\ProjectFolder\\beep.png"
var imgPath = Path.Combine(_hostingEnvirounment.ContentRootPath, name);
return Image.FromFile(imgPath);
}
//get image from projects wwwroot folder
public Image GetImageFromWebRoot(string name) {
// e.g.: imgPath = "D:\\Hosting\\ProjectFolder\\wwwroot\\beep.png"
var imgPath = Path.Combine(_hostingEnvirounment.WebRootPath, name);
return Image.FromFile(imgPath);
}
}

How to persist a solution with projects and documents using Roslyn's AdhocWorkspace?

I've been trying to persist a new solution containing a project and a simple cs file with the following code but nothing get saved to the disk. Am I doing something wrong or is Roslyn not the tool to be used to generate solutions project and files?
class Program
{
static void Main(string[] args)
{
var workspace = new AdhocWorkspace();
var solutionInfo = SolutionInfo.Create(SolutionId.CreateNewId(),
VersionStamp.Create(),
#"C:\Seb\SebSol.sln");
var projectInfo = ProjectInfo.Create(ProjectId.CreateNewId(),
VersionStamp.Create(),
"SebProj",
"SebProj.dll",
LanguageNames.CSharp,
#"C:\Seb\SebSol\SebProj\SebProj.csproj");
workspace.AddSolution(solutionInfo);
workspace.AddProject(projectInfo);
var sourceText = SourceText.From("public class A { }");
workspace.CurrentSolution.AddDocument(DocumentId.CreateNewId(projectInfo.Id), "ClassA.cs", sourceText);
workspace.TryApplyChanges(workspace.CurrentSolution);
}
}
You're looking for MsBuildWorkspace, which can actually update sln and csproj files in MSBuild format on disk.
Other than that class, Roslyn APIs are completely agnostic to project formats such as MSBuild.

autoformat code from command line

Is it possible to run auto-format code for all or for specific file in solution, like (Ctrl+K, Ctrl+D) formatting in Visual Studio but from it`s command line?
Or use Resharper's cleanup also from command line for solution files?
Create your own tool. You can use EnvDTE, EnvDTE80 to create Visual Studio project and load the files you want to format on the fly. Once you are done delete the Visual Studio project. You can specify to not to show Visual Studio window while formatting. If you are interested let me know I can give you some code to make this work.
UPDATE:
I am copying the code I have. I used it to format *.js files. I removed some code which you don't need. Feel free to ask if it doesn't work.
//You need to make a reference to two dlls:
envdte
envdte80
void FormatFiles(List<FileInfo> files)
{
//If it throws exeption you may want to retry couple more times
EnvDTE.Solution soln = System.Activator.CreateInstance(Type.GetTypeFromProgID("VisualStudio.Solution.11.0")) as EnvDTE.Solution;
//try this if you have Visual Studio 2010
//EnvDTE.Solution soln = System.Activator.CreateInstance(Type.GetTypeFromProgID("VisualStudio.Solution.10.0")) as EnvDTE.Solution;
soln.DTE.MainWindow.Visible = false;
EnvDTE80.Solution2 soln2 = soln as EnvDTE80.Solution2;
//Creating Visual Studio project
string csTemplatePath = soln2.GetProjectTemplate("ConsoleApplication.zip", "CSharp");
soln.AddFromTemplate(csTemplatePath, tempPath, "FormattingFiles", false);
//If it throws exeption you may want to retry couple more times
Project project = soln.Projects.Item(1);
foreach (FileInfo file in files)
{
ProjectItem addedItem;
bool existingFile = false;
int _try = 0;
while (true)
{
try
{
string fileName = file.Name;
_try++;
if (existingFile)
{
fileName = file.Name.Substring(0, (file.Name.Length - file.Extension.Length) - 1);
fileName = fileName + "_" + _try + file.Extension;
}
addedItem = project.ProjectItems.AddFromTemplate(file.FullName, fileName);
existingFile = false;
break;
}
catch(Exception ex)
{
if (ex.Message.Contains(file.Name) && ex.Message.Contains("already a linked file"))
{
existingFile = true;
}
}
}
while (true)
{
//sometimes formatting file might throw an exception. Thats why I am using loop.
//usually first time will work
try
{
addedItem.Open(Constants.vsViewKindCode);
addedItem.Document.Activate();
addedItem.Document.DTE.ExecuteCommand("Edit.FormatDocument");
addedItem.SaveAs(file.FullName);
break;
}
catch
{
//repeat
}
}
}
try
{
soln.Close();
soln2.Close();
soln = null;
soln2 = null;
}
catch
{
//for some reason throws exception. Not all the times.
//if this doesn't closes the solution CleanUp() will take care of this thing
}
finally
{
CleanUp();
}
}
void CleanUp()
{
List<System.Diagnostics.Process> visualStudioProcesses = System.Diagnostics.Process.GetProcesses().Where(p => p.ProcessName.Contains("devenv")).ToList();
foreach (System.Diagnostics.Process process in visualStudioProcesses)
{
if (process.MainWindowTitle == "")
{
process.Kill();
break;
}
}
tempPath = System.IO.Path.GetTempPath();
tempPath = tempPath + "\\FormattingFiles";
new DirectoryInfo(tempPath).Delete(true);
}
I hope this helps.
To format net core c# source, use https://github.com/dotnet/format
Install the tool as per the project readme.
I had a need to format some code files I was generating from Razor templates. I created a shell .CSProj file in the root of my output folder, using dotnet new console which gives you this basic file:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
<RootNamespace>dotnet_format</RootNamespace>
</PropertyGroup>
</Project>
Then run dotnet format from a VS command prompt in that folder. It will recurse into sub-directories and format everything it finds. To format specific files you can provide a list of filenames with the --files switch.
As a followup to Dilshod's post, if you're just looking to format a single file, here's a way of doing it that won't need a temporary path:
static void FormatFile(string file)
{
EnvDTE.Solution soln = System.Activator.CreateInstance(
Type.GetTypeFromProgID("VisualStudio.Solution.10.0")) as EnvDTE.Solution;
soln.DTE.ItemOperations.OpenFile(file);
TextSelection selection = soln.DTE.ActiveDocument.Selection as TextSelection;
selection.SelectAll();
selection.SmartFormat();
soln.DTE.ActiveDocument.Save();
}
Note that "file" will need to have the full path on disk in all likelihood. Relative paths don't seem to work (though I didn't try all that hard).
Use CodeFormatter from the .NET Team
Install MSBuild Tools 2015.
Download CodeFormatter 1.0.0-alpha6.
Add CodeFormatter.csproj to the root directory of your projects:
CodeFormatter.csproj
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Compile Include="**\*.cs" />
</ItemGroup>
<Target Name="Compile">
<Csc Sources="#(Compile)"/>
</Target>
</Project>
Then run this from the Command Line.
> codeformatter.exe CodeFormatter.csproj /nocopyright
The result: all your projects' C# files now adhere to the majority of the .NET Foundation coding guidelines.
Remarks
Installing MSBuild Tools 2015 means that we do not need Visual Studio.
Adding CodeFormatter.csproj to the root directory recursively includes all C# files, which means the above works with project.json and *.xproj based setups.
See also
http://bigfontblog.azurewebsites.net/autoformat/
Not possible with Visual Studio, but there are command line utilities for this: http://astyle.sourceforge.net/astyle.html

Categories