asp.net (VB) strange double image upload with CodeFile and no Namespace - asp.net

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!

Related

Access request after upload (ASP classic)

So, as I figured out, when I have a form with enctype="multipart/form-data" and I upload a file, I can no longer access the object request. The following error is shown:
Cannot use the generic Request collection after calling BinaryRead.
After checking some resources, I stumpled upon a statement, which says: "This is by design". Well, okay, not here to judge about design-decisions.
To give you a quick overview, let me walk you through the code:
if request("todo") = "add" then
Set Form = New ASPForm
category = request("category")
title = request("title")
if len(Form("upload_file").FileName) > 0 then
filename = Form("upload_file").FileName
DestinationPath = Server.mapPath("personal/allrounder/dokumente/")
Form.Files.Save DestinationPath
end if
end if
Nothing too special here so far. Later however, when I try to access my request object, the error mentioned above occures:
<% if request("todo") = "new" then %>
...
My question now, how to get rid of it or fix this. I don't want to open the upload in a popup if there is another way around. This is the only solution I could think off.
Perfectly would be an object, which checks Form and request. Alternatively maybe a check at the top of the file, which object I have to use?
Thanks for any suggestions.
There used to be a very popular ASP class/component that solved ASP file uploads. The site for that component has been taken down, but the code is mirrored here:
https://github.com/romuloalves/free-asp-upload
You can include this ASP page on your own page, and on your page instantiate the class to get access to the files in your form, but also to the form variables. Here is a piece of example code (Upload.Form accesses the form fields):
Dim uploadsDir : uploadsDir = server.mapPath(".") ' whatever you want
Dim Upload, ks, fileKey, mailto
Set Upload = New FreeASPUpload
call Upload.Save(uploadsDir)
ks = Upload.UploadedFiles.keys
for each fileKey in ks
Response.write(fileKey & " : " & Upload.UploadedFiles(fileKey).FileName & "<br/>")
next
mailto = Upload.form("mailTo")
Set Upload = Nothing
If you want to stick to your own implementation, you can probably figure out how to get to the form variables in a multipart/form-data encoded data stream by having a look at the code they use to do so.

Call VB Sub from Embedded GeckoWebBrowser using window.external.Sub1();

I have an aspx page on my webserver which I load through an embedded web browser on a windows form. I am able to call the Sub1 from javascript window.external procedure. This is only when using the standard VB control WebBrowser. I have the necessary permissions active with
<PermissionSet(SecurityAction.Demand, Name:="FullTrust")> _
<System.Runtime.InteropServices.ComVisibleAttribute(True)> _
This works just fine. However, I am in need of using GeckoFx as my javascript is too complex for the standard WebBrowser as well as my styling.
I have tried the same approach as is, just with the geckobrowser, but it does not work at all, is there any:
GeckoPrefereces.User("somesetting") = True
that I need to activate to get it to work or is there something else I am missing?
I would just like to call the 'form close' procedure of my windows form, from the webpage which is embedded in the GeckoBrowserControl.
Refer the following link for your answer as it is solved here.
How to call C# method in javascript by using GeckoFX as the wrapper of XULRunner
Change this process to C# as VB cannot send the message to a procedure, only store the value and this creates a difficult situation in reading the data later.
then:
private void showMessage(string s)
{
if (s == "some data")
{
//Do stuff here you need to, ie. close the form, etc
}
}
This allows you to read the message sent and do with it what you wish.
Also important:
browser.AddMessageEventListener("myFunction", ((string s) => this.showMessage(s)));
must be before you load the html or the url
myBrowser.Navigate("www.google.com");

Execute VB Script on page_load

