how to read a file from a different project? - c#

how to read a file from a different project?
I have a solution:
Solution1
-MyProject
-MyProject.Artifacts
----Message.XML
-MyProject.Tests
I am attempting to read the contents of Message.XML from MyProject.Tests.
How do I read the contents of Message.XML from MyProject.Tests?
Unfortunately, right now I'm doing something like this, but it's not very pretty:
var currentDir = Directory.GetCurrentDirectory();
var parentDir = Directory.GetParent(Directory.GetParent(currentDir).FullName).FullName;
var parentParentDir = Directory.GetParent(Directory.GetParent(Directory.GetParent(currentDir).FullName).FullName).FullName;
var parentParentParentDir = Directory.GetParent(Directory.GetParent(Directory.GetParent(Directory.GetParent(currentDir).FullName).FullName).FullName).FullName;

You can store a path to the file in app settings of app.config / web.config using that read the file contents.
That way if you need to deploy your software in a different way you have the flexibility

If your path is fixed, you can write the path like "c:\projects\solution ... Message.xml"
If you want a relative path, the simplest way is this:
var DI = new DirectoryInfo("..\\..\\..\\..\\Your Folder\\Message.XML");
This path is started from CurrentDirectory and goes four folders up and the one folder down and finds the file.

Related

Hide Json file containing GOOGLE_APPLICATION_CREDENTIALS when building executable file in Visualstudio [SOLVED]

currently I am developing a tool that interacts with a Firebase Firestore database. When I want to make the C# Forms Application an executable file I get the .exe but also the json file which contains the Google App Credentials. However, I want to forward the tool so that you can't see the json file or read the contents of the file, so you only need the .exe file. Is there a way to achieve this? For example, define the app credentials in a C# script so that it compiles to the .exe file? If so how?
My current implementation looks like this:
string path = AppDomain.CurrentDomain.BaseDirectory + #"cloudfire.json";
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", path);
The cloudfire.json file is directly contained in the namespace "LUX".
I also tried making the cloudfire.json file a resource, since i read this post but then the problem is, that i can't set the path of the .json, if i try it like that:
var assembly = Assembly.GetExecutingAssembly();
string resourceName = assembly.GetManifestResourceNames()
.Single(str => str.EndsWith("cloudfire.json"));
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", resourceName);
I get the error: System.InvalidOperationException: "Sequence contains no matching element"
Is there maybe a way to set the "GOOGLE_APPLICATION_CREDENTIALS" to the embedded cloudfire.json ressource file?
EDIT:
I solved the problem by adding the "cloudfire.json" file to Resources.resx and changed the modifier to public. Like mentioned here.
Since you can only set the GOOGLE_APPLICATION_CREDENTIALS by using this code:
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", "path to file");
I solved it by creating a temporary file:
byte[] resourceBytes = Properties.Resources.cloudfire;
// Write the resource to a temporary file
string tempPath = Path.GetTempFileName();
File.WriteAllBytes(tempPath, resourceBytes);
// Set the GOOGLE_APPLICATION_CREDENTIALS environment variable
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", tempPath);
Add you file as embedded resource with name. And try to read by following code:
var resources = new ResourceManager("<namespace>", Assembly.GetExecutingAssembly());
var obj = resources.GetObject(<embedded_resource_key>);
or
var str = resources.GetString(<embedded_resource_key>)

Configuration Builder - search through subfolders for JSON files

I'd like to know how to set a ConfigurationBuilder to search through all subfolders for JSON files not only in Base Path itself.
var testDataBuilder = new ConfigurationBuilder();
var basePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "myData");
testDataBuilder.SetBasePath(basePath);
testDataBuilder.AddJsonFile("myData.json");
testDataBuilder.AddJsonFile("myDataInSubCatalogue.json"); //HOW TO REACH THAT?
return testDataBuilder.Build();
First of all, if you know the names and locations of the files it's far safer to add them explicitly. Adding arbitrary configuration files without some way of checking their validity is a great way to get hacked.
AddJsonFile accepts a path but doesn't care where it points. There's no restriction that forces it to look into the current folder. That path could be a relative or absolute path. It could point to a remote shared folder too, allowing multiple clients to use a centralized configuration file.
You could enumerate all *.json files under the current folder and add them one after the other, eg :
var jsonFiles=Directory.EnumerateFiles(".","*.json", SearchOption.AllDirectories);
foreach(var path in jsonFiles)
{
builder.AddJsonFile(path);
}

Referencing a file inside of a Project without using its absolute path?

