Classic ASP application-wide initializations and object caching - asp-classic

In classic ASP (which I am forced to use), I have a few factory functions, that is, functions
that return classes. I use JScript.
In one include file I use these factory functions to create some classes that are used throughout the application. This include file is included with the #include directive in all pages.
These factory functions do some "heavy lifting" and I don't want them to be executed on every page load.
So, to make this clear I have something like this:
// factory.inc
function make_class(arg1, arg2) {
function klass() {
//...
}
// ... Some heavy stuff
return klass;
}
// init.inc, included everywhere
<!-- #include FILE="factory.inc" -->
// ...
MyClass1 = make_class(myarg01, myarg02);
MyClass2 = make_class(myarg11, myarg12);
//...
How can I achieve the same effect without calling make_class on every page load?
I know that
I can't cache the classes in the Application object
I can't use the Application_OnStart hook in Global.asa
I could probably create a scripting component, but I really don't want to do that
So, is there something else I can do? Maybe some way to achieve caching of these classes, which are really objects in JScript.
PS: [further clarification] In the above code "heavy stuff" is not so heavy, but I just want to know if there's a way to avoid it being executed all the time. It reads database meta information, builds a table of the primary keys in the database and another table that resolves strings to classes, etc.

it is not possible to store objects of asp classes in sessions or application (in VBScript).
that is because objects in ASP Classic are not serializable. well not automatically serializable. you could do it yourself.... but that means of course some extra work.
as i said above it is not possible to store classes written in vbscript in session or application.
you can stor classes written in jscript in the session or application. so what you have to do is write your classes in jscript in store them in the session.
then use thos classes from your (existing) vbscript code.
example:
<script runat="server" language="jscript">
function MyClass() {
this.Var1 = "54321";
this.Var2 = Var2;
}
var Var1, Var2;
function MyClassFactory() {
return new MyClass();
}
</script>
<script runat="server" language="vbscript">
dim instance : set instance = MyClassFactory()
instance.Var1 = "12345"
set session("sesInstance") = instance
response.write session("sesInstance").Var1
</script>
hope that helps sorry for my incompetence in pasting the code correctly formatted...

Related

How to get from JavaScript to TypeScript in ASP.Net MVC?

For obvious reasons we want to start with TS instead of JS in our project.
The problem we occurred are the variables who are set in the MVC Views which are set by the Model of the given View.
E.g. tes.cshtml:
#model Testmodel
<script>
var test = {};
var test.myProp = #Model.Testproperty;
<script>
Now in my test.ts I got an error when I try to get the test-variable because my TypeScript file doesn't know it.
Do I have a architecture miss-conception here? Or is there a trick to do that?
To be honest we have around 100 variables set and / or created in RazorViews, most likely a lot of Ressource-Variables from our resx files we would need e.g. in a java-script alert!
You can create definitions file and put all your global declarations there. For example:
declare interface SampleInterface{
myProp:string;
myFunc(someParameter:string):void;
}
declare var test:SampleInterface;
declare var someFunc: () => number;
More info on writing declaration files here.
One way is to attach to Window all your variables or even all your resource variables and after that you can create something like a helper in typescript where you can parse Window.Variables and Window.ResxVariables for your need.
Server-side you will need two dictionaries Variables and ResxVariables which can be statics in your base controller.
Then you will need two methods that will facilitate adding variables to these dictionaries
Variables.Add("Timezone", "GMT+2");
And
ResxVariables.Add("ExitAlert", "Please stay more");
These two methods will be accessible in your controller actions and you will have the possibility to add model properties too.
Then you will need a HtmlHelper that will help you render those dictionaries as objects attached to Window.
You will need to also support clearing those dictionaries when you render a new page or depends on your need.
When i used something like this, we had two dictionaries GlobalVariables and PageVariables. Global wasn't cleared when we render a new page, but PageVariables was.

Shared Functions in VB.Net

