Asp.net: path encoding - asp.net

I have an image gallery that I created by reading the contents inside a directory. Now right away I noticed a problem when there was a "+" in the filename. Like "glas + door.jpg" would break. So I thought it was an encoding problem and since it was only the "+" sign I thought that replacing the "+" with "%2b" would solve the problem. Locally the problem was fixed but when I uploaded it to my host I noticed replacing the "+" sign with "%2b" didn't work help anymore.
So this is where I started looking at the encoding possibilities of ASP.NET. I found Server.UrlEncode and Server.UrlPathEncode. This gave me some mixed results like images that worked before wouldn't work anymore.
So what's the correct way of encoding a path and why did the replace "trick" work on my PC but not in my hosting environment?
public List<fileInfo> RenderImages()
{
List<fileInfo> RenderImages = new List<fileInfo>();
var Images = GetImages();
if (Images != null)
{
foreach (var Image in Images)
{
string FullPath = Path + FolderName + "/" + Image.Name.Replace("+", "%2b");
string ImageName = Image.Name.Replace(Image.Extension, string.Empty);
RenderImages.Add(new fileInfo { path = FullPath, name = ImageName });
}
}
return RenderImages;
}
public class fileInfo
{
public string path { get; set; }
public string name { get; set; }
}
The GetImages() function gets jpg, gif and png FileInfos from a certain directory. If needed, I can post that part of code also.
If it helps, here you can see how the images break. This is with Replace("+", "%2b").
Thanks in advance.

The problem is that space can be escaped as + in URL:s and there is no way for a server to tell if you really mean + or space. Even when encoded as %2b it might be a double encoded space, so it will still turn out as a space when decoded.
To fix this, you can manually replace "+" with "%252b" instead, which will correctly decode as +.

It's not a real fix to my problem but I just replaced all the "+" signs with "plus". In the captation of the images I replaced it back with "+". It's just a work around because I wasn't able to solve my problem.

Related

Change image format using WebImage

I'm new to asp.net and I'm making a website with asp.net mvc 4 where user can upload any type of image(png, jpeg, gif) but system will save the image as a png format. I'm using WebImage helper. So far uploading is working fine but whenever system saves the image, filename looks like this, Filename.png.jpeg. Here is my codes from Controller,
if (file != null && file.ContentLength > 0)
{
string picName = "FileName";
WebImage img = new WebImage(file.InputStream);
if (img.Width > 265 || img.Height > 158)
{
img.Resize(265, 158);
}
string picExt = Path.GetExtension(file.FileName);
if (picExt == ".jpg")
{
picExt = ".png";
}
string path = System.IO.Path.Combine(Server.MapPath("~/Images/"), picName + picExt);
img.Save(path);
}
How can I save the image as only png format no matter what user uploads in any format of image? Need this help badly. Tnx.
I had the same problem, and I just told it to ignore correct extension forcing.
The third parameter is bool forceCorrectExtension which is true by default. You don't need the second parameter since you manually set your extension.
img.Save(path, null, false);
Just ran into the same issue. Please see here:
WebImage.Save Method
Cognis is half correct and it will probably work like that. However, the 2nd parameter actually tells it what format to save as:
imageFormat Type: System.String The format to use when the image file
is saved, such as "gif", or "png".
A jpeg doesn't become a png simply because you change the extension. Unless the Save method knows to reformat based on extension (???), I would rather error on the side of caution by doing:
img.Save(path, "png", false);

virtual path change

I want to change Virtual Path(The path is out of project means local system or Server.) of the file Which is save on the folder in asp.net.
Code is
DataTable dtFiles =
GetFilesInDirectory(HttpContext.Current.Server.MapPath(UPLOADFOLDER));
gv.DataSource = dtFiles;
gv.DataBind();
if (dtFiles != null && dtFiles.Rows.Count > 0)
{
double totalSize = Convert.ToDouble(dtFiles.Compute("SUM(Size)", ""));
if (totalSize > 0) lblTotalSize.Text = CalculateFileSize(totalSize);
}
private static string UPLOADFOLDER = "D:/Uploads";
And the error show "D:/Uploads is not a valid virtual path.".
If you want to get the files in a directory and you know the full path, then you don't need to use Server.MapPath(). Just use the path.
Incidentally, the path delimiter is incorrect in your code. The string "D:/Uploads" should be #"D:\Uploads" (note the leading # sign to denote a string that should be treated literally and not escaped).
Of course. You're telling your server to map path that is completely off the IIS. How is it supposed to do? If you're using a web application, try to avoid such ideas completely. Even though it is possible, it isn't a good idea because of security issues you can run into.

Character + is converted to %2B in HTTP Post