I'm using StreamReader to dynamically replace content in an HTML template. The HTML file has been imported into my project.
Right now I'm having to referencing the HTML file a static location on my dev box because I'm not able to find the right syntax to reference it once it's been imported into my VS project.
How do I refer to the file without using an absolute path?
Current implementation for reference:
StreamReader reader = new StreamReader(#"C:\Users\n00b\Desktop\EmailTemplate.html");
{
body = reader.ReadToEnd();
}
One common thing I've seen is to put the file's location in a configuration file. This lets you change the file location at will without having to recompile.
You can add it as an embedded resource and extract it this way.
using (Stream stream = System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("<namespace>.Resources.EmailTemplate.html"))
per your comment
using (System.IO.StreamReader sr = new StreamReader(System.Reflection.Assembly.GetExecutingAssembly().GetManifestResourceStream("<namespace>.Resources.EmailTemplate.html"))
{
body = sr.ReadToEnd();
}
There are 2 main ways to do this, In a desktop application, the current directory of the .exe is set to the directory where it is launched from by default. Unless that is changed by launching the .exe by a shortcut with special settings, or by another process using a special feature, it should be the default value. If that is the case, you can just use a relative path. For example, if you have a file named "data.txt" in a folder called "things" inside a folder called "stuff" in the same directory as your app, you can just us the relative path "stuff/things/data.txt" directly and Windows will work it out for you.
If you need to be absolutely sure you are targeting that file, even if the app launches with a modified current directory, you can get the .exe's path, and combine it with a relative path using System.IO.Path.Combine.
var appPath = Assembly.GetEntryAssembly().Location;
var filePath = "stuff/things/data.txt"
var fullPath = System.IO.Path.Combine(appPath, filePath)
If, for some reason, you need to up "up" from the application's directory, you can use ".." to represent that parent folder of a directory. So "../data.txt" would look in the folder that contains the current directory for a file named "data.txt".
You could also change the app's current directory when it starts to be the directory of the .exe, and then reference everything via relative path, as in the first example.
var appPath = Assembly.GetEntryAssembly().Location;
System.IO.Directory.SetCurrentDirectory(appPath);
I found two solutions to this:
If you don't care if the external file is visible in the build directory/installdir of your app:
StreamReader reader = new StreamReader(#"../../EmailTemplate.html");
{
body = reader.ReadToEnd();
}
If you want your external file to be invisible once compiled:
var embeddedResource = "<namespace>.EmailTemplate.html";
using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedResource))
{
StreamReader sr = new StreamReader(stream);
body = sr.ReadToEnd();
}
Note the 2nd solution requires adding your external file and changing the build action to "Embedded Resource" on the properties menu of that file within Visual Studio.

Write a text file to a sub-folder

I am trying to write out a text file to: C:\Test folder\output\, but without putting C:\ in.
i.e.
This is what I have at the moment, which currently works, but has the C:\ in the beginning.
StreamWriter sw = new StreamWriter(#"C:\Test folder\output\test.txt");
I really want to write the file to the output folder, but with out having to have C:\ in the front.
I have tried the following, but my program just hangs (doesn't write the file out):
(#"\\Test folder\output\test.txt");
(#".\Test folder\output\test.txt");
("//Test folder//output//test.txt");
("./Test folder//output//test.txt");
Is there anyway I could do this?
Thanks.
Thanks for helping guys.
A colleague of mine chipped in and helped as well, but #Kami helped a lot too.
It is now working when I have:
string path = string.Concat(Environment.CurrentDirectory, #"\Output\test.txt");
As he said: "The CurrentDirectory is where the program is run from.
I understand that you would want to write data to a specified folder. The first method is to specify the folder in code or through configuration.
If you need to write to specific drive or current drive you can do the following
string driveLetter = Path.GetPathRoot(Environment.CurrentDirectory);
string path = diveLetter + #"Test folder\output\test.txt";
StreamWriter sw = new StreamWriter(path);
If the directory needs to be relative to the current application directory, then user AppDomain.CurrentDomain.BaseDirectory to get the current directory and use ../ combination to navigate to the required folder.
You can use System.IO.Path.GetDirectoryName to get the directory of your running application and then you can add to this the rest of the path..
I don't get clearly what you want from this question , hope this get it..
A common technique is to make the directory relative to your exe's runtime directory, e.g., a sub-directory, like this:
string exeRuntimeDirectory =
System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().Location);
string subDirectory =
System.IO.Path.Combine(exeRuntimeDirectory, "Output");
if (!System.IO.Directory.Exists(subDirectory))
{
// Output directory does not exist, so create it.
System.IO.Directory.CreateDirectory(subDirectory);
}
This means wherever the exe is installed to, it will create an "Output" sub-directory, which it can then write files to.
It also has the advantage of keeping the exe and its output files together in one location, and not scattered all over the place.

How can I properly reference this config file so I'm not hard coding the path?

Im trying to reference this config file that is in the same folder as the class that contains this code. I'd like to do some type of relative reference to it, so I can use it from other places. When I try using just the file name without the path, the application doesn't find the file. I debugged and the folder it seems to be looking in IIS folder which makes sense as Im using it in an IIS hosted wcf service. Anyways, how I can properly reference this config file without hard coding the path? So it looks in the project location. Thanks for any help. Have a great weekend!
public void Init()
{
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = #"C:\workspace\new\UnityDemo-v1.0.0.1\src\Core\unity.config" };
Configuration configuration = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
var unitySection = (UnityConfigurationSection)configuration.GetSection("unity");
_container = new UnityContainer().LoadConfiguration(unitySection);
}
Cheers,
~ck
Using config files with services hosted in IIS is tricky, because the application directory is the one IIS runs in and that will be heavily protected against placing any files there. There may be other ways but for me it works to name the file web.config and copy it to the directory the .svc file resides in and then you can read the settings directly without having to reference the config file. I do not know of any way to do this copying from within the program itself. The installer will be able to do it though.
See: this question
Use Application.StartupPath to get the path the application started in then simply combine with the filename to get the full path:
var filePath = Path.Combine(Application.StartupPath, "unity.config");
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = filePath };
This will work only in winforms.
Another option is to use Environment.CurrentDirectory - by default it will be set to the process startup directory. Note that this property is mutable:
var filePath = Path.Combine(Environment.CurrentDirectory, "unity.config");
var fileMap = new ExeConfigurationFileMap { ExeConfigFilename = filePath };
Another option that worked for me in .NET is using Server.MapPath. This returns the full path of the given relative virtual path in the web application.
var filePath = Server.MapPath("/unity.config")
This physical file path can then be used to create the file map as above.

Categories

Resources