I am having VB Script in ASPX page.I need to use that Script in codeBehind in Page _load with in a For loop,for each iteration.
My Code is :-
(.ASPX Page with VB Script. )
<script type="text/vbscript" language="vbscript" >
sub wordit()
'Opens Word application and does some process
end sub
</script>
VB Code Behind Part:-
For i As Integer = 1 To colSelRowIndex
CheckboxTemplateId = colSelRowKeys(i).ToString 'I get the ID from here
ViewState("TemplateID") = CheckboxTemplateId 'I need to send the value to the sub routines
hen()'sub
den()'sub
cs.RegisterStartupScript(cstype, csname1 & i, "wordit();", True)
Next
I need to open a word doc for an ID and another document for another ID from the loop.
Try this:
For i As Integer = 1 To 10
cs.RegisterStartupScript(cstype, csname1 & i, "wordit();", True)
Next
That second argument in that function call is looking for a unique key. This is a feature, to prevent accidentally programmatically adding the same script more than once. If you want to do it on purpose, you need a unique key each time.
But that you want to do this at all indicates a possible fundamental misunderstanding about what's going on. While your server code (including Page_Load) is running, your client page in the web browser doesn't exist. The purpose of the server code is always to generate an html response to web request. The server code can never directly manipulate a page DOM.
Obviously this is true for a first request to a page in session: the server must first generate the initial page to send the client. But even on subsequent postbacks, the browser will destroy the prior instance of a page. The server must rebuild the entire page from scratch. Every. Time. While this happens, the page you're looking at in your browser window is only a sort of after-image. The browser has already destroyed any prior DOM, and is waiting for the server to supply a whole new set of HTML.
I also wonder at your use of vbscript, rather than javascript. Using vbscript pretty much guarantees you're page will only work with Internet Explorer.

Write a file containing ASP delimiters

We have lots of files containing image / static file references to resources on our site. As we are moving these files to S3 hosting, I am writing a script that reads each of our ASP files, replaces each reference so that each one points at a globally defined variable, and rewrites those changes to the file, so that we don't have to update all these files manually!
This works alright with references inside actual code.
eg.
Response.Write "<img src=""http://www.site.com/images/image.gif"">"
becomes
Response.Write "<img src=""" & s3BucketName & "/images/image.gif"">"
But when it comes to replacing code like this :
<script src="/javascript/script.js">
It's more difficult - as we have to place the ASP delimiters <%= %>
around the global var around it.
eg.
<script src="<%=s3BucketName%>/javascript/script.js">
Because the script delimiters actually stop the page where they are, and generate an error, that's what I'm finding difficult. URLencoding the <%=s3BucketName%> string, and writing, just writes the encoded text (unusable by ASP), doesn't transform into what I want.
Any ideas gratefully received.
Thanks, Adam
Ok, I've come up with a solution, seems to work. If you find a better one, please comment.
textToReplace = "src="""& chr(60) & chr(37) & chr(61) & "s3BucketName" & chr(37) & chr(62) & "/javascript/script.js"
Basically each symbol of <%= and %> is converted into chr() values.
You could use the basetag in the head section of your pages then you can leave the relative urls like your script example alone, you can combine this technique with the one peedeeaay suggests.
<base href="http://www.s3bucketdomain.com/directory/" />

is it possible to issue dynamic include in asp-classic?

