Access static files on server from RCL - asp.net

I've read dozens of questions but none seem to work for me. I'm not using IIS. I'm using ASP.Net Core 3.1 with Kestrel.
I have a Razor Class Library with a resources folder, in that I have folders like css, js, content, etc. I use this library so all of my common Web Api projects can share common files instead of duplicating them everywhere. To do this, I followed the guide from here. Please see there for how Startup is configured.
That works great, I can access those files by going to e.g. localhost/css/site.css. In my cshtml files, I can include that file by doing <link rel="stylesheet" href="~/css/site.css"/>
The problem arises when I try to access those files from a controller. I have a sister folder to css called content which contains json files. I can view that file by going to localhost/content/test.json, but I can't figure out how to access it from a controller.
What I'd like to do is make an HTTP request to ~/content/test.json and download its contents, but the path is not found.
I've tried using Url.Content to map a relative path to the absolute path, but it doesn't work.
var url = Url.Content("~/content/test.json"); // spits out "/content/test.json"
I've DI'd IWebHostEnvironment into the controller and tried to access the ContentRootFileProvider and the ContentRootPath and WebRootPath, but those paths aren't right either. They are pointing to my currently running service's wwwroot's parent and wwwroot, respectively.
I've tried creating my own file provider:
var filesProvider = new ManifestEmbeddedFileProvider(GetType().Assembly, "resources");
var content = filesProvider.GetDirectoryContents("content");
var fileInfo = filesProvider.GetFileInfo(Path.Combine("content", "test.json"));
This successfully finds the file and claims it exists, but the fileInfo's PhysicalPath is always null.
I just want to do something like this:
string SomeMagicMapFunction(string s) => ????
var webClient = new WebClient();
var json = webClient.DownloadString(SomeMagicMapFunction("~/content/test.json"));
Where am I going wrong? Any pointers are appreciated.

Related

Can I serve static content with spring-boot-starter-tomcat but without spring-boot-starter-web?

I'm working on a web service using spring-boot-starter-jersey and spring-boot-starter-tomcat (v. 1.5.2) and as such, I'd rather not add spring-boot-starter-web and further complicate my configuration. I want to stick the Swagger UI static files in a folder and serve them from there.
What I'm wondering is, can I serve static files using just spring-boot-starter-tomcat? I've found Spring documentation saying that I can server static content from a variety of sources on the classpath, but the examples I've found seem to require Spring MVC. I've tried disabling Jersey and putting static files in src/main/resources/static to test just Tomcat, but when I go to localhost/index.html, I get a 404 not found error.
As you might be able to tell from my path, I'm using Maven.
Since you can serve static files with just Tomcat, it seems like I should be able to serve static files with spring-boot-starter-tomcat. If this is the case, where do I put those files?
To put this another way, say I have started with the Spring-provided
spring-boot-sample-jersey project. I have a requirement that the Jersey web service answer calls to the root address (/). How would I add some static content (HTML, CSS, JS) to be served from subdirectory called /swagger?
So the default servlet (which serves static content) is by default registered. But it will use only search specific paths as the document root. I had to go digging through source code to finally find it. If you look in the AbstractEmbeddedServletContainerFactory, you'll see
private static final String[] COMMON_DOC_ROOTS = {
"src/main/webapp", "public", "static" };
If we don't explicitly set the document root, the above three are the paths that will be searched. In order, the first directory found that exists, will be used as the document root. I've verified that all of these work.
If you want to set a different directory, you can use a customizer bean
#Bean
public EmbeddedServletContainerCustomizer tomcatCustomizer() {
return new EmbeddedServletContainerCustomizer() {
#Override
public void customize(ConfigurableEmbeddedServletContainer container) {
container.setDocumentRoot(new File("src/main/resources/static"));
}
};
}
The one thing I haven't figured out is if we can serve files as classpath resources, instead of file system resources. If you look at the source code I linked to, it has some code that looks for the existence of a META-INF/resources. I thought that might work, but unfortunately it didn't for me. Maybe some guys of the Spring Boot team can enlighten us.

What's the recommended way to load an internal file on the web site?