I have to send emails when a person receives a personal message on my website and for that I use a StringBuilder to create the HTML markup of the email.
also since it is required at many other places as well I have made a Shared Function (I am using VB.NET). now my only concern is that since shared functions are shared among all objects and maybe asp.net sessions, can it be possible that before one person email is being formed and another person access the same function, it would cause the data in the stringbuilder to be overwritten..
Currently my site doesn't have many users but can this become an issue in the future... Please advise me on this... Is there any better way or standard procedure to follow when using shared functions?
Also at one time I made the mistake of using a shared connection object and it would cause close if many people were to access it.
Shared functions can only access static/global variables as well as variable inside the function scope. So, if the the function is working with any number of static/shared resources then you need to synchronize between the calls to the function.
In your case, however, it doesn't sound like you're working with any shared resources, so it shouldn't be a problem.
Here's a case that illustrates the problem:
private static myCounter As Integer = 0
public shared function IncreaseCount() As Integer
myCounter += 1
for i as integer = 0 to 10 million
//'do extensive work
next
return myCounter
End Function
Imagine that you call the function for the first time, and you would expect it to return the number 1. But due to the fact that the function was called again before the first function call got to return the counter was increased once more, which means that both function calls return 2 instead of respectively 1 and 2. All the problem arrives when you want several things working on the same static resource.
Instead of using a static method you can have an EmailSender object attach to current HttpContext.This way each user will have its own EmailSender instance.
Here's the code in C# :
private static EmailSender _instance;
public static EmailSender GetEmailSender()
{
if(System.Web.HttpContext.Current != null)
{
if(! System.Web.HttpContext.Current.Items.ContainsKey("EmailSender"))
System.Web.HttpContext.Items["EmailSender"]=new EmailSender();\
return (EmailSender)System.Web.HttpContext.Current.Items["EmailSender"];
}
if(_instance==null)
_instance=new EmailSender();
return _instance;
}
It will work in web and windows application.
now every time you want to send an email you can do as follows:
GetEmailSender().SendMail(MailInfo mailInfo);
Also, if you're using VB.NET on Framework 3.5, you may want to look into using XML literals to build your HTML instead of StringBuilder. XML literals will make your code SUPREMELY more readable, and allow for very easy insertion of data into your message.
As a SIMPLE example...
Dim msg = <html><body>
Message sent at <%= Now.ToString() %>
</body></html>
myMailMessage.IsBodyHtml = True
myMailMessage.Body = msg.ToString()

asp.net server control - avoid adding multiple javascript

I created an asp.net Server control that derives from a LinkButton, and renders a small javascript function to the page.
I want to use this control many times on the page, but just want the javascript to be rendered once on the page. On the other hand, I rather not manually add it in a js file, because i don't want to have a chance of forgetting to add the js file in the future.
What will be the best way to go about doing this ?
Preventing duplication in client scripts
Use a registration method such as Page.ClientScript.RegisterClientScriptBlock(..). There are a couple of overloads but they all work in a similar fashion. It's smart enough to render the script only once no matter from how many control instances it's issued.
Microsoft remarks in the MSDN documentation:
A client script is uniquely identified
by its key and its type. Scripts with
the same key and type are considered
duplicates. Only one script with a
given type and key pair can be
registered with the page. Attempting
to register a script that is already
registered does not create a duplicate
of the script.
The MSDN docs also contain sample code such as this:
// Check to see if the client script is already registered.
if (!cs.IsClientScriptBlockRegistered(cstype, csname2))
{
StringBuilder cstext2 = new StringBuilder();
cstext2.Append("<script type=text/javascript> function DoClick() {");
cstext2.Append("Form1.Message.value='Text from client script.'} </");
cstext2.Append("script>");
cs.RegisterClientScriptBlock(cstype, csname2, cstext2.ToString(), false);
}
Other similar registration methods
Different methods can be used to register your client script in different ways - see each of the ClientScriptManager.RegisterClientScript*(..) methods in MSDN for more detail about each. They're all built to prevent duplication in the rendered page.
This gives you the freedom to output scripts at the control level without worrying or having to track or count scripts.
Edit:
The ClientScriptManager instance is accessed through the Page.ClientScript property.
You can use the Page.RegisterClientScriptBlock method.
Here is an example from the MSDN:
if (!this.IsClientScriptBlockRegistered("clientScript"))
{
// Form the script that is to be registered at client side.
String scriptString = "<script language=\"JavaScript\"> function DoClick() {";
scriptString += "myForm.show.value='Welcome to Microsoft .NET'}<";
scriptString += "/";
scriptString += "script>";
this.RegisterClientScriptBlock("clientScript", scriptString);
}
HTH
Any way to reference a script on a CDN and not have it duplicated multiple times? Or can I just not worry about it since it's just a pointer anyway and the browser is (?) smart enough not to load the same library twice?
In other words, suppose I want the following code inserted from a server control:
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.4.4/jquery.min.js"></script>
If I use a RegisterClientScriptBlock I can use the IsClientScriptBlockRegistered method to not have the server control load it multiple times. But, the preceding code is likely to have been put on the page anyway by either another (different) server control or by the developer who wants to use jQuery for something outside of the server control.
How do I get the server control to not load the script if the developer already loaded it?

