Getting DLL's 'Content' file from web app - c#

I have a class library that has some text files with Build Action = Content. These text files are read by a function within the class library. To get the location of the text files I use this:
var filePath = System.IO.Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"AFolder",
"textFileName.txt");
var fileContent = System.IO.File.ReadAllText(filePath);
I have successfully retrieved the content of the text file when I called the function from a unit test. The text file is in C:\MySolution\MyProject.Test\bin\Debug\AFolder\textFileName.txt.
I have another web app that references this class library. When I called the function to read the text file from the web app, it couldn't find the text file because it tried to get the file from C:\MySolution\MyProject.Web\AFolder\textFileName.txt while the text file is actually in C:\MySolution\MyProject.Web\bin\AFolder\textFileName.txt.
So my problem is calling AppDomain.CurrentDomain.BaseDirectory doesn't always work. What should I use instead to get the folder location?

Found the answer from the link on the right by using System.Reflection.Assembly.GetExecutingAssembly().CodeBase:
var libPath = System.IO.Path.GetDirectoryName(
new Uri(
System.Reflection.Assembly.GetExecutingAssembly().CodeBase
).LocalPath
);
var filePath = System.IO.Path.Combine(
libPath,
"AFolder",
"textFileName.txt");
var fileContent = System.IO.File.ReadAllText(filePath);

You can try System.WebHttpRuntime.BinDirectory to get the physical path to the /bin directory for the current application.
EDIT 1:
Another way to get without using System.Web is using AppDomain.CurrentDomain.SetupInformation.PrivateBinPath, this property provides list of directories under the application base directory that are probed for private assemblies.

Related

Package a Folder in C#

I'm looking to make a program to make my life easier, I need to be able to easily select a folder, which I can do, I don't need help with that. I want to take the directory of a folder, and put that folder into a new folder with a specified name, and then zip up that folder into a zip format in which I can change the name and filetype of. Is this possible in vanilla C#? I've only ever done files for text and I've never looked at moving and packaging files. SO I'm really clueless, I'd just like to be guided into the right direction.
Edit: I found this code online, but I need to put the folder inside another folder, may I adapt upon this to do so?
string startPath = #"c:\example\start";
string zipPath = #"c:\example\result.zip";
string extractPath = #"c:\example\extract";
ZipFile.CreateFromDirectory(startPath, zipPath);
ZipFile.ExtractToDirectory(zipPath, extractPath);
So, after an extended chat discussion, here's what we've established.
The goal is to put the contents of a source directory into a zip with the following structure:
- Payload
|- name of source
|-- contents of source
Okay, so, starting from an input path called startPath:
var parent = Path.GetDirectoryName(startPath);
var payload = Path.Combine(parent, "payload");
Directory.CreateDirectory(payload); // ensure payload ex
Directory.Move(startPath, Path.Combine(payload, Path.GetFileName(startPath));
var zipPath = Path.Combine(parent, "export.zip");
File.Delete(zipPath);
ZipFile.CreateFromDirectory(payload , zipPath, CompressionLevel.Optimal, true);
The key is that true in the CreateFromDirectory call, that puts the entries in the archive under a directory with the same name as the directory being zipped (in this case, "payload"). Feel free to change CompressionLevel to other values if you want.
Now, this has the side effect of actually physically moving the source directory, which might not be the best user experience. If you want to avoid that, you'll have to basically do what ZipFile.CreateFromDirectory does by hand, which is to enumerate the source directory yourself and then copy the files into the zip archive (in which case you can name those files whatever you want):
var parent = Path.GetDirectoryName(startPath);
var zipPath = Path.Combine(parent, "export.zip");
File.Delete(zipPath);
using var zip = ZipFile.Open(zipPath, ZipArchiveMode.Create);
foreach(var file in Directory.EnumerateFiles(startPath, "*", SearchOption.AllDirectories))
{
// get the path of the file relative to the parent directory
// this gives us a path that starts with the source directory name
// e.g. C:\example\start\file.txt -> start\file.txt
var relativePath = Path.GetRelativePath(parent, file);
// construct the path of the entry in the archive
// this is "Payload", and then the relative path of the file
// we need to fix up the separators because zip entries use /
// e.g. start\file.txt -> Payload/start/file.txt
var entryPath = Path.Combine("Payload", relativePath).Replace(Path.DirectorySeparatorChar, '/');
// put the file in the archive
// to specify a compression level, pass it as the third parameter here
zip.CreateEntryFromFile(file, entryPath);
}

cannot find the path to the resource file c#

firstly apology if this has already been answered and I am duplicating the question. I have tried to find the answer to my issue but have failed and none of the auto-suggestions answers my problem.
I have my main project (XAML) and also a class library project called FileStore for files. The class library project is referenced into the main project and I have images and icon file in the class library project that I can access with no issues in my main project, however, I struggle to get the content of a txt file from the CL project to display in a label on the main project. I get the error: the system could not find the file and from the error, I can see that it is trying to look for a file in the main project bin\debug folder
I tried to follow this previous post which seemed to partly answer my issue but to no avail sadly.
Get relative file path in a class library project that is being referenced by a web project
The txt file Build action is set to: Resource and Copy to Output Directory set to: Copy Always.
As I mentioned I have the FileStore project referenced in my main project and the images work fine.
Below is the code I am using, I have tried different variations such as:
\Resources\textFile.txt and \textFile.txt, still no luck.
'''
public static string ReadFileinClLibr()
{
var buildDir =
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var filePath = buildDir + #"\textFile.txt";
return File.ReadAllText(filePath);
}
'''
For comparition here is the path for the image files that works, but I cannot get it to work with the txt file, as the error reads: the given paths format is not supported..
'''
#"pack://application:,,,/FileStore;component/Resources\textFile.txt"
'''
I want to be able to input the content of the text file from the class library project to the label in the main xaml project.
At the moment compiler keeps looking for this file in a debug folder of the main project, what I want is, for the compiler to look for the txt file in a CL FileStore project
In order to access the file all the time, we have to have the file copied to the debug folder. Right click the file from solution explorer change the properties then try to access the file from the executing assembly location.
StringBuilder bodyContent = new StringBuilder();
string fileName = "myfile.txt";
try
{
string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), fileName);
using (StreamReader sr = new StreamReader(filePath))
{
// Read the stream.
bodyContent.Append(sr.ReadToEnd());
}
}
catch(Exception ex)
{
Console.WriteLine(String.Format("{0} # {1}", "Exception while reading the file: " + ex.InnerException.Message, DateTime.Now));
throw ex;
}
Thanks to the post from #Sreekanth Gundlapally I have managed to fix my issues. I have mostly drawn on from the answer provided by #Sreekanth Gundlapally but there is one important bit missing. The string fileName should include any subfolders that the resource file is within in the Class Library Project, for example in my case the folder was named 'Resources' so the code should look like this:
string fileName = #"Resources/myfile.txt";
try
{
string filePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), fileName);
using (StreamReader sr = new StreamReader(filePath))
{
// Read the stream.
bodyContent.Append(sr.ReadToEnd());
}
I have also cleaned and rebuilt solution after which it all worked a charm.
Also a side note, anyone trying this and getting funny characters make sure your file's encoding is set to UTF-8 as this is the default encoding used by StreamReader, otherwise your file content may not be read correctly if it contains signs such as apostrophe.