We've got a certain image in the \Images folder of our web site. We need to include that image in an OpenXml file we're generating internally, and for that we're using the following snippet:
var logo = Server.MapPath(#"~\Images\logo-new.png");
var imagePart = mainPart.AddImagePart(ImagePartType.Png); // mainPart is of type MainDocumentPart
using (var stream = new FileStream(logo, FileMode.Open))
{
imagePart.FeedData(stream);
}
Then later imagePart is used for embedding in the document.
This code works fine in development, but in deployment we're getting a System.UnauthorizedAccessException when we try to open the file for streaming.
Clearly there is an access permission problem, since Server.MapPath() is converting the web path to an absolute path on the server drive, and the IIS user doesn't have rights to that. We might be able to get around it by granting access to everyone, but something tells me that this is not the textbook way of doing it. Surely there must be a way of accessing this file that doesn't require us to start futzing with access permissions to the web deployment folder?
Solved, by including the file as a resource rather than by trying to access it through the file system:
var logo = Resources.logo_new;
var imagePart = mainPart.AddImagePart(ImagePartType.Png);
using (var stream = logo.ToStream(ImageFormat.Png))
{
imagePart.FeedData(stream);
}
Hat tip to this answer for the .ToStream() extension.

Java EE - Best way to get real path to uploaded files? [duplicate]

This question already has answers here:
Recommended way to save uploaded files in a servlet application
(2 answers)
Closed 6 years ago.
I have a web application with an upload form where users can upload files.
I'd like to store the files a folder 'files'. And i'd like this folder to be placed directly under the webapp-root.
Using struts2, in my uploadFileAction, i can easily set this path with String uploadDir = ServletActionContext.getServletContext().getRealPath("/files")+ "/";
But when i'm trying to retrieve the files, apparently my bean which tries to access the file does not have access to getServletContext() and thus throws a nullpointer on getRealPath
Now im trying to figure out how i should approach this. I've heard about spring resource is the way to go, but i cant find any relevant examples.
Is there an easy way to get my paths? I just want the rootpath to my webapp. Nothing more nothing less...
I'd like this folder to be placed directly under the webapp-root.
This isn't going to work. All those files will get lost whenever you redeploy the webapp or even when you restart the server. Those files are namely not contained as part of the original WAR.
You need to store them in a fixed path outside the webapp's context. E.g. /var/webapp/uploads. You can configure this path in a properties file or as a system property.
I've found that a few ways to accomplish this regardless of what OS platform you're using. I typically like to store my files in some way relative to my web application. This being said, the easiest way to do this is using your class file as a reference to get the real path. I use something similar to the following to store image uploads for a few web applications that I've built:
public class FileLocationTest {
public static void main(String[] args) {
String path = FileLocationTest.class.getProtectionDomain().getCodeSource().getLocation().getPath();
System.out.println(path);
}
}
This can be done using a static utility class in your web app, or any class for that matter to obtain the real path of your application regardless of OS. Alternatively in a servlet I've also used the request class to get the Tomcat location if my appbase is in a different area, something like this:
String location = request.getClass().getProtectionDomain().getClassLoader().getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
String path = location.substring(0, location.indexOf("/tomcat")) + "/data/events/images/";

Flash XML config file problems with asp.net MVC

I'm creating an asp.net MVC app, first time I've done this. I have a flash component I need to use in a view. I have included the SWF files etc in the Contents folder and referenced it from my view, the flash file loads when you get to the view, great.
The problem occurs because the flash file references and XML file for its configuration data, and I'm getting an error accessing that XML file. I'm guessing this is because flash is looking for a relative path and is using the URL for the page, which is obviously an MVC url and so does not refer to an actual location on disk, so the XML file is not there.
I guess the obvious answer is the alter the flash file to look in the contents folder for the XML file, but that means re-compiling the flash, and I know very little about flash so I'd like to avoid doing that. So is there any way to get the XML file to show up in the same URL as the view, so at the moment, the page with the flash component on is located at htttp://localhost/upload/ so I guess the XML file needs to be accessible from http://localhost/upload/flash-settings.xml?
If there's any other better way to do this, without editing the flash file, im open to that too,
Add this Action to the FlashUpload Controller:
public class FlashUploadController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult FlashSettings()
{
var fileName = Server.MapPath("~/Contents/flash-settings.xml");
return new FilePathResult(fileName, "text/xml");
}
}
And this route to the RouteTable:
routes.MapRoute("FlashSettings", "upload/flash-settings.xml",
new { Controller = "FlashUpload", Action = "FlashSettings" });
You'll need to either set the routing mechanism to allow for direct files access to the /upload/ folder, or create a Controller Action which will return an XML stream (dynamic or the one read from the physical XML file), and point your SWF to that Route. I'd go with the second option, as it is much flexible.