I'm adding functionality to a GM script we use here at work, but when trying to post (cross site may I add) to another page, my posting value of CMD is different than what it is on the page.
It's supposed to be Access+My+Account+Info but the value that is posted becomes Access%2BMy%2BAccount%2BInfo.
So I guess my question is: What's escaping my value and how do I make it not escape? And if there's no way to unescape it, does anyone have any ideas of a workaround?
Thanks!
%2B is the code for a +. You (or whatever framework you're using) should already be decoding the POST data server-side...
Just a quick remark: If you want to decode a path segment, you can use UriUtils (spring framework):
#Test
public void decodeUriPathSegment() {
String pathSegment = "some_text%2B"; // encoded path segment
String decodedText = UriUtils.decode(pathSegment, "UTF-8");
System.out.println(decodedText);
assertEquals("some_text+", decodedText);
}
Uri path segments are different from HTML escape chars (see list). Here is an example:
#Test
public void decodeHTMLEscape() {
String someString = "some_text+";
String stringJsoup = org.jsoup.parser.Parser.unescapeEntities(someString, false);
String stringApacheCommons = StringEscapeUtils.unescapeHtml4(someString);
String stringSpring = htmlUnescape(someString);
assertEquals("some_text+", stringJsoup);
assertEquals("some_text+", stringApacheCommons);
assertEquals("some_text+", stringSpring);
}
/data/v50.0/query?q=SELECT Id from Case
This worked for me. Give space instead of '+'

error in displaying data from specific XML tags in a file?

XmlTextReader reader = new XmlTextReader("D://project_elysian//data.xml");
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
reader.Read();
//Response.Write(reader.Value + "</br>");
//Response.Write(reader.Depth);
switch (reader.Name)
{
case "Id": Response.Write(reader.Value + "</br>");
break;
case "Name": Response.Write(reader.Value + "</br>");
break;
}
}
}
I am trying to read data.xml file and display its contents of the specified tags, but the resultant page remains blank, and no compilation error is given, am stuck, can't figure out what is wrong with this code.
I suspect if you "View Source" on the resulting page you'll see the data you are expecting to see.
The problem is that your web browser sees these xml elements as unknown html tags and so doesn't know how to display them.
You need to "encode" your output, so your string is literally displayed as is.
Instead of writing:
Response.Write(reader.Value + "</br>");
try
Response.Write(Server.HtmlEncode(reader.Value) + "</br>");
What this does is replace < with < > with > and a few others. "<" tells the browser to render "<" rather than treat it as the beginning of a tag.
[Edit - in response to comment]
It sounds like your none of your cases are ever true. Without knowing the contents of the source xml file, it is hard to say - but have you tried putting a breakpoint on the Response.Writes in the cases? Are they ever hit?
If not, then this is not related to anything I mentioned above - but you are not getting what you expect from your reader.
Try starting with a small sample of the xml file and step through in the debugger. Try and determine what data (e.g. the reader.Name property) is present on the reader when you hit something you are interested in, and amend the switch statement accordingly.
[2nd Edit - in response to sample xml]
Your mistake is the Read() call just after the check for the XmlNodeType.Element. You are basically reading until you find an element (the Read() call in the while). Once you've found the element, you are then pushing past the element (the other Read() call) before trying to read the element name. This inner reader.Read() makes sure you are no longer on the element by the time you try to check its name.
Try this:
while (reader.Read())
{
if (reader.NodeType == XmlNodeType.Element)
{
// Capture the element name before pushing past it.
var elementName = reader.Name;
reader.Read();
//Response.Write(reader.Value + "</br>");
//Response.Write(reader.Depth);
switch (elementName)
{
case "Id":
Response.Write(reader.Value);
break;
case "Name":
Response.Write(reader.Value);
break;
}
}
}
The key to finding this sort of thing, is to debug carefully. Start with a cut down xml file and either actually step through in the debugger, or write debug output to a log or the response. It'll make identifying these sort of issues much easier.
Since it is working outside switch, I guess than name of the node is of different case.Check the case of the nodes
Edit:
You are calling reader.read() twice and the reader.value will not return proper value for an element.
If you still want to use xmlreader check the below code
XmlTextReader reader = new XmlTextReader(<XML Path>)
while (reader.Read())
{ if (reader.NodeType == XmlNodeType.Element)
{
switch (reader.Name)
{
case "Id": Response.Write(Server.HtmlEncode(reader.ReadString()) + "</br>");
break;
case "Name": Response.Write(Server.HtmlEncode(reader.ReadString()) + "</br>");
break;
}
}
}
reader.Close();
I would suggest that you take a look at XML (de)serialization instead of using XmlReader. .Net will verify the xml and you will more easily be able to debug the Xml input.
You simply create a class with fields mirroring your Xml structure and use the following code:
class searchResult
{
public List<item> itemList { get; set;}
}
A complex field class example
class item
{
public int Id { get; set; }
public string Name{ get; set; }
}
The actual work gets done like so:
XmlSerializer SerializerIn = new XmlSerializer(typeof(SerializeTest));
FileStream fs = new FileStream(#"C:\test.xml", FileMode.Open, FileAccess.Read, FileShare.Read);
SerializeTest loadTest = (SerializeTest)SerializerIn.Deserialize(fs);
fs.Close();
Where SerializeTest is the class your loading the xml into. It is much easier to work this way, because you never need to deal with the raw Xml unless it is invalid.
You can find more info here: http://www.codeproject.com/Articles/4491/Load-and-save-objects-to-XML-using-serialization
Probably a better tutorial: https://web.archive.org/web/20211020113423/https://www.4guysfromrolla.com/webtech/012302-1.shtml

How do I convert a file path to a URL in ASP.NET

Basically I have some code to check a specific directory to see if an image is there and if so I want to assign a URL to the image to an ImageControl.
if (System.IO.Directory.Exists(photosLocation))
{
string[] files = System.IO.Directory.GetFiles(photosLocation, "*.jpg");
if (files.Length > 0)
{
// TODO: return the url of the first file found;
}
}
this is what i use:
private string MapURL(string path)
{
string appPath = Server.MapPath("/").ToLower();
return string.Format("/{0}", path.ToLower().Replace(appPath, "").Replace(#"\", "/"));
}
As far as I know, there's no method to do what you want; at least not directly. I'd store the photosLocation as a path relative to the application; for example: "~/Images/". This way, you could use MapPath to get the physical location, and ResolveUrl to get the URL (with a bit of help from System.IO.Path):
string photosLocationPath = HttpContext.Current.Server.MapPath(photosLocation);
if (Directory.Exists(photosLocationPath))
{
string[] files = Directory.GetFiles(photosLocationPath, "*.jpg");
if (files.Length > 0)
{
string filenameRelative = photosLocation + Path.GetFilename(files[0])
return Page.ResolveUrl(filenameRelative);
}
}
The problem with all these answers is that they do not take virtual directories into account.
Consider:
Site named "tempuri.com/" rooted at c:\domains\site
virtual directory "~/files" at c:\data\files
virtual directory "~/files/vip" at c:\data\VIPcust\files
So:
Server.MapPath("~/files/vip/readme.txt")
= "c:\data\VIPcust\files\readme.txt"
But there is no way to do this:
MagicResolve("c:\data\VIPcust\files\readme.txt")
= "http://tempuri.com/files/vip/readme.txt"
because there is no way to get a complete list of virtual directories.
I've accepted Fredriks answer as it appears to solve the problem with the least amount of effort however the Request object doesn't appear to conatin the ResolveUrl method.
This can be accessed through the Page object or an Image control object:
myImage.ImageUrl = Page.ResolveUrl(photoURL);
myImage.ImageUrl = myImage.ResolveUrl(photoURL);
An alternative, if you are using a static class as I am, is to use the VirtualPathUtility:
myImage.ImageUrl = VirtualPathUtility.ToAbsolute(photoURL);
This worked for me:
HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority) + HttpRuntime.AppDomainAppVirtualPath + "ImageName";
Maybe this is not the best way, but it works.
// Here is your path
String p = photosLocation + "whatever.jpg";
// Here is the page address
String pa = Page.Request.Url.AbsoluteUri;
// Take the page name
String pn = Page.Request.Url.LocalPath;
// Here is the server address
String sa = pa.Replace(pn, "");
// Take the physical location of the page
String pl = Page.Request.PhysicalPath;
// Replace the backslash with slash in your path
pl = pl.Replace("\\", "/");
p = p.Replace("\\", "/");
// Root path
String rp = pl.Replace(pn, "");
// Take out same path
String final = p.Replace(rp, "");
// So your picture's address is
String path = sa + final;
Edit: Ok, somebody marked as not helpful. Some explanation: take the physical path of the current page, split it into two parts: server and directory (like c:\inetpub\whatever.com\whatever) and page name (like /Whatever.aspx). The image's physical path should contain the server's path, so "substract" them, leaving only the image's path relative to the server's (like: \design\picture.jpg). Replace the backslashes with slashes and append it to the server's url.
So far as I know there's no single function which does this (maybe you were looking for the inverse of MapPath?). I'd love to know if such a function exists. Until then, I would just take the filename(s) returned by GetFiles, remove the path, and prepend the URL root. This can be done generically.
The simple solution seems to be to have a temporary location within the website that you can access easily with URL and then you can move files to the physical location when you need to save them.
For get the left part of the URL:
?HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Authority)
"http://localhost:1714"
For get the application (web) name:
?HttpRuntime.AppDomainAppVirtualPath
"/"
With this, you are available to add your relative path after that obtaining the complete URL.
I think this should work. It might be off on the slashes. Not sure if they are needed or not.
string url = Request.ApplicationPath + "/" + photosLocation + "/" + files[0];

Resources