How to get the file relative path in c# service project?

I have this code:
Stream stream = new StreamReader("~/quartz.xml").BaseStream;
Q1:What is the "~" symbol specify path in C#?
Q2:How to get the "~" directory in C# service project?
Q3:Does it mean the bin exe directory or project name directory?
The quartz.xml file in my Windows service project located in two position:
D:\jsptpd\Code\jsptpdJobScheduler\jsptpdJobScheduler\bin\Debug
D:\jsptpd\Code\jsptpdJobScheduler\jsptpdJobScheduler
Sure the path will change everytime!So get the relative path is better.
Just omit it entirely:
Stream stream = new StreamReader("quartz.xml").BaseStream;
The default directory is the .exe's directory.
Per the OP's edit to the question:
Go to View > Solution Explorer. Right-click the file in question, then choose Properties. Change the Copy To Output Directory option to Copy Always. Then use the code above.
if we use(../quartz.xml):
the StreamReader read path is(not the file actual path):
C:\Windows\quartz.xml
if we use(quartz.xml):
the StreamReader read path is(not the file actual path):
C:\Windows\system32\quartz.xml
This is the way to find the file relative path:
string assemblyFilePath = Assembly.GetExecutingAssembly().Location;
string assemblyDirPath = Path.GetDirectoryName(assemblyFilePath);
string configFilePath = assemblyDirPath + "\\quartz.xml";
Stream stream = new StreamReader(configFilePath).BaseStream;
So the path is(you can specify either of two):
D:\jsptpd\Code\jsptpdJobScheduler\jsptpdJobScheduler\bin\Debug\quartz.xml

Bundle a folder with a .Net application

