Assembly.GetExecutingAssembly() not looking in the correct path - asp.net

I'm reading an embedded xml file using
C#:
var AssemblyRef = Assembly.GetExecutingAssembly();
TextReader reader = new StreamReader(AssemblyRef.GetManifestResourceStream("Text.xml"));
It has been working for some time, but starting throwing errors. I traced the path that it is looking for and it is looking for the dll in the root of the bin folder and not in the Debug or release folder.
Once it is published this is fine, but for local development I cannot get my one feature to work.
I have it set to Debug when compiling. Any help would be great.

You have:
Changed Assembly Name OR
Changed namespace OR
Moved the resource to a folder in the project

I changed the call to this and everything is fine.
TextReader reader = new StreamReader(Assembly.GetExecutingAssembly().AssemblyRef.GetManifestResourceStream("Text.xml"));
Making the call one statement made it work. I'm not sure why.

Related

IIS Shadow Copied DLL accessing dependency DLLs from bin location

I am trying to resolve an issue with ASP.Net Framework 4.8 site using EFCore 3.1.16 in IIS. Microsoft.Data.SqlClient has a process lock on SNI.dll which causes issues with xcopy deployment in IIS.
I have tried a strategy of copying the SNI.dll to the same shadow copy location as Microsoft.Data.SqlClient so it doesn't have to try and access the DLL in the bin folder as outlined in https://github.com/lscorcia/sqlclient.snishadowcopy.
// Look for the main Microsoft.Data.SqlClient assembly in the
// shadow copy path
var sqlClientShadowAssembly = Directory.GetFiles(
currentShadowPath, "Microsoft.Data.SqlClient.dll",
SearchOption.AllDirectories).FirstOrDefault();
// Extract the directory information from the shadow assembly path
var sqlClientShadowPath =
Path.GetDirectoryName(sqlClientShadowAssembly);
// Find out the process bitness and choose the appropriate native
// assembly
var moduleName = Environment.Is64BitProcess ? "x86\\SNI.dll"
: "x64\\SNI.dll";
// Compute the source and target paths for the native assembly
var sourceFile = Path.Combine(currentPrivatePath, moduleName);
var targetFile = Path.Combine(sqlClientShadowPath, "SNI.dll");
File.Copy(sourceFile, targetFile);
However, it still tries to access the bin location first instead of the sni.dll that is in the same folder location.
I have checked that the Microsoft.Data.SqlClient in the shadow location is being used correctly by deleting the DLL and confirming that a FileNotFound exception is thrown.I have also tried copying directly into the same folder and also copying into an x64 sub folder in the shadow location.
In my case, the error occured only when my IIS application is located on an UNC path (e.g. "\\myserver\myshare\myapplication"). Here is a workaround that worked in my scenario.
Use P/Invoke to SetDllDirectory:
[DllImport(#"kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool SetDllDirectory(string lpPathName);
(See also this MSDN article about DLL load order)
Then, early in my Global.asax.cs Application_Start method (before any DB calls), call it like this:
SetDllDirectory(Server.MapPath(#"~/bin"))
After that, everything works as expected.
I still to consider this to be kind of a hack/workaround, but at least, it is working now in my scenario.
As I do understand, you can call SetDllDirectory multiple times to add additional directories (i.e. not overwrite the existing one).
So in case someone reading this might have other assemblies that refer to native DLLs in "x86" or "x64" folders, one might do something like this:
var bitness = Environment.Is64BitProcess ? #"x64" : #"x86";
SetDllDirectory(Server.MapPath($#"~/bin/{bitness}"));
I've also tried serving my test application from a local path (like "C:\Inetpub\wwwroot") and here, the error does not occur, even when not calling SetDllDirectory.
I'm still not sure why the error occurs for UNC paths only, and not for local paths, as I would expect that the shadow copied managed assemblies to fail the DllImports, too.
(I've also posted the above in this GitHub issue)

Entity Framework migration: access sql file within ASP.NET

I have a ASP.NET Web API project. I'm using Entity Framework Migrations. Currently, I have a custom script that is to be executed during a migration. I'm using the SqlFile method for this:
SqlFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Migrations/Scripts/MyCustomScript.sql"));
This works fine in the integration tests, IF I set the "Copy to Output Directory" of the script to "Copy always".
However, when running the website, the script is copied to <websiteroot>\bin\Migrations\MyCustomScript.sql, while AppDomain.CurrentDomain.BaseDirectory points to the websiteroot. Therefore, an error is thrown stating that the script cannot be found: it resides in the bin folder, not in the root.
How can I load the script so that things work both in the tests and in the actual website?
I would include the script in you dll and than load the script from the dll directly. Than you do not need any if statements and you always know you have the correct scripts included. Set the build action to Embedded resource. Then you can get the script like:
Assembly assembly = Assembly.LoadFile(dll);
using (Stream stream = assembly.GetManifestResourceStream(resourcepath))
using (StreamReader reader = new StreamReader(stream))
{
string script = reader.ReadToEnd();
I would fix it this way (it's not the best way, but it's a way)
string sqlfilepath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, #"Migrations/Scripts/MyCustomScript.sql");
if (!File.Exists(sqlfilepath))
sqlfilepath = "your other path where it might exist";

How to save generated file temporarily in servlet based web application

I am trying to generate a XML file and save it in /WEB-INF/pages/.
Below is my code which uses a relative path:
File folder = new File("src/main/webapp/WEB-INF/pages/");
StreamResult result = new StreamResult(new File(folder, fileName));
It's working fine when running as an application on my local machine (C:\Users\userName\Desktop\Source\MyProject\src\main\webapp\WEB-INF\pages\myFile.xml).
But when deploying and running on server machine, it throws the below exception:
javax.xml.transform.TransformerException:
java.io.FileNotFoundException
C:\project\eclipse-jee-luna-R-win32-x86_64\eclipse\src\main\webapp\WEB INF\pages\myFile.xml
I tried getServletContext().getRealPath() as well, but it's returning null on my server. Can someone help?
Never use relative local disk file system paths in a Java EE web application such as new File("filename.xml"). For an in depth explanation, see also getResourceAsStream() vs FileInputStream.
Never use getRealPath() with the purpose to obtain a location to write files. For an in depth explanation, see also What does servletcontext.getRealPath("/") mean and when should I use it.
Never write files to deploy folder anyway. For an in depth explanation, see also Recommended way to save uploaded files in a servlet application.
Always write them to an external folder on a predefined absolute path.
Either hardcoded:
File folder = new File("/absolute/path/to/web/files");
File result = new File(folder, "filename.xml");
// ...
Or configured in one of many ways:
File folder = new File(System.getProperty("xml.location"));
File result = new File(folder, "filename.xml");
// ...
Or making use of container-managed temp folder:
File folder = (File) getServletContext().getAttribute(ServletContext.TEMPDIR);
File result = new File(folder, "filename.xml");
// ...
Or making use of OS-managed temp folder:
File result = File.createTempFile("filename-", ".xml");
// ...
The alternative is to use a (embedded) database or a CDN host (e.g. S3).
See also:
Recommended way to save uploaded files in a servlet application
Where to place and how to read configuration resource files in servlet based application?
Simple ways to keep data on redeployment of Java EE 7 web application
Store PDF for a limited time on app server and make it available for download
What does servletcontext.getRealPath("/") mean and when should I use it
getResourceAsStream() vs FileInputStream
just use
File relpath = new File(".\pages\");
as application cursor in default stay into web-inf folder.

File Not found in exe of wpf application

When publishing the WPF application and generate an exe, I am unable to get the files which are placed in the templates-folder. When I copy my folder and files to bin it works, or if use
string StartUpPath = AppDomain.CurrentDomain.BaseDirectory.ToString();
// var gparent = Directory.GetParent(Directory.GetParent(Directory.GetParent(StartUpPath).ToString()).ToString()).ToString();
ReportDocument reportDocument = new ReportDocument();
StreamReader reader = new StreamReader(new FileStream(StartUpPath + #"\Templates\Invoice.xaml", FileMode.Open));
This code works fine for my local, but when I generate an exe, these files are not found.
That's because your files aren't in the exe. I had the same problem recently.
It sounds like you need to handle your resources - there are several ways to go about this, and Microsoft has a full explanation here about resources, including the difference between using Linked and Embedded Resources, and links through to other great guides.
I'm assuming you're using Visual Studio, in which case this should work;
right click the file you can't access
select properties (or press ALT + ENTER)
set Build Action to be Resource
set Copy to Output Directory to be Copy if newer
save
... and you should be good to go.
I think it throws an exception because the file doesn't exist on that machine. You can set Build Action to Content and Copy to Output Directory to Copy Always or Copy If Newer on property window.
These settings will make sure that you have the file to your output.

Get Application File Path in Windows Forms Application

I have a simple windows form app that I need to get the file path for. I am placing a config file in the same directory and I need to be able to get the path to that file.
I have used
Application.CommonAppDataPath
but that returns the path with 1.0.0.0 at the end.
and
Applicaiton.StartupPath
but that returns the path with \bin\debug at the end
Is there anyway to get the path to just the main file directory without anything appended to the end?
Application.StartupPath is returning the path with \bin\debug on the end because that is where your code is running, at least on your development machine.
If you are going to deploy this away from your development machine then Application.StartupPath will give you what you're asking for - the file path for your application. And yes, if you have deployed the config file to that same location, your code is going to find it.
How to get the application also working on your development machine and get round the bin\debug issue? Well, a dirty hack would be just to chop the bin\debug string off the end of Application.StartupPath.
In that case, if you need to check for whether you're running inside the debugger, see this question
Try with
Dim aPath As String
Dim aName As String
aName = _
System.Reflection.Assembly.GetExecutingAssembly. _
GetModules()(0).FullyQualifiedName
aPath = System.IO.Path.GetDirectoryName(aName)
You can use
Application.ExecutablePath; which gives full path including executable file name
and
Application.StartupPath; for your current running application path directory without file name

Resources