Problem with deployment of windows application using setup wizard - c#

I have some xml files, which are used in my application. They are stored in the same folder with application , in subfolder DATA: "C:\MyProject\DATA\".
To get the DATA folder path i use this code :
static public string GetDataFolderPath()
{
string s = System.IO.Directory.GetCurrentDirectory().Replace(#"\bin\Debug", "");
int i = s.LastIndexOf(#"\");
s = s.Substring(0, i);
i = s.LastIndexOf(#"\");
s= s.Substring(0, i);
return s + #"\Data\";
}
So when i want to deploy my application, i create a setup project, and add the DATA folder to Application folder. But after i install the program f.e. "C:\Project"(DATA folder- "C:\Project\DATA" i got the error: "folder C:\DATA is not found".
What i need to change to make things working after deployment. Why it looks for the DATA folder on 1 level higher?

Try this, it might work better:
public static string GetDataFolderPath()
{
#if DEBUG
// This will be executed in Debug build
string path = Directory.GetCurrentDirectory().Replace(#"\bin\Debug", "");
#else
// This will be executed in Release build
string path = Directory.GetCurrentDirectory();
#endif
return Path.Combine(path, "Data");
}
Or just this if you want one for both Debug and Release builds:
public static string GetDataFolderPath()
{
string path = Directory.GetCurrentDirectory().Replace(#"\bin\Debug", "");
return Path.Combine(path, "Data");
}
You have to add using System.IO; for this to work.

Maybe current directory (during launching your program) is not the same one that assemblies lie?
try:
//get the full location of the assembly
string fullPath = System.Reflection.Assembly.GetAssembly(typeof(<your class name>)).Location;
//get the folder that's in
string theDirectory = Path.GetDirectoryName( fullPath );
or
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);

Related

How to get the path of folder in Azure Function C#

I have created 2 folders in my project named TempFile and TempFile\Sample. Here is the folder structure
How can I get the path of this folder and the file SampleExcel.xlsx (project\TempFile and project\TempFile\Sample\SampleExcel.xlsx resp) using c#. Also once I publish it to Azure will I need to change it?
Here is what I have tried:
public void Run([QueueTrigger("my-queuename", Connection = "")] string myQueueItem, ILogger log)
{
//Method 1
var dir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
//Method 2
var path = Environment.CurrentDirectory;
//Method 3
var filePath = Path.GetFullPath(#"TempFile\Sample" + "\\SampleExcel.xlsx");
}
The problem with these methods is that they return the path project\bin\Debug\netcoreapp3.1
How can I get the required path?
Any suggestions?
Use Environment.CurrentDirectory as:
filePath1 = Environment.CurrentDirectory +"\\TempFile\\" + tempFile + ".xlsx";
filePath2 = Environment.CurrentDirectory +"\\TempFile\\Sample\\SampleExcel.xlsx";

C# : File rename using ASP:NET MVC and IISExpress

I have a utility to rename a file in a specified directory using a certain condition. Running the code using a console application works well and the file is renamed appropriately. However, when I attempt the same in a web application the file is not getting renamed. I am using VS2017 Development Server for the web application debugging.
What am I missing?
Using the console application code as below the file successfully gets renamed :
Rename method:
public static string AddSuffix(string filename, string suffix)
{
string fDir = Path.GetDirectoryName(filename);
string fName = Path.GetFileNameWithoutExtension(filename);
string fExt = Path.GetExtension(filename);
string renamedFilePath = Path.Combine(fDir, String.Concat(fName, suffix, fExt));
return renamedFilePath;
}
Usage in main program:
static void Main(string[] args)
{
string batchperiod = "_70_";
string realPath = #"C:\Users\myuser\source\repos\Solution\Project\BatchIn";
IEnumerable<string> fileList = Directory.EnumerateFiles(realPath);
var CurrentBatchName = (from file in fileList
let fileName = Path.GetFileName(file)
where fileName.Contains(batchperiod)
select fileName).FirstOrDefault();
string absolutePath = (#"C:\Users\myuser\source\repos\Solution\Project\BatchIn\" + CurrentBatchName);
string newPath = Helpers.AddSuffix(absolutePath, String.Format("({0})", Helpers.parameters.IsProcessed));
System.IO.FileInfo fi = new System.IO.FileInfo(absolutePath);
if (fi.Exists)
{
fi.MoveTo(newPath);
}
}
With this code the file is successfully renamed from
GL_Export_70_201907081058.xml
to
GL_Export_70_201907081058(P).xml
The only difference using web application is that the absolutePath is stored in a Session variable .. its derived from a preceding operation/ActionResult :
var absolutePath = (#"C:\Users\myuser\source\repos\Solution\Project\BatchIn\" + CurrentBatchName);
files.FileName = CurrentBatchName;
Session["AbsoluteBatchPath"] = absolutePath;
and later invoked in another ActionResult as :
var sourceFile = Convert.ToString(Session["AbsoluteBatchPath"]);
string newPath = AddSuffix(sourceFile, String.Format("({0})", parameters.IsProcessed));
System.IO.FileInfo fi = new System.IO.FileInfo(sourceFile);
if (fi.Exists)
{
// Move file with a new name. Hence renamed.
fi.MoveTo(newPath);
}
What am I missing?
I do suspect there are some permissions I may need to configure when attempting the rename using the Visual Studio Development Server.
Your code see perfect there is no missing ,debug and check whether in MVC your code entered fi.exist if condition..
Please confirmed the same

What is the best way to get the fullpath of an application that is not running?

I am trying to get the path of application "WinMergeU.exe" using Path.GetFullPath() but the return value of this code is the folder of my application.
How can i get the fullpath of the application in C: drive while the return value is d using the Path.GetFullPath().
You have to search for the file, e.g.
using system.Linq;
...
// Either full path of "WinMergeU.exe" file or null (if not found)
string result = Directory
.EnumerateFiles(#"c:\", "WinMergeU.exe", SearchOption.AllDirectories)
.FirstOrDefault();
Edit: In case the application is in the C:\Program Files (see comments) we can restrict the scan:
string result = Directory
.EnumerateFiles(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
"WinMergeU.exe",
SearchOption.AllDirectories)
.FirstOrDefault();
Or (if we quite sure in c:\Program Files\WinMerge path) we can just test if the file exits:
string result = Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles),
"WinMerge",
"WinMergeU.exe");
if (File.Exists(result)) {
// we have the file
}
I installed it, as it looked like a handy tool, and searched the registry.
string key = #"HKEY_LOCAL_MACHINE\SOFTWARE\Classes\WinMerge.Project.File\shell\open\command";
string path = Microsoft.Win32.Registry.GetValue(key, "", -1);
... seems to contain the value you need. In my case:
"C:\Program Files (x86)\WinMerge\WinMergeU.exe" "%1"
The method will return -1 if the key is not found.
WinMerge doesn't allow to change its installation folder AFAIK, therefore searching the whole drive C is an overkill.
This will suffice:
static string GetWinMergeFullPath()
{
const string executableName = "WinMergeU.exe";
const string installationFolder = "WinMerge";
var locations = new Environment.SpecialFolder[]
{
Environment.SpecialFolder.ProgramFiles,
Environment.SpecialFolder.ProgramFilesX86
};
string fullPath = locations
.Select(l => Path.Combine(Environment.GetFolderPath(l), installationFolder, executableName))
.Where(File.Exists)
.FirstOrDefault();
return fullPath ?? throw new FileNotFoundException(executableName);
}
EDIT
As it was commented the above won't suffice:). The below version uses two registry locations that should contain the path. One is "App Paths" which is provided by the installation, the second one is "Uninstall". While I believe that "App Paths" should be enough I still provided the second one for robustness.Note that it will work even if shell integration is unchecked in the installer! Both 32-bit and 64-bit installations are covered.
static string GetWinMergeFullPathFromRegistryEx()
{
const string executableName = "WinMergeU.exe";
const string appPathKeyName = #"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\";
const string uninstallKeyName = #"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\WinMerge_is1";
const string installLocationName = "InstallLocation";
var locations = new List<(string path, string value, bool withFilename)>
{
($"{appPathKeyName}{executableName}", null, true),
(uninstallKeyName, installLocationName, false),
};
List<RegistryView> views = Environment.Is64BitOperatingSystem ?
new List<RegistryView>() { RegistryView.Registry32, RegistryView.Registry64 } :
new List<RegistryView>() { RegistryView.Default };
foreach (var view in views)
{
using (RegistryKey localMachine = RegistryKey.OpenBaseKey(RegistryHive.LocalMachine, view))
foreach (var (path, value, withFilename) in locations)
{
using (RegistryKey key = localMachine.OpenSubKey(path, false))
{
var fullpathValue = key?.GetValue(value);
if (fullpathValue != null)
{
string fullpath = (string)fullpathValue;
if (!withFilename)
fullpath = Path.Combine(fullpath, executableName);
if (File.Exists(fullpath))
return fullpath;
}
}
}
}
throw new FileNotFoundException(executableName);
}
Of course my assumption is that WinMerge was actually installed. If you should support cases when WinMerge was deployed manually then you still can use to the full scan option as a fallback.

Can I write a file to a folder on a server machine from a Web API app running on it?

I have this code in my Web API app to write to a CSV file:
private void SaveToCSV(InventoryItem invItem, string dbContext)
{
string csvHeader = "id,pack_size,description,vendor_id,department,subdepartment,unit_cost,unit_list,open_qty,UPC_code,UPC_pack_size,vendor_item,crv_id";
int dbContextAsInt = 0;
int.TryParse(dbContext, out dbContextAsInt);
string csvFilename = string.Format("Platypus{0}.csv", dbContextAsInt);
string csv = string.Format("{0},{1},{2},{3},{4},{5},{6},{7},{8},{9},{10},{11},{12}", invItem.ID,
invItem.pksize, invItem.Description, invItem.vendor_id, invItem.dept, invItem.subdept, invItem.UnitCost,
invItem.UnitList, invItem.OpenQty, invItem.UPC, invItem.upc_pack_size, invItem.vendor_item, invItem.crv_id);
string existingContents;
using (StreamReader sr = new StreamReader(csvFilename))
{
existingContents = sr.ReadToEnd();
}
using (StreamWriter writetext = File.AppendText(csvFilename))
{
if (!existingContents.Contains(csvHeader))
{
writetext.WriteLine(csvHeader);
}
writetext.WriteLine(csv);
}
}
On the dev machine, the csv file is saved to "C:\Program Files (x86)\IIS Express" by default. In preparation for when it is deployed to its final resting/working place, what do I need to do to get the file to save, e.g., to the server's "Platypi" folder - anything special? Do I have to specifically set certain folder persimmons to allow writing to "Platypi."
Is it simply a matter of changing this line:
string csvFilename = string.Format("Platypus{0}.csv", dbContextAsInt);
...to this:
string csvFilename = string.Format(#"\Platypi\Platypus{0}.csv", dbContextAsInt);
?
In the case of the IIS folder the application has rights to write in there. I suggest to write files to the App_Data folder.
When you want to save files outside the IIS application folder you have to give the service account of the IIS application pool (I think it by default is NETWORKSERVICE) the appropriate rights on that folder.
As requested by B. Clay Shannon my implementation:
string fullSavePath = HttpContext.Current.Server.MapPath(string.Format("~/App_Data/Platypus{0}.csv", dbContextAsInt));
Thanks to Patrick Hofman; this is the exact code I am using, and it is saved to the project's App_Data folder:
public static string appDataFolder = HttpContext.Current.Server.MapPath("~/App_Data/");
. . .
string csvFilename = string.Format("Platypus{0}.csv", dbContextAsInt);
string fullSavePath = string.Format("{0}{1}", appDataFolder, csvFilename);

Using GetEnvironmentVariable method to move files

I was using hard-coded directory path to Program Files to move file. I would now like to use the correct method to find the folder in Program Files.
I have found this method doing some Googling and it is what i would like to use:
static string ProgramFilesx86()
{
if( 8 == IntPtr.Size || (!String.IsNullOrEmpty(Environment.GetEnvironmentVariable("PROCESSOR_ARCHITEW6432"))))
{
return Environment.GetEnvironmentVariable("ProgramFiles(x86)");
}
return Environment.GetEnvironmentVariable("ProgramFiles");
}
I unfortunately am not sure how to implement and use this method.
Where do i insert the method in my app?
How do i use the above instead of this:
if (File.Exists(#"C:\PROGRA~1\TEST\ok.txt"))
File.Delete(#"C:\PROGRA~1\TEST\ok.txt");
File.Copy(#"C:\PROGRA~1\PROGRAMFOLDER\ok.txt", #"C:\PROGRA~1\TEST\ok.txt");
It's much easier to get the special folders like Program Files using
Environment.SpecialFolders
string programFilesFolder =
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86)
Continuing that example you could do something like this
string pathToFile =
Path.Combine(programFilesFolder, #"TEST\ok.txt");
if (File.Exists(pathToFile))
File.Delete(pathToFile);
UPDATE
Modified the code example to always get the 32-bit Program Files folder whether you're running 32- or 64-bit OS as #Mario pointed out that's what your original code was doing.
string fileName = Path.Combine( ProgramFilesx86(), applicationPath, #"ok.txt");
if (File.Exists( fileName ) )
{
File.remove( fileName );
}
string sourceFile = Path.Combine( ProgramFilesx86(), #"\PROGRAMFOLDER", "ok.txt" );
File.Copy( sourceFile, fileName);
Edit:
You should not use this method. The program folder depends on the capability of the programs and not the system! You must know whether they install to the ProgramFiles or ProgramFilesX86 folder.
And then use Eric J.'s answer.
string sourceFolder =
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
string source =
Path.Combine(sourceFolder, #"ok.txt");
string targetFolderPath =
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
string target = Path.Combine(targetFolderPath, #"ok.txt");
if (File.Exists(source))
File.Delete(source);
File.Copy(targetFolderPath, source);

Categories