How can I bundle a folder with a one click application and reference those files/folders after?
Seems rather simple but I just can't figure out how.
As in, I had the file index.html in the folder UI and I wanted to package that with the application, then I want to get the stream for that file with the string "/UI/index.html" but instead of just index.html, an entire website.
Add the folder to your VS Project, right-click on it and select "embed as resource". That will make the files in the folder be embedded in the .NET assembly. To get the file contents in your program, you can use something like this:
public class ReadResource
{
public string ReadInEmbeddedFile (string filename) {
// assuming this class is in the same assembly as the resource folder
var assembly = typeof(ReadResource).Assembly;
// get the list of all embedded files as string array
string[] res = assembly.GetManifestResourceNames ();
var file = res.Where (r => r.EndsWith(filename)).FirstOrDefault ();
var stream = assembly.GetManifestResourceStream (file);
string file_content = new StreamReader(stream).ReadToEnd ();
return file_content;
}
}
In the above function I assume your files a text/html files; if not, you can change it not to return string but byte[], and use a binary stream reader for that.
I also select the files by file.EndsWith() which is enough for my needs; if your folder has a deep nested structure you need to modify that code to parse for folder levels.
Perhaps there is a better way, but given the content is not too large you can embed binaries directly into your program as a base64 string. In this case it would need to be an archive of the folder. You would also need to embed the dll used for unzipping that archive (If I understood correctly you want to have single .exe and nothing more).
Here is a short example
// create base64 strings prior to deployment
string unzipDll = Convert.ToBase64String(File.ReadAllBytes("Ionic.Zip.dll"));
string archive = Convert.ToBase64String(File.ReadAllBytes("archive.zip"));
string unzipDll = "base64string";
string archive = "probablyaverylongbase64string";
File.WriteAllBytes("Ionic.zip.dll", Convert.FromBase64String(unzipDll));
File.WriteAllBytes("archive.zip", Convert.FromBase64String(archive);
Ionic.Zip.ZipFile archive = new Ionic.Zip.ZipFile(archiveFile);
archive.ExtractAll("/destination");
The unzipping library is DotNetZip. It's nice because you need just a single dll. http://dotnetzip.codeplex.com/downloads/get/258012
Edit:
Come to think of it, as long as you write the Ionic.dll to the working directory of the .exe you shouldn't need to use the dynamic dll loading so I removed that part to simplify the answer (it would still need to be written before you reach the method it is in though).

Load local HTML file in a C# WebBrowser

In my app I have a WebBrowser element.
I would like to load a local file in it.
I have some questions:
Where to place the HTML file (so that it will also be installed if a user executes the setup)
how to reference the file? (e.g. my guess is the user's installation folder would not always be the same)
EDIT
I've added the HTML file to my project.
And I have set it up so that it gets copied to output folder.
When I check it it is present when run: \bin\Debug\Documentation\index.html
However when I do the following I get a 'Page cannot be displayed' error in the webbrowser element.
I use the following code to try to display the HTML file in the Webbrowser.
webBrowser1.Navigate(#".\Documentation\index.html");
Do a right click->properties on the file in Visual Studio.
Set the Copy to Output Directory to Copy always.
Then you will be able to reference your files by using a path such as #".\my_html.html"
Copy to Output Directory will put the file in the same folder as your binary dlls when the project is built. This works with any content file, even if its in a sub folder.
If you use a sub folder, that too will be copied in to the bin folder so your path would then be #".\my_subfolder\my_html.html"
In order to create a URI you can use locally (instead of served via the web), you'll need to use the file protocol, using the base directory of your binary - note: this will only work if you set the Copy to Ouptut Directory as above or the path will not be correct.
This is what you need:
string curDir = Directory.GetCurrentDirectory();
this.webBrowser1.Url = new Uri(String.Format("file:///{0}/my_html.html", curDir));
You'll have to change the variables and names of course.
quite late but it's the first hit i found from google
Instead of using the current directory or getting the assembly, just use the Application.ExecutablePath property:
//using System.IO;
string applicationDirectory = Path.GetDirectoryName(Application.ExecutablePath);
string myFile = Path.Combine(applicationDirectory, "Sample.html");
webMain.Url = new Uri("file:///" + myFile);
Note that the file:/// scheme does not work on the compact framework, at least it doesn't with 5.0.
You will need to use the following:
string appDir = Path.GetDirectoryName(
Assembly.GetExecutingAssembly().GetName().CodeBase);
webBrowser1.Url = new Uri(Path.Combine(appDir, #"Documentation\index.html"));
Place it in the Applications setup folder or in a separte folder beneath
Reference it relative to the current directory when your app runs.
Somewhere, nearby the assembly you're going to run.
Use reflection to get path to your executing assembly, then do some magic to locate your HTML file.
Like this:
var myAssembly = System.Reflection.Assembly.GetEntryAssembly();
var myAssemblyLocation = System.IO.Path.GetDirectoryName(a.Location);
var myHtmlPath = Path.Combine(myAssemblyLocation, "my.html");
What worked for me was
<WebBrowser Source="pack://siteoforigin:,,,/StartPage.html" />
from here. I copied StartPage.html to the same output directory as the xaml-file and it loaded it from that relative path.
Windows 10 uwp application.
Try this:
webview.Navigate(new Uri("ms-appx-web:///index.html"));
Update on #ghostJago answer above
for me it worked as the following lines in VS2017
string curDir = Directory.GetCurrentDirectory();
this.webBrowser1.Navigate(new Uri(String.Format("file:///{0}/my_html.html", curDir)));
I have been trying different answers from here, but managed to derive something working, here it is:
1- Added the page in a folder i created at project level named WebPagesHelper
2- To have the page printed by webBrowser Control,
string curDirectory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().GetName().CodeBase);
var uri = new Uri(curDirectory);
string myFile = Path.Combine(uri.AbsolutePath, #"WebPagesHelper\index.html");
Uri new_uri = new Uri(myFile);
i had to get the assembly path, create a first uri to get an absolute path without the 'file://' attached, next i combined this absolute path with a relative path to the page in its folder, then made another URI from the result.
Then pass this to webBrowser URL property webBrowser.URL = new_uri;

Categories