We are using the new DbMigration.SqlFile method in EF Migrations 6.1.2 to run a migration script in our migration. According to the documentation, the file has to be relative to the current AppDomain BaseDirectory. We have included these files in the project, and set them to copy to output directory.
Locally this all runs fine. They get output to the bin directory, and run fine.
When deploying the software to a server running IIS however, the migration fails, because it suddenly expects the files to be relative to the root. When I copy them there, the migration works.
How can I use DbMigration.SqlFile so it runs correctly both locally and on the server?
The SqlFile method uses the CurrentDomain.BaseDirectory if a relative path is given. A workaround is to map the path yourself and give an absolute path to the method. A solution would look like this:
var sqlFile = "MigrationScripts/script1.sql";
var filePath = Path.Combine(GetBasePath(), sqlFile);
SqlFile(filePath);
public static string GetBasePath()
{
if(System.Web.HttpContext.Current == null) return AppDomain.CurrentDomain.BaseDirectory;
else return Path.Combine(AppDomain.CurrentDomain.BaseDirectory,"bin");
}
BasePath solution taken from: Why AppDomain.CurrentDomain.BaseDirectory not contains "bin" in asp.net app?
We're using it like this from within the migration: SqlFile(#"..\..\Sql\views\SomeView.sql");
Related
I have some Selenium C# tests hosted on Azure which they need to look for the pre-built excel file in project tree, stored inside bin folder, to execute some file upload validation scenarios.
When they are executed locally these scenarios pass without any problem, but when it comes to be executed on the Azure they receive the following error.
invalid argument: File not found : D:\a\r1\a_Selenium_Tests\TestApplication\bin\Debug\netcoreapp3.1\Files\SC003_CT014_ActiveEmployees.xlsx
The files do exists in the following path: ...\bin\Debug\netcoreapp3.1\Files...
And the code I use to them is:
string root = Directory.GetCurrentDirectory() + "\\Files\\" + file;
Do you know if there's a missing file configuration or building the filePath in another way?
Thanks for your help :D
Directory.GetCurrentDirection() returns the current working directory, not the folder in which the DLL file resides. The current working directory is a different thing. In your case, the current working directory is probably something like D:\a\r1\. Instead, you need to get the folder in which the test assembly resides:
var binDirectory = Path.GetDirectoryName(GetType().Assembly.Location);
// ^^^^^^^^^
var excelFilePath = Path.Combine(binDirectory, "Files", "SC003_CT014_ActiveEmployees.xlsx");
Note: Replace GetType() with typeof(ClassName) if you are executing your code from a static method, or you would like to specify a path to a different assembly than the one that is currently executing.
I need to load in an XML schema file to validate some information on a .Net Core 2.1 api that is on a linux server. Unfortunately, I do not have access to this server (we use jenkins to deploy so I have 0 contact with it), so I can only test on my computer which is Windows 10.
I have tried the following:
System.AppContext.BaseDirectory
System.AppContext.BaseDirectory.Substring(0, AppContext.BaseDirectory.IndexOf("bin"));
AppDomain.CurrentDomain.BaseDirectory
Directory.GetCurrentDirectory()
GetType().Assembly.Location
System.Reflection.Assembly.GetExecutingAssembly().Location
System.Reflection.Assembly.GetExecutingAssembly().CodeBase
All of these return the current execution location on Windows (i.e. C:/SomePath/SomeProject/Name/api.dll) which I can use with Path.Combine to produce the path to the schema file.
However, on linux, these all return /home/app/ which is not where the dll should be according to the Jenkins logs. This is leading to failures loading the schema file. The project is actually located under /services/projectname/.
Test Code:
var schema = new XmlSchemaSet { XmlResolver = new XmlUrlResolver() };
schema.Add(null, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Schema/schema.xsd"));
Expected: On Windows and Linux this loads the schema file using the .dll execution path as the base.
Actual: On Linux I get home/app instead of the correct path.
Edit: I cannot hardcode the path. The path changes on every deployment as the project name is versioned. This means the second I deploy it, any hardcoded value will be incorrect. I absolutely require a relative path. Beyond that technical requirement, hard coding is a major taboo. I will never get it past a code review.
For me, in dotnet core 3.1 the following statement works for a console application in both Windows and Ubuntu:
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
With asp.net core 1.0 There are lots of functionality added. But there is not way to get Bin Folder path.
Can anyone please know how we can get the bin folder path for asp.net core 1.0 application.
Alternative way (corresponds to the AppDomain.BaseDirectory):
AppContext.BaseDirectory
This works to retrieve the assembly's directory, from which we can determine the bin location.
var location = System.Reflection.Assembly.GetEntryAssembly().Location;
var directory = System.IO.Path.GetDirectoryName(location);
System.Console.WriteLine(directory);
Output
C:\MyApplication\bin\Debug\netcoreapp1.0
Well, the bin folder does exists but it is moved to artifacts folder next to the solution file. Since ASP.NET Core RC 1 compiles everything in memory, you will find empty bin folder. But if you set "Produce output on build" option to true (Right click Project file -> Properties and Build tab) then you will find the generated files in bin folder.
I don't think so there is any direct property available as to get the path of this but you can use the same solution pointed out by #Nikolay Kostov to get application path. And then using System.IO classes jump to bin folder.
Code updated to for ASP.NET Core as mentioned here.
http://www.talkingdotnet.com/get-application-wwwroot-path-aspnet-core-rc2/
public Startup(IHostingEnvironment env, IApplicationEnvironment appenv)
{
string sAppPath = env.ContentRootPath;
string sRootPath = Path.GetFullPath(Path.Combine(sAppPath, #"..\..\"));
string sBinFolderPath = #"artifacts\bin\" + appenv.ApplicationName;
string sBinPath = Path.Combine(sRootPath, sBinFolderPath);
}
You can't really get the /bin/ folder since it is not relevant to your project and the ASP.NET environment doesn't know what a /bin/ folder is.
And also there isn't exactly a /bin/ folder. You may want to read this article: http://docs.asp.net/en/latest/conceptual-overview/understanding-aspnet5-apps.html
But you can get the so called ApplicationBasePath which is the directory in which you application runs:
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv)
{
string baseDir = appEnv.ApplicationBasePath;
// Other startup code
}
AppDomain.CurrentDomain.BaseDirectory;
I want to be able to set default folder and file creating inside of the folder where the app is installed? Because this app will be used on multiple machines so I cannot specify path like C://Users/PcName/etc.. Is there any very simple way of doing it?
What you are trying to do is not advisable; if your application is installed using recommended default methods (following Microsoft guidelines) the app will be in a directory under C:\Program Files (or where the program files folder may be redirected) and the user that runs the app will not have write access to that directory, so the directory creation will fail.
That said, you cannot use the Environment.CurrentDirectory, because it may or may not be the directory where your application's executable files reside, neither CurrentDomain.BaseDirectory, because that is not significative too (documentation says it's the directory where the loader will search for assemblies, but that may or may not be the directory of your application's executable files).
Copying from this other answer, the correct way to find the directory of your assembly is
public static string AssemblyDirectory
{
get
{
string codeBase = Assembly.GetExecutingAssembly().CodeBase;
UriBuilder uri = new UriBuilder(codeBase);
string path = Uri.UnescapeDataString(uri.Path);
return Path.GetDirectoryName(path);
}
}
Once you have the path, you can try to create the directory with System.IO.Directory.CreateDirectory() and a file with System.IO.File.WriteAllText() or its siblings, or any other standard method of creating files.
You may also want to use the newer Assembly.GetExecutingAssembly().Location property, and use Path.GetDirectoryName() on that.
This applies to both web and windows apps:
Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
You can get the path for the executable using this code (most of the time, actually it returns the current working directory)
System.Environment.CurrentDirectory
If you only specify a path that doesn't start with a drive letter then the path will be relative to where the application is running. e.g. The following program will create a folder and file in the application's local folder.
class Program
{
static void Main(string[] args)
{
var installedLocation = Directory.GetParent(Assembly.GetExecutingAssembly().Location);
var di = installedLocation.CreateSubdirectory("MyFolder");
File.WriteAllText(Path.Combine(di.FullName, "File.txt"), "This will be written to the file");
var installedPath = AppDomain.CurrentDomain.BaseDirectory;
var di2 = Directory.CreateDirectory(Path.Combine(installedPath, "MyFolder2"));
File.WriteAllText(Path.Combine(di.FullName, "File2.txt"), "This will be written to the file");
}
}
I have created a windows service in c# .Net 4.0.
In VS it works great, I have built the project and installed the exe as a service which does run.
I have found that when operating as a service the application does not reference application configuration files I have placed in the same directory as the service exe.
If I strongly type the full file path in code there is no problem, however this is not an ideal solution as users could install things where ever they like.
How can I make the application reference (look for) files local to the EXE and not I assume where the .Net service wrapper is located.
Nothing seems to be helpful on google.
Example
Does Work:
var config =
ClassLib.XmlInterface.DeserializeConfiguration(
"C:\\Users\\Damo\\Documents\\Visual Studio 2010\\Projects\\FileDownloadService\\FileDownloadService\\bin\\Debug\\config.xml");
Does not work: (dispute been local to the EXE)
var config =
ClassLib.XmlInterface.DeserializeConfiguration(
"config.xml");
There are a couple of ways to resolve this.
You could create an environment variable, and read the path from it. This is kind of kludgy, if you don't have a Setup application, and it's prone to breakage if users muck with their settings. But it will work if you do it correctly.
If you have a setup application, you could also store the path to your executable in the Registry, and read it at runtime.
Or, you can try retrieving the path to your assembly at runtime using something like this:
public static string GetCoreAssemblyPathRoot()
{
const string AssemblyName = "MyAssemblyName,";
var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
var path = (from assembly in loadedAssemblies
where assembly.FullName.StartsWith(AssemblyName)
select Path.GetDirectoryName(assembly.Location))
.FirstOrDefault();
if (path == null)
{
return null;
}
// The last part of the path is "\bin". Remove it, and return the remainder.
var index = path.IndexOf("\\bin\\");
return index == -1
? path
: path.Substring(0, index);
}