I mean, like php'h include...
something like
my_file_to_be_included = "include_me.asp"
-- >
for what I've seen so far, there are a couple of alternatives, but every one of them has some sort of shortcoming...
what I'm trying to figure out is how to make a flexible template system... without having to statically include the whole thing in a single file with a loooooong case statement...
here there are a couple of links
a solution using FileSysmemObject, just lets you include static pages
idem
yet another one
same thing from adobe
this approach uses Server.Execute
but it has some shortcomings I'd like to avoid... seems like (haven't tried yet) Server.Execute code runs in another context, so you can't use it to load a functions your are planning to use in the caller code... nasty...
same thing
I think this one is the same
this looks promising!!!
I'm not sure about it (couldn't test it yet) but it seems like this one dinamycally handles the page to a SSDI component...
any idea???
No you can't do a dyanmic include, period.
Your best shot at this is a server.execute and passing whatever state it needs via a Session variable:-
Session("callParams") = BuildMyParams() 'Creates some sort of string
Server.Execute(my_file_to_be_included)
Session.Contents.Remove("callParams")
Improved version (v2.0):
<%
' **** Dynamic ASP include v.2.0
function fixInclude(content)
out=""
if instr(content,"#include ")>0 then
response.write "Error: include directive not permitted!"
response.end
end if
content=replace(content,"<"&"%=","<"&"%response.write ")
pos1=instr(content,"<%")
pos2=instr(content,"%"& ">")
if pos1>0 then
before= mid(content,1,pos1-1)
before=replace(before,"""","""""")
before=replace(before,vbcrlf,""""&vbcrlf&"response.write vbcrlf&""")
before=vbcrlf & "response.write """ & before & """" &vbcrlf
middle= mid(content,pos1+2,(pos2-pos1-2))
after=mid(content,pos2+2,len(content))
out=before & middle & fixInclude(after)
else
content=replace(content,"""","""""")
content=replace(content,vbcrlf,""""&vbcrlf&"response.write vbcrlf&""")
out=vbcrlf & "response.write """ & content &""""
end if
fixInclude=out
end function
Function getMappedFileAsString(byVal strFilename)
Dim fso,td
Set fso = Server.CreateObject("Scripting.FilesystemObject")
Set ts = fso.OpenTextFile(Server.MapPath(strFilename), 1)
getMappedFileAsString = ts.ReadAll
ts.close
Set ts = nothing
Set fso = Nothing
End Function
execute (fixInclude(getMappedFileAsString("included.asp")))
%>
Sure you can do REAL classic asp dynamic includes. I wrote this a while back and it has opened up Classic ASP for me in a whole new way. It will do exactly what you are after, even though people seem to think it isn't possible!
Any problems just let me know.
I'm a bit rusty on classic ASP, but I'm pretty sure you can use the Server.Execute method to read in another asp page, and then carry on executing the calling page. 15Seconds had some basic stuff about it - it takes me back ...
I am building a web site where it would have been convenient to be able to use dynamic includes. The site is all ajax (no page reloads at all) and while the pure-data JSON-returning calls didn't need it, all the different html content for each different application sub-part (window/pane/area/form etc) seems best to me to be in different files.
My initial idea was to have the ajax call be back to the "central hub" main file (that kicks the application off in the first place), which would then know which sub-file to include. Simply including all the files was not workable after I realized that each call for some possibly tiny piece would have to parse all the ASP code for the entire site! And using the Execute method was not good, both in terms of speed and maintenance.
I solved the problem by making the supposed "child" pages the main pages, and including the "central hub" file in each one. Basically, it's a javascript round-trip include.
This is less costly than it seems since the whole idea of a web page is that the server responds to client requests for "the next page" all the time. The content that is being requested is defined in scope by the page being called.
The only drawback to this is that the "web pieces" of the application have to live partly split apart: most of their content in a real named .asp file, but enough of their structure and relationship defined in the main .asp file (so that, for example, a menu item in one web piece knows the name to use to call or load another web piece and how that loading should be done). In a way, though, this is still an advantage over a traditional site where each page has to know how to load every other page. Now, I can do stuff like "load this part (whether it's a whole page or otherwise) the way it wants to be loaded".
I also set it up so each part can have its own javascript and css (if only that part needs those things). Then, those files are included dynamically through javascript only the first time that part is loaded. Then if the part is loaded repeatedly it won't incur an extra overhead.
Just as an additional note. I was getting weird ASCII characters at the top of the pages that were using dynamic includes so I found that using an ADODB.Stream object to read the include file eliminated this issue.
So my updated code for the getMappedFileAsString function is as follows
Function getMappedFileAsString(byVal strFilename)
Dim fso
Set fso = CreateObject("ADODB.Stream")
fso.CharSet = "utf-8"
fso.Open
fso.LoadFromFile(Server.MapPath(strFilename))
getMappedFileAsString = fso.ReadText()
'Response.write(getMappedFileAsString)
'Response.End
Set fso = Nothing
End Function

Resources