All.
(Using CodeFile for pages published to a webserver
Removing Namespace, as I get errors after adding CodeFile)
I created a video for everyone to see the issue live. This is creating a new web project and then demonstrating the issue.
Please click here to view the video.
I've run into a strange issue that I'm hoping someone will be able to assist with.
Below are identical codes, with only the CodeBehind and CodeFile, and the namespace removal changed.
The issue is this.
The below code will upload a single image that is renamed with the date.
<%# Page Language="vb" AutoEventWireup="false" CodeBehind="Test.aspx.vb" Inherits="ImageServer.Test" %>
This code will upload duplicates of the image renamed with a date.
<%# Page Language="vb" AutoEventWireup="false" CodeFile="Test.aspx.vb" Inherits="Test" %>
If you upload the file with its default name, it will only upload ONE file, regardless of the Inherits property.
So, this will upload single files either way.
Dim fileName As String = IO.Path.GetFileName(postedFile.FileName)
postedFile.SaveAs(Server.MapPath("~/Uploads/") & fileName)
This code will upload duplicates with CodeFile and no Namespace.
Dim getYear As String = (((((now.ToString("hh") & "") + now.ToString("mm") & "") + now.ToString("ss") & "") + now.ToString("mm") & "") + now.ToString("dd") & "") + now.ToString("yyyy") + now.ToString("fff") + ""
Dim testName As String = getYear + ext
postedFile.SaveAs(Server.MapPath("~/Uploads/") & testName)
Any idea what is going on here?
Text.aspx (Uncomment each Page header to test out code)
<%'# Page Language="vb" AutoEventWireup="false" CodeBehind="Test.aspx.vb" Inherits="ImageServer.Test" %> <!--Singles-->
<%# Page Language="vb" AutoEventWireup="false" CodeFile="Test.aspx.vb" Inherits="Test"%> <!--Duplicates-->
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script language="javascript" type="text/javascript">
$(function () {
$("[id*=fuUpload]").change(function () {
if (typeof (FileReader) !="undefined") {
var dvPreview = $("#dvPreview");
dvPreview.html("");
var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.jpg|.jpeg|.gif|.png|.bmp)$/;
$($(this)[0].files).each(function () {
var file = $(this);
if (regex.test(file[0].name.toLowerCase())) {
var reader =new FileReader();
reader.onload = function (e) {
var img = $("<img />");
img.attr("style","height:100px;width: 100px");
img.attr("src", e.target.result);
dvPreview.append(img);
}
reader.readAsDataURL(file[0]);
}else {
alert(file[0].name +" is not a valid image file.");
dvPreview.html("");
return false;
}
});
}else {
alert("This browser does not support HTML5 FileReader.");
}
});
});
</script>
</head>
<body>
<form runat="server">
<asp:FileUpload ID="fuUpload" runat="server" multiple="multiple" />
<asp:Button ID="btnUpload" Text="Upload" runat="server" OnClick="Upload" />
<hr />
<div id="dvPreview">
</div>
</form>
</body>
</html>
Text.aspx.vb
Place the following code under your upload button.
For i As Integer = 0 To Request.Files.Count - 1
Dim postedFile As HttpPostedFile = Request.Files(i)
Dim ext As String = System.IO.Path.GetExtension(postedFile.FileName)
Dim now As DateTime = DateTime.Now
Dim getYear As String = (((((now.ToString("hh") & "") + now.ToString("mm") & "") + now.ToString("ss") & "") + now.ToString("mm") & "") + now.ToString("dd") & "") + now.ToString("yyyy") + now.ToString("fff") + ""
Dim testName As String = getYear + ext
If postedFile.ContentLength > 0 Then
Dim fileName As String = IO.Path.GetFileName(postedFile.FileName)
postedFile.SaveAs(Server.MapPath("~/Uploads/") & fileName) ' Single file either way
'postedFile.SaveAs(Server.MapPath("~/Uploads/") & testName) ' Duplicate file CodeFile and no Namespace
End If
Next
==Update==
OK, so it was the
Dim getYear As String
The last part of it was causing the issue.
now.ToString("fff")
Also happens with a GUID as well.
Guid.NewGuid().ToString()
I even tried a random file name for kicks, and it duplicated the files.
Path.GetRandomFileName()
Though it had nothing to do with the CodeFile, there is still the scratching of the head part of WHY does it duplicate the files with the milliseconds added to it?
If you use the example code I provided and test it, you will see that the Random getYear will work with CodeBehind but not with CodeFile.
So, something is going on with CodeFile that causes this bizarre behavior.
Thanks for any assistance on this issue.
Wayne
First of all, I VERY but VERY much doubt changing the use of codepage, and code file will effect the outcome here.
the issue is really quite simple:
You allow a user to up-load mutliple files. But, your 2nd code snip does NOT use the file name, and in fact uses a file name based on the time stamp.
You do realize that if user selects 5 files, then in 99% of cases, the file name (based just on time) will OFTEN and NEAR ALWAYS result in say all 5 files being given the same name.
Remember, when a user selects say 5 files, and then hits submit. The files are not really up-loaded separate, but ALL WILL be part of the submit button (the post-back).
So, AFTER ALL the files are up-loaded, then your code loop runs. and it is in most cases going to run VERY fast - less then 1 second. As a result, all 5 files will be given the same file name.
It is possible that you using a computer found in a dumpster, and it runs slow, so slow that somehow the time to run that loop to save (write) each file takes more then one second.
And remember, you as a general rule would not mess with using codefile vs codebehind.
But, without question, using codebehind probably will at least the first time run MUCH faster. If you use codefile, then the source code is saved and is part of the web page, and is compiled by IIS (internet server).
However, if you use cdebehind, then the code is pre-compiled. This thus suggests perhaps that on first page load when using codefile, the code runs VERY slow the first time - it has to be compiled on the fly, and this might buy you some extra time, enough that the additional file names increased by one second.
However, with codebehind, then this is NOT likly to occur (in other words, the code will run faster, and ALMOST FOR SURE, that if you up-loaded 5 files, they ALL WILL get the same name if you base the file name on JUST time, and don't for example add say the file name or some other part to distinguish the file names your code generates.
Obviously, your first code snip always works, since you using the file name from the up-load.
The 2nd example? If the computer runs fast, then you almost for sure wind up over writing the set of files with the same time - since that code will run rather fast.
And you should not mess with the codebehind vs codefile settings.
codebehind:
This assumes you are using an asp.net web application. This means that you compile the web site and code BEFORE deployment, and your source code files (code behind) are NOT up-loaded to the server.
CodeFile
This assumes you are NOT using a sp.net application, but are using what is called a asp.net web site. This means that you can deploy one simple page, and not have to re-deploy the whole site (like you do with web applications). This certainly can be easier to maintain a web site, but a web site application also has some advantages, and this is in the area of refencing other code libraries etc. You also tend to require MORE control over the web server, and a web site can easy be published as as sub site, where as in most cases the asp.net web applcation is going to be the root of your site, and the configuration applies to the whole server - not several sub sites.
Anyway, wondering off topic here.
It looks like using the time stamp for the file name is a bad idea, and that loop will surely OFTEN run in less then one second, and that will result in all files having the same file name. You either need to introduce the part of the file name, or even consider a file.Exists(strFile), and maybe then increment the time by 5 seconds or some such if the file already exists (for the file name to be used).
As noted, if you are using codefile, and it seemed to work, it likly due to the code running oh so much slower. However, if you run that page, or do the test multiple times, that page will when loaded, and compiled by IIS will start to run faster, and you then start to see the same file names generated based on using time.
For code behind, then it is pre-compiled, and thus the chance of the time changing from one file save to the next will increase, and once again, file based on time stamp will no doubt start to over write each other in that loop.
Edit: two examples web site, and web site application
Ok, so lets create two projects. We use the time stamp example in both.
so, lets create a web site (not a web site application).
So, this one:
so, to be 100% clear, we do NOT open this as a project.
Thus we ALWAYS will open this project with open web site option from VS.
so, to open + develop, we use open web site, and NOT open application.
Eg this:
And then this to open:
And of course, it ALWAYS dangerous to mess around with the code file and page settings (that first header in the markup).
So, we add a new page - MyTest (and we MOST certainly let VS create this page for us, right????).
So, we now cut + paste in your markup:
And we now have this:
<%# Page Language="VB" AutoEventWireup="false" CodeFile="MyTest.aspx.vb" Inherits="MyTest" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script language="javascript" type="text/javascript">
$(function () {
$("[id*=fuUpload]").change(function () {
if (typeof (FileReader) !="undefined") {
var dvPreview = $("#dvPreview");
dvPreview.html("");
var regex = /^([a-zA-Z0-9\s_\\.\-:])+(.jpg|.jpeg|.gif|.png|.bmp)$/;
$($(this)[0].files).each(function () {
var file = $(this);
if (regex.test(file[0].name.toLowerCase())) {
var reader =new FileReader();
reader.onload = function (e) {
var img = $("<img />");
img.attr("style","height:100px;width: 100px");
img.attr("src", e.target.result);
dvPreview.append(img);
}
reader.readAsDataURL(file[0]);
}else {
alert(file[0].name +" is not a valid image file.");
dvPreview.html("");
return false;
}
});
}else {
alert("This browser does not support HTML5 FileReader.");
}
});
});
</script>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:FileUpload ID="fuUpload" runat="server" multiple="multiple" />
<asp:Button ID="btnUpload" Text="Upload" runat="server" OnClick="Upload" />
<hr />
<div id="dvPreview">
</div>
</div>
</form>
</body>
</html>
So, I did not mess with the page directive, I pasted in your bits in parts.
And for code behind, we have this:
Partial Class MyTest
Inherits System.Web.UI.Page
Protected Sub Upload(sender As Object, e As EventArgs)
For i As Integer = 0 To Request.Files.Count - 1
Dim postedFile As HttpPostedFile = Request.Files(i)
Dim ext As String = System.IO.Path.GetExtension(postedFile.FileName)
Dim now As DateTime = DateTime.Now
Dim getYear As String = (((((now.ToString("hh") & "") + now.ToString("mm") & "") + now.ToString("ss") & "") + now.ToString("mm") & "") + now.ToString("dd") & "") + now.ToString("yyyy") + now.ToString("fff") + ""
Dim testName As String = getYear + ext
If postedFile.ContentLength > 0 Then
Dim fileName As String = IO.Path.GetFileName(postedFile.FileName)
'postedFile.SaveAs(Server.MapPath("~/Uploads/") & fileName) ' Single file either way
postedFile.SaveAs(Server.MapPath("~/Uploads/") & testName) ' Duplicate file CodeFile and no Namespace
End If
Next
End Sub
End Class
I added a folder to the project Uploads.
I only get one file. That web site saved as a zip file is here:
Now, if you want to mess around, and try changing CodeFile settings, then be my guest - but I would NOT risk doing as such, since a web site assumes that IIS will compile that code.
Ok, now lets do this with a asp.net web site project. This one:
And again, now we do NOT use open web site, but will use open project when you want to work on this application.
so, link to first example - zipped web site (not app), open as web site.
https://1drv.ms/u/s!Avrwal_LV4qxhpxvZPRHjzs6JES-LQ?e=HQvgp9
And link to 2nd example - zipped web site applcation. Open the project file.
(so you open with open project - choose the sln file).
https://1drv.ms/u/s!Avrwal_LV4qxhpxuJis0Pwwf4jwxxg?e=WUnx8m
Both of these work with the time stamp file example. Neither triggers two files.
Now, at this point, you are free as a bird to start mucking around with the page heading directive - but I been do this for LONG time, and have NEVER messed with that page directive header. I might have touch one when importing a web page from another project.
HOWEVER, you want to let asp.net and the designers create the page heading directive. And I VERY much doubt you can mess with a flip between CodeFile, and codebehind, since that setting is used for TWO VERY different types of projects and a different deployment model.
Edit4: the problem
Remember, I suggested this:
Try changing name of click event. Say test_click. Better yet, remove existing name and use ctrl- space to pop the choice to create new event. It will become ctrl name+ _click, and see if that prevents the double run the code. (Thus move code to new event name)stub
Note carefully in above - I said MOVE the code to a new event stub behind.
When you place a button on a form, you HAVE TWO choices here. You can EITHER double click on the button - and then code behind wires up a Handles event.
OR YOU CAN put the event name in the markup, and YOU WILL NOT be using, nor get a handles event.
In above suggestion, I stated to remove the default click you have, erase it, and then hit ctrl-space. You get this:
So, that will create a NEW event stub in code behind. And NOTE very, but very carefully I stated this:
Thus move code to new event name)stub
In other words, we remove the other stub.
So, the reason (of couse!!!) is that a static file name works, is that the code WAS running two times, but since the name is the same, you get one file - the same file.
If you use milliseconds, and HAVE TWO events wired up to the one button, then the code stub fires two times. (and you get two files as a result)
And HOW MANY times did I ask this:
quote:
when you say you get two files, is your sub being called two times? Or does the for/next loop run two times? Which is it?
and this:
quote:
but then you not answered the question. Does the code run two times? that code can't create two files unless it runs two time, or is called two times. If you put in a break-point, and debug the code when it runs, what happens? single step that code, and determine if the routine is called two times, or the loop runs two times
and this:
quote:
You did not try my break-point suggestion - you need to do that.
So, when I asked above multiple times - I assume you tested, checked, and REMOVED that from our list of things to check. Skipping a suggestion to test/check try during a trouble shooting session is a VERY bad thing to do. I take that out and off the list once I add that question + suggestion. I have to assume you double checked, and double tested that solution.
So, you did not follow up on my things to try - ignored them.
So, the issue was and is simple. There was two events attached to the button click, the code stub runs two times. And with milisecond file name, then you get two files. With a single file name, it ALSO was running two times, but you saving the file two times.
So, this issue I brough up was ignored.
So, either use the screen cap ctrl-space to create the event stub in markup, OR double click on the button and let the code behind have a handler. (but, you had both active at the same time). (aand of couse then remove the onclick in the markup - you can't have both active).
So, remove the onclick in markup (and remove the code beind stub). Now try the double click to crate the event.
You can add the event EITHER way as per above, but you can't have a handles event (in code behind) AND ALSO a onclick in the markup.
So, do one, or the rother - but not both. So you can have or add onclick in the markup (use ctrl-space) -- create new event, and REMOVE the (or any) old event with the "handles" directive.
Good luck!
I have the following code:
<%#Language="VBSCRIPT"%>
<html>
<head>
<title>in/Test Page 2</title>
</head>
<body>
<%
response.write "Request.QueryString = """ & Request.QueryString & """<br />"
for each item in request.QueryString
response.write (item + " = " + Request.QueryString(item) + "<br>")
next
%>
</body>
</html>
When I call it with this url:
TestPage2.asp?id=1&turl=http://www.google.com?id=1&url=generic#index
Which produces this output
Request.QueryString = "id=1&turl=http://www.google.com?id=1&url=generic"
id = 1
turl = http://www.google.com?id=1url=generic
How do I get the bit after the # char in the original url? I've looked all through the Request.Servervariable's.
Short answer: You can't
It's by design.
From RFC 2396: Uniform Resource Identifiers (URI): Generic Syntax - Section 4.1 Fragment Identifier
When a URI reference is used to perform a retrieval action on the identified resource, the optional fragment identifier, separated from the URI by a crosshatch (“#”) character, consists of additional reference information to be interpreted by the user agent after the retrieval action has been successfully completed. As such, it is not part of a URI, but is often used in conjunction with a URI.
Basically the # is never sent to the server so you can't retrieve it from Classic ASP. The client (Internet Browser) removes the # fragment from the URI before it is sent.
Having said that it is possible to retrieve it from the client-side using JavaScript then pass the value via a form / querystring to the server where Classic ASP can retrieve and use it.
I have a classic ASP page, and I need to create a loop for each row on a table and then create an html document and save it to the hard drive, but I want to create a template so I just send the two variables to the template so I don't have to write the HTML document each time on the loop.
This is what I have so far:
SQL = "select Title, Article from [ASPTest].[dbo].[articles]"
set rs = conn.execute(SQL)
arrRecs = rs.GetRows
For row = 0 To UBound(arrRecs, 2) 'Rows
For col = 0 To UBound(arrRecs, 1) 'Columns
Response.Write rs.Fields(col).Name & " = " & arrRecs(col, row) & " "
dim fs,f
set fs=Server.CreateObject("Scripting.FileSystemObject")
set f=fs.CreateTextFile("C:\Users\User\Documents\ASP Pages\"+arrRecs(col, row)+".html",true)
f.write("<html><body><div>It kinda works</div></body></html>")
f.close
set f=nothing
set fs=nothing
Next
Response.Write "<br />"
Next
Is there a way to use a template that has 2 variable holders and send the article name and title to the template and then save it to the disk?
Thank you.
I think you could probably achieve what you want using a template stored as a text file, and the Replace function.
Your template should be a fully-formed html page, but with placeholder values for the title and article. The placeholders need to be unique, so something like [[[~~~Title~~~]]] or a similar sequence that will not occur in your actual titles, articles, or the template itself.
<html>
<head><title>[[[~~~Title~~~]]]</title></head>
<body>
<h1>[[[~~~Title~~~]]]</h1>
<div id="article">[[[~~~Article~~~]]]</div>
</body>
</html>
In your code, read the template from the file and store it in a variable. (So technically, you could just write it to a variable in the first place, but VBScript is bad at string concatenation... anyway.) Get your array of titles & articles and loop through it (though only once: I'm not sure why you're looping through both rows and columns in your attempt). For each row, make a copy of the template, replace the title placeholder with the current row's title, replace the article placeholder with the current row's article, and write the result to a file.
Dim template, t
Dim fso, file
Dim rs, conn, SQL
Dim records, row
SQL = "SELECT ID, Title, Article FROM [ASPTest].[dbo].[articles]"
'[...database stuff...]
records = rs.GetRows
'[...close database...]
Set fso = Server.CreateObject("Scripting.FileSystemObject")
Set file = fso.OpenTextFile("path/to/template.txt",1) '- 1 = For reading
template = file.ReadAll
file.Close
Set file = Nothing
For row = 0 to UBound(records,2)
t = template
t = Replace(t,"[[[~~~Title~~~]]]",records(1,row))
t = Replace(t,"[[[~~~Article~~~]]]",records(2,row))
Set file = fso.CreateTextFile("path/to/html/" & records(0,row) & ".html")
file.Write(t)
file.Close
Set file = Nothing
Next
Set fso = Nothing
Back in the day I created the KudzuASP template engine to solve this rather complex deficiency in Classic ASP. In KudzuASP you can have ASP code pages that have absolutely NO HTML in them.
KudzuASP is as small include file roughly under 1000 lines of code that turns your hosting ASP page into an event driven object used by the template engine.
In short you create an instance of the template engine, set some variables, install custom code objects, and invoke it after which the template engine reads your template and make callbacks to your ASP page when and where appropriate. It has a library system so you can load libraries of custom tags handlers/components via code or by tags placed in your HTML template.
One of the best features is that for those still under the Classic ASP umbrella it makes 100% separation of application code and logic from presentation possible. Coding Classic ASP pages using KudzuASP is much easier than without and because of the way ASP compiles pages the callbacks are "native" and very fast.
You can find it here KudzuASP where the project is still maintained.
I'll try to keep this basic. I'm trying to run a shell on the server side (not the client). I've broken down my code so it's pretty basic. right now if I run this on the client side using CreateObject("Wscript.shell") it will 'document.write' the user in my browser.
<script type="text/vbscript" >
Set Shell = CreateObject("WScript.Shell")
Set whoami = shell.exec("whoami")
Set whoamiOutput = whoami.StdOut
strWhoamiOutput = whoamiOutput.ReadAll
document.write strWhoamiOutput
</script>
Now if I change my code to run on the server side:
<script type="text/vbscript" >
Set Shell = Server.CreateObject("WScript.Shell")
Set whoami = shell.exec("whoami")
Set whoamiOutput = whoami.StdOut
strWhoamiOutput = whoamiOutput.ReadAll
document.write strWhoamiOutput
</script>
I get an error in my browser telling me 'object required: server' at line 11. Line 11 is the 'Server.CreateObject' line. What am I missing here?
Thanks
From your 'document.write' and 'script' lines it would appear that you are trying to run this code in the browser... if so, you won't be able to do what you want to do.
server.createobject would be for VBScript/ASP usage on the server itself. (the 'server' object is an ASP object and would not be available in VBScript in the client browser)
To do what you want (if I am reading between the lines correctly) you would need to create an ASP script (or similar) on your server to grab the output from 'whoami' and return/output it. You could call it from your client-side page via javascript/AJAX.
(Keep in mind that running a command using 'WScript.Shell' carries its own set of security challenges, as well)
In order for the script to run on the server, you need the runat attribute on your script tag:
<script type="text/vbscript" runat="server">
or, if your default scripting language is VBScript (which it will be unless you've explicitly changed it), then you should use the ASP script delimiters <% %> instead to avoid any unexpected results due to script execution order (see this SO question for more information).
I have two asp pages on the same server. The first one generates XML dynamically using querystring informations and session information. The second one reads the first one using an XMLHTTP object and do things using the XML datas.
However, my problem is that the XMLHTTP request is done server-side. Thus, the session variables of the client are not accessible when the xml should be generated.
How can I do so that the page that generates the XML receives the session variables ?
Thanks.
There are many problems with what you are trying to do, not least is that it can lead a busy server to lock up entirely.
Here is the another approach.
Add a third page to your solution. This page contains simply a function which returns an XML DOMDocument. This function contains all the logic from your original xml generating page but builds the XML into the DOM (which you were probably doing all ready right?).
Now your original page simply includes this new function page, calls the function and sends the DOM to the response:
<!-- #include file="xmlFunction.asp" -->
<%
Response.ContentType = "text/xml"
Response.CharSet = "UTF-8"
GenerateXml().Save Response
%>
Your client page can now look this
<!-- #include file="xmlFunction.asp" -->
<%
. . .
Dim dom: Set dom = GenerateXml()
''# Code that uses the XML in the dom.
%>
No additional "Request to self" is needed hence no potential lock up. Since code in the xmlFunction.asp is running as part of the original request the appropriate Session object is accessible.