net core 2.0 read file added as resources - c#

I am doing a C# Net Core 2.0 Application...
I have a .sln with several Console projects called PrjA, PrjB, PrjC that will be run in differents ports, port 5000, port 5010, port 5020. They are running in parallel by Console
C:>dotnet PrjA.dll
C:>dotnet PrjB.dll
C:>dotnet PrjC.dll
I have another Library Project called PrjCommon that it is referenced by all three Project. In this Project I want to have a configuration file in common to all three projects.
this file is a json file called portsettings.json.
When i run any of those projects in Debug mode or generating the Publish folder, portsettings.json file is not saved.
In PrjCommon Project I tried to embebed portsettings.json as a file in Resources.resx.
From any of these three projects, I called a Method in PrjCommon that should read portsettings.json file.
I have tried to read this file from Resources.resx in two ways.
First like this
var assembly = Assembly.GetEntryAssembly();
string[] names = assembly.GetManifestResourceNames();
but names is null.
And Second
var byteArray = Resources.portsettings;
That return a bytes arrays, but i can not transform those byte array into json.
My questions is how can I make it Works. Either to save json file when I Compile those Projects, or, to save it as resources file and be able to read it.
Thanks

You could read the embedded resources with the following.
public static class EmbeddedResource
{
public static string[] GetApiRequestFile(string namespaceAndFileName)
{
try
{
using (var stream = typeof(EmbeddedResource).GetTypeInfo().Assembly.GetManifestResourceStream(namespaceAndFileName))
using (var reader = new StreamReader(stream, Encoding.UTF8))
return reader.ReadToEnd().Split(';');
}
catch(Exception exception)
{
ApplicationProvider.WriteToLog<EmbeddedResource>().Error(exception.Message);
throw new Exception($"Failed to read Embedded Resource {namespaceAndFileName}");
}
}
}
So, in my case I want to read embedded text files that contain URL's that I format, they act as a template primarily. But the logic you're seeking would be that first stream line.
Solution - Opti
Folder - Resource
File - RequestUrl.txt
If I had a class where the text file is, the namespace with the specified file would be Opti.Resource.RequestUrl.txt.

I solved saving json file in Debug and Publish directory by setting .json file property Copy to Output Directory to Always as says here.
I have also add Resources file following this tutorial
I do not if it the best way, but it is the simplest.

Related

How do I get a simple relative file path in c# for an easy to reach folder