How to load WSDL from file

I am trying to save some bandwidth and include wsdl file in my flex/air application. Which url format should I use in order to load that file instead of the remote one.
I am using loadWSDL() method.
EDIT:
wsdl file needs to be part of the application. I know I can use file://some/path for local files, but don't know how to load file which is inside application itself.
If the file is local, just use the file URI scheme:
file://host/path/file.wsdl
If this doesn't work, check if the security sandbox features are blocking it.
In AIR apps, in order to access files in the application's temporary storage directory or the application's own directory, you need to use special app: or app-storage: URL schemes, though.
Like dirkgently said, you can always embed the file into the application, but as far as I know, you then won't be able to modify it afterwards in a persistent manner since it's not just a file in the filesystem. Probably the best option for you is to embed this file and if you later need to update it, have the app save an updated version into the File.applicationStorageDirectory (which you would then always check first before using the default embedded version.) Although I have no idea if using embedded XML files with the WebService classes is even possible.
See this article for info on how to embed external XML files into your app. This is how I've done it:
// note: common sense says that the mimeType should be "text/xml" here but
// it doesn't work -- this does, though. who knows why.
[Embed(source="File.xml", mimeType="application/octet-stream")]
private const _fileXMLClass:Class;
private var _fileXML:XML = XML(new _fileXMLClass());
wsdl file needs to be part of the application.
Have you tried embedding it inside the Flex/AIR project as a resource? Read this. For example, you can load static images shipped with your app by specifying the source as:
source="#Embed(source='relativeOrAbsolutePath')"
Uf, this was ugly, so I'm answering for the reference. Thanks for insights to hasseg and dirkgently
Here is the code.
First, declare the variables:
[Embed(source="/ws/wsdl/LoginService.wsdl",
mimeType="application/octet-stream")]
private const _fileXMLClass:Class;
private var _fileXML:XML = XML(new _fileXMLClass());
Then, loading wsdl:
var file : File = dir.resolvePath(name + ".xml");
var stream : FileStream = new FileStream();
stream.open(file, FileMode.WRITE);
stream.writeUTFBytes(getWsdl().toXMLString());
stream.close();
loadWSDL(file.url);
If someone have an idea to make this less ugly, please let me know.
EDIT: I just noticed edited answer, so instead of this code it was enough to use just:
loadWSDL('app:///path/to/my/file.wsdl');
I use below code in flash builder air mobile app and it works, may help some else. I get file contents from a web service using url loader and wirte it down to a xml file in document directory of my air app.
var url:URLRequest = new URLRequest(Globals.deviceSettings.endpoint);
loader.load(url);
loader.addEventListener(Event.COMPLETE, loaderComplete);
get the status of web service, if it is 200 then available and heads up.
loader.addEventListener(HTTPStatusEvent.HTTP_STATUS, ldrStatus);
and in the eventlistener
function loaderComplete(e:Event):void
{
var f:File= File.documentsDirectory.resolvePath("source/category.xml");
var _xml:XML = new XML(loader.data);
var fs:FileStream = new FileStream();
fs.open(f, FileMode.WRITE);
fs.writeUTFBytes(_xml.toXMLString());
fs.close();
popup.close(true);
var popup:MyPopupComponent = new MyPopupComponent();
popup.show("Successfully updated from the server",this);
popup.close();
}
you can use file.documentdirectory or applicaiton or your choice directory as per your need please keep in mind that some of the paths are read only for security. if you want to write back to those files you wont be able but just for reading purposes it is a good idea to place the files there.

Resources