Multiple user controls and javascript

I include a JS file in a user control. The host page has multiple instances of the user control.
The JS file has a global variable that is used as a flag for a JS function. I need the scope of this variable be restricted to the user control. Unfortunately, when I have multiple instances of the control, the variable value is overwritten.
What's the recommended approach in a situation like this?
Some options are to dynamically generate the javascript based on the ClientId of the User Control. You could dynamically generate the global variable for example.
Another option and one I would recommend is to encapsulate the global variable and function within an object, then your user control can emit the JS to create an instance of that object (Which can be dynamically named thus letting you scope the object as you see fit).
Edit
I don't have a working code sample that I can share but, I have done this in a couple different ways. the easiest method is to do this in the markup of your user control.
<script language='javascript'>
var <%=this.ClientID%>myObject=new myObject();
</script>
Assuming your control has a clientId of myControl this will create a variable myControlmyObject.
Another way to do this would be to generate the script in the code behind you could register it using: Page.ClientScript.RegisterStartupScript().
I would recommend refactoring your code such that all the common JS logic is stored in one place, not in every UserControl. This will reduce the size of your page by a good margin.
You can pass in the id of the UserControl to the common JS method(s) to differentiate between the UserControls.
For the issue of limiting the scope of your 'UserControl' variable, you could store some sort of a Key/Value structure to keep your UserControl-specific value - the Key would be the UserControl clientID, and the value would be the variable that you're interested in.
For example:
var UCFlags = new Object();
//set the flag for UserControl1:
UCFlags["UC1"] = true;
//set the flag for UserControl2:
UCFlags["UC2"] = false;
To access them, you simply pass the ClientID of the UserControl in to the UCFlags array:
myFlag = UCFlags["UC1"];
On the server-side, you can replace the constant strings "UC1" or "UC2" with
<%= this.ClientID %>
like this:
myFlag = UCFlags["<%= this.ClientID %>"];
You can still use the <%= this.ClientID %> syntax here even though the bulk of the JS is in a separate file; simply set
UCFlags["<%= this.ClientID %>"] = value;
before the call to embed the JS file.
Well, if you have to keep with the current solution, you could rename your global variable to something like the following code, which should be in the .ascx file for your control:
<script type='text/javascript'>
var <%= this.ClientID %>_name_of_global_variable;
</script>
Where "this" is the asp.net control. That way, each control has a unique variable name, based off the client id. Make sure you update the rest of your javascript to use this new naming convention. The problem, it looks messy, and the variable names will become very long depending on where the control is embedded in the page.
Does that make sense? It should take minimal javascript modification to get it working.
I ran into same issue and below blog post solved it. Solution is to take Object oriented way for javaScript
Adding multiple .NET User Controls that use JavaScript to the same page

ASP.NET Localized web site -- updating on the fly

I think I have a solution to this, but is there a better way, or is this going to break on me?
I am constructing a localized web site using global/local resx files. It is a requirement that non-technical users can edit the strings and add new languages through the web app.
This seems easy enough -- I have a form to display strings and the changes are saved with code like this snippet:
string filename = MapPath("App_GlobalResources/strings.hu.resx");
XmlDocument xDoc = new XmlDocument();
XmlNode xNode;
xDoc.Load(filename);
xNode = xDoc.SelectSingleNode("//root/data[#name='PageTitle']/value");
xNode.InnerText = txtNewTitle.Text;
xDoc.Save(filename);
Is this going to cause problems on a busy site? If it causes a momentary delay for recompilation, that's no big deal. And realistically, this form won't see constant, heavy use. What does the community think?
I've used a similar method before for a very basic "CMS". The site wasn't massively used but it didn't cause me any problems.
I don't think changing a resx will cause a recycle.
We did something similar, but used a database to store the user modified values. We then provided a fallback mechanism to serve the overridden value of a localized key.
That said, I think your method should work fine.
Have you considered creating a Resource object? You would need to wrap your settings into a single object that all the client code would use. Something like:
public class GuiResources
{
public string PageTitle
{
get return _pageTitle;
}
// Fired once when the class is first created.
void LoadConfiguration()
{
// Load settings from config section
_pageTitle = // Value from config
}
}
You could make it a singleton or a provider, that way the object is loaded only one time. Also you could make it smart to look at the current thread to get the culture info so you know what language to return.
Then in your web.config file you can create a custom section and set restartOnExternalChanges="true". That way, your app will get the changed when they are made.

Resources