I'm fairly new to C#. I've got a small project that makes use of a CSV file. I want the user of the said little app to be able to place the CSV file in the same folder as the startup file (or the .application file) and the program to be able to find it. I tried using the Application.StartupPath but that led me to a different file path than the one I was hoping for.
Currently, when I publish my project, I've got my 'setup.exe', 'Floyds.application' and 'Application Files' all sitting in 'C:\Users\Dell\Desktop\Floyds Published'. This is where I'd ideally like to be able to place my CSV file such that the app reads it. (Of course, this is just an example in my specific case, I'd like the little folder with those three to be the place where you can place CSV files regardless of where it is.)
Alternatively, if anyone can give me another means of getting a simple relative file path that would make is easy enough for someone who doesn't know their way around computers too well to easily dump the file in a folder and for my program to be able to read it, that would also work.
string filepath;
if(FileAddressBox.Text == "")
{
filepath = Application.StartupPath + #"\InitialTable.csv";
}
else
{
filepath = FileAddressBox.Text;
}
using (var reader = new StreamReader(filepath))
Thanks in advance!
Edit: I should have probably clarified that it is a winforms application. My apologies!
Edit 2: I am ideally hoping that the user of the app swaps the CSV file with other CSV files regularly to get different results when running the application, so as to save the user from having to input the different CSVs filepath manually.
Edit 3: The link I was given to the other question does not seem to work either. Added the code where it is used.

File containing null values instead of JSON object after computer restart

I am working on a C# project in which I have several configuration files. Each of these files contains a JSON Object. During the whole lifecycle of the program, these files can be read or be written at various moments.
This program manages an industrial machine which for various reasons can be turned off at any moment. Turning off the machine leads to instantly turning off the computer on which my program is running. The computer is running Windows 10 Pro x64 with a NTFS formatted SSD.
When the machine is turned on, and thus my program restarts, it throws an exception when reading a configuration file telling the file does not contain any JSON object. When I open the file with Notepad, the file really is "empty".
For example, instead of having a JSON Object:
{
"key": value
}
I have the following content:
NULNULNULNULNULNULNULNUL etc.
The properties of the file show the same filesize whether it contains a JSON object or is "empty", the same goes for the size on disk property.
I have other configuration files that are read and written but as plain text, which are not affected.
This issue does not arise at each power off / power on, and does not affect each configuration file. It mostly appears with the same file but not always.
I've checked if the configuration files are correctly closed whenever I read or write them:
Read file:
JObject jsondata = JObject.Parse(File.ReadAllText(Path));
Write file:
File.WriteAllText(Path, jsondata.ToString());
Both methods (ReadAllText and WriteAllText) specify that they open, read and close the file.
These methods are surrounded with try catch clauses and I never had an issue with a wrong JSON structure or a NULL Object. If I'm correct, even a NULL JSON object would write at least the brackets {} into the file.
I've tried to programmatically backup my configuration files in another folder. Backing up files are done without reading the files (using the File.Copy() method):
Periodically (every 10 minutes), update the backup files with the latest configuration files.
If a configuration file is "empty" (by checking if all bytes in file equal 0), replace it with the corresponding backup file.
// Check if any file has been modified since last check
for (int file = 0; file < Directory.GetFiles(_FolderToBackup).Length; ++file)
{
// Get file to check
string FilePath = Directory.GetFiles(_FolderToBackup)[file];
string FileName = Path.GetFileName(FilePath);
// Check if backup file with same name exists in Backup folder
if (BackupFileExist(FileName))
{
// File path to backup file
string BackupFilePath = _BackupFolder + "\\" + FileName;
// If backup file is empty
if (isFileEmpty(BackupFilePath))
{
Log.Write("File " + FilePath + " is empty");
// Copy file to backupfolder, we don't have to check if file to backup is empty, because destination is already empty !
File.Copy(FilePath, BackupFilePath, true);
}
// If file to backup is empty
if (isFileEmpty(FilePath))
{
Log.Write("File " + FilePath + " is empty");
// Copy backup file back to folder to backup
File.Copy(BackupFilePath, FilePath, true);
}
// If no file is empty, update only files that have been modified since last check
if(new FileInfo(FilePath).LastWriteTime > new FileInfo(BackupFilePath).LastWriteTime)
{
File.Copy(FilePath, BackupFilePath, true);
}
}
// If backup file does not exist
else
{
string BackupFilePath = Path.Combine(_BackupFolder, FileName);
File.Copy(FilePath, BackupFilePath);
}
}
This turnaround works perfectly, when a configuration file is "empty".
However, sometimes when I turn off/on the machine, both the configuration file and it's backup file were empty.
I also managed once to obtain an empty configuration file on machine restart even if the power off happened while my code wasn't running.
At this point, I don't know if my issue is related to the power off/on or the way I read/write my files:
Why does it happen when the computer is shut down / turned on ?
Why does it affect only my JSON configuration files ?
Why does it empty the files and not corrupt them ?
Why does it happen even if the file is not open in my program ?
Thank you very much for your time.
Looking at the source for File.WriteAllText(), it seems that your data could be the victim of buffering (seems to be a 1K buffer size). If you want to guarantee immediate writing to disk, you'll need your own method:
using (Stream stream = File.Create(yourPath, 64 * 1024, FileOptions.WriteThrough))
using (TextWriter textWriter = new StreamWriter(stream))
{
textWriter.Write(jsonData);
}
Non-authoritative answer, but googling "non-atomic writes windows" I stumble across a really interesting article that suggests what you're experiencing is reasonably normal even on NTFS: https://blogs.msdn.microsoft.com/adioltean/2005/12/28/how-to-do-atomic-writes-in-a-file/
If I've understood correctly, then for your use-case what it recommends you do, is:
Do your writes (your JSON config file write) to a temporary file
(if power fails here, you've just lost this round of changes, the original file is fine)
"Flush the writes" (not sure what the right way to do that is, in your environment, but this question explores exactly that: How to ensure all data has been physically written to disk? ), or do the write with FileOptions.WriteThrough as outlined by #JesseC.Slicer
(if power fails here, you've just lost this round of changes, the original file is fine)
Rename the original file to an "I know I'm doing something dangerous" naming format, eg with a specific suffix
(if power fails here, you don't have a main config file, you've lost this round of changes, but you can still find the backup)
Rename the temporary file to the final/original name
(if power fails here, you have a main updated config file AND a redundant outdated "temporarily renamed" file)
Delete the temporarily renamed file
All this of course assumes you're able to ensure the temp file is fully written before you start renaming things. If you've managed that, then at startup your process would be something like:
If a "temporarily renamed" file is found, then either delete it (if there is also a "main file"), or rename it to the main file name
Load the main file (should never be corrupted)

How to implement a text file in content (XNA)

I am building a game which loads its map from a text file.
While creating the parts that handle maps, I simply kept the text file in the content folder and fetched it by its Windows filepath. This won't work for proper deployment (or even running the game from different drives) because it requires that the filepath be exactly the same.
I looked around for a way to include the text file the same way I would a Texture2D, but I cannot find any class that allows me to use it. Some answers to other questions suggested that I just use the text file from my content folder? How would I do that? My program's name is IslandQuest (placeholder; it doesn't even involve an island) so would I place the text file in the IslandQuestContent folder generated by XNA Studio? How would I access it from there such that its filepath doesn't depend on the drive configuration of a computer?
Thanks for any help.
This may not be the best way to do this but just looked back at what I did in my first year at university with XNA,
I added my txt file to the contents folder. Then in the properties for the file (select it in the solution explorer and view properties window) there should be "Copy to Output Directory", make sure this is copy if newer.
Then its just a case of
string.Format("Content/{0}.txt", filename)
I do think this can be improved perhaps by the following but it is untested
Path.Combine(Content,filename +".txt");
In my case I was reading XML file files from a data folder in my main project.
So under my project in Solution explore I had this set up:
WindowsPhoneGame1
...
data/
content.xml
Game1.cs
Program.cs
etc...
Where properties for content.xml were Build Action: Content and Copy to Output Directory: Copy always
In the class that read the file I used TitleContainer.OpenStream Method which according to the docs:
Returns a stream to an existing file in the default title storage
location. .... The stream returned is read-only. The file to be read must already exist, or this method will fail.
My example code
//open stream
Stream stream = TitleContainer.OpenStream("data/content.xml");
//do something with it...
Create a "Content" folder in your main project.
Put the files that cannot be put in the Content project in there.
Be sure to set all your content Build actions to Content and Copy Always.
The Content folder from your main project and the content in the content project will end up in the same folder when built.
The file path would still be "Content/file.ext" or whatever.

c# - where to place txt files

I'm working on a simple progam, and part of it populates a list from a txt file.
this probably is not a smart question but, I didn't find any info on this.
I was wondering where is the best place to put text files in the application directory.
O know about the Resouces but, I wasn't able to get the path of the file I stored there.
so 2 questions:
where is the best place to put a txt file? (or any other importent file to use in the application)
if I put files in the Resources how do I get its path ?
(sorry fo my English)
If these are files that you do not need to expose to the users and only serve an internal purpose, then you can embed them in your assembly as resources, and extract them when you need them.
To do this, create a new directory in your application. Let's call it 'Resources'. Then, add text files to it. Use the properties window of each text file to change the BuildAction setting to "Embedded Resource". Then, in your code once you need the contents of the file you can use code like this to extract it:
using System.Reflection;
// ...
using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MyApplication.Resources.MyFile.txt")) {
using (StreamReader reader = new StreamReader(stream)) {
string contents = reader.ReadToEnd();
// Do stuff with the text here
}
}
If you don't want to do this, the correct location to place files is in a directory you create under the AppData directory. This is a known system path, which you can obtain like this:
string folderLocation = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
string myPath = Path.Combine(folderLocation, "MyAppName");
You can then use a StreamReader or other class in System.IO to find/enumerate and read the files.
When an application has associated/companion data files it sometimes makes sense to embed them as a Resource, because then there is less chance for them to be tampered with e.g. deleted, or the data modified.
And other times it makes sense to keep the file loose....so you have to decide the best place to store them....you can locate these in the place where the application is installed, or in the Application Data/AppData directory.
For embedding files in Resources have a look at this link:
http://support.microsoft.com/kb/319292
It has a step-by-step guide showing how to embed a file (e.g. a Text file into Resources), and then using a StreamReader to access it and read its contents.
To store the files and access them from a suitably located directory you can use:
System.Environment.SpecialFolder.ApplicationData
with
Environment.GetFolderPath()
to find out where the AppData directory is.
Then when you create your application Setup/Installer, you should get it to create a directory for your application underneath AppData, and then you can decide what files you want to be installed into that location.
See:
Saving a file to Application Data in c#
Note, ApplicationData "roams"...i.e. when you logon to a different machine, the files are transferred onto that machine as part of your profile....you may not want this....so you could instead use:
System.Environment.SpecialFolder.CommonApplicationData

How to read text from a text file in the XAP?

I'm working on an out-of-browser Silverlight program, and I have successfully gotten it to open local files by means of an OpenFileDialog. However, now I need it to open a file from within its own XAP (no browsing necessary, the file to open is hard-coded). I am trying to use this code, but it's not working:
using (StreamReader reader = new StreamReader("Default.txt"))
{
TextBox1.Text = reader.ReadToEnd();
}
This code throws a SecurityException that says "File operation not permitted. Access to path 'Default.txt' is denied." What am I doing wrong?
Your code is trying to open a file called "Default.txt" that is somewhere out in the user's file system. Where exactly I don't know, as it depends on where the Silverlight app's executing from. So yes, in general you don't have permission to go there.
To pull something out of your XAP, you need ton construct the stream differently. It will be along these lines:
Stream s = Application.GetResourceStream(
new Uri("/MyXap;component/Path/To/Default.txt", UriKind.Relative)).Stream;
StreamReader reader = new StreamReader(s);
Note, this means your Default.txt should be set to 'Resource', not 'Embedded Resource'. By being a 'Resource' it will get added to the XAP. Embedded Resource will add it to the assembly.
More info: http://nerddawg.blogspot.com/2008/03/silverlight-2-demystifying-uri.html
Note: In cases where your Silverlight program has multiple assemblies, check that the "/MyXap" part of the Uri string references the name of assembly containing the resource. For example if you have two assemblies "ProjectName" and "ProjectName.Screens", where "ProjectName.Screens" contains your resource, then use the following:
new Uri("ProjectName.Screens;component/Path/To/Default.txt", UriKind.Relative))

Categories