Intro: Have you ever needed to use JavaScript on a User Control/ Server Control in ASP.NET?
The code behind the scenes, where you just add the literal script, was messy, and at times just plain old hard to follow. Not to mention also when someone else wrote the code. Well, using resource files (.resx and .resources) inside ASP.NET applications changes everything. This approach makes your code easy to use, and allows you to focus on the real VB.NET/C#/C++ code to make your web application more manageable.
There are many creative things you can do when using this approach.
- You could use the resource file to store images, XML files, XSL files, XSD files, VBScript files, sound clips in different languages (or even using the new .NET Speech SDK grammar files), and even video clips that are loaded dynamically.
- You could create these resource files to load into another Windows application. Here�s a thought: You have a company that designs logos, given an upload of a Windows form, or Web form, on your web site, you could dynamically (using real time) change the Windows form or Web form on your website to show your customer, the new dazzling effects of your newly created images, using resource files.
- Or simply use the resource file to store your JavaScript and dynamically load it during the server process of you User Control.
To keep things simple let�s use the 3rd approach.
Normally, the steps involved with using JavaScript with a User Control are quite simple. However, when retracing through the code, you quickly see the messy conglomeration of both .NET code and script code. Can we say uhggghhhleeee (ugly) boys and girls? We thought ASP.NET was suppose to separate the �Code� from the �HTML tags�. Well, for all intents and purposes, except User Controls, Server Controls and dynamic controls, ASP.NET does a fair job.
In order to use the User Control inside the JavaScript, your script must be able to access it through its �ID� naming scheme, or document[�ID�] properties. This is somewhat a problem, because when ASP.NET recompiles the ASPX page, the ASP.NET engine renames your user control to an arbitrary name, sometimes, depending on if you�re using a Repeater
or DataList
control, so for the safe side we�ll access it another way. ASP.NET comes to the rescue with a property called CLIENTID
. This ClientID
is exactly what the arbitrary name value is, the client�s id for that particular user control.
So, now that we have the ClientID
, we can use it for access in the JavaScript. But, wait a moment! The client script in most cases has already been written with an ID that we used from our design. How can we get that ClientID
into our JavaScript? Some choose not to write the JavaScript in the client side HTML tags; they choose to place it inside the VB.NET/C#/C++ code anywhere between the Page_OnLoad
to the Page_UnLoad
events. They call the function Page:: RegisterClientScriptBlock()
. And then substitute the ID value in the literal JavaScript code with the ClientID
value inside this literal string value and pass it to the function.
While this method works, it is not the cleanest form when dealing with huge amounts of script code. This is the basis for this article. Here�s an example of what we�re discussing:
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Dim oCntrl As Control = DIV1.FindControl("UcForm11")
Dim odiv1 As HtmlGenericControl = _
DirectCast(oCntrl.FindControl("DIV1"), HtmlGenericControl)
odiv1.Attributes.Add("onclick", "Show_Message();")
Dim sDivID As String = odiv1.ClientID
oCntrl = DIV1.FindControl("UserInfo1")
Dim sUserInfoClientID As String = oCntrl.ClientID
� Now Add the Client Side Script along with its
�ASP.NET Generated ClientID values
dim sJS as StringBuilder = new _
StringBuilder (�<script language="�Jscript�">function")
sJs.append(" Show_Message(){ if (document.all[��)
sJs.Append( sDivID )
sJs.Append _
(��].style.visibility == �hidden�) { return; } else { document.all[��)
sJs.append(sDivID)
sJs.append(��].style.visibility = �hidden�; }")
sJs.append("SaveListing();} function SaveListing(){")
sJs.append("/*do validation on object everything OK */")
sJs.append("alert(�Document Saved!\n Thank you for Using")
sJs.append(" Resource Files In ASP.NET�);}</script>�)
RegisterClientScriptBlock(�Show_Message�, sJs.ToString())
End Sub
It this example, there are two user controls inside the ASPX page. One called UcForm11
,
and the other UserInfo1
.
Inside the page load event, the client IDs are stored inside the string variables and then passed to a sJS
string variable which is then passed into the RegisterClientBlock
method of the Page
object. This method adds the client side script as you can see written in the literal string values of the sJS
variable's append()
method. When the HTML tags are processed, the JavaScript is sent to the browser with the substituted ClientID
values. Now imagine the literal Jscript code to be 1000 lines long, or even intertwined with src=somefile.js
attribute, calling other functions inside these functions from the Jscript source file, as well as calling other methods inside that 1000 script section. Can we say �Nightmare on ASPX street!� Practically one long scary night in order to debug and manage.
How do we clean this up?
We use resource files. Let�s use the same steps as above. However, we�ll use a resource file, which we�ll explain how to generate in a second, to show �How Neat It Is� (pun intended). Here�s the example:
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
Dim oCntrl As Control = DIV1.FindControl("UcForm11")
Dim odiv1 As HtmlGenericControl = _
DirectCast(oCntrl.FindControl("DIV1"), _
HtmlGenericControl)
odiv1.Attributes.Add("onclick", "Show_Message();")
Dim sDivID As String = odiv1.ClientID
oCntrl = DIV1.FindControl("UserInfo1")
Dim sUserInfoClientID As String = oCntrl.ClientID
Dim sBinDirectory As String = Server.MapPath("bin")
Dim rm As Resources.ResourceManager = _
Resources.ResourceManager.CreateFileBasedResourceManager("Jscript", _
sBinDirectory, Nothing)
Dim sJS As StringBuilder = New _
StringBuilder(rm.GetString("Show_Message"))
sJS.Replace("@Div1ID", sDivID)
Page.RegisterClientScriptBlock("Script1", sJS.ToString())
End Sub
Look for the Jscript code in the preceding example�.
Don�t see any here do you? That�s because all the Jscript code and details are inside the resource file named Jscript.resources. We copied this file into the bin directory of the ASP.NET application and then loaded this file into the ResourceManager
object. The ResourceManager
object is that same object that�s used in Windows Forms where you can create a Windows Form and add a couple of background images to it and it's saved inside a .resx file for the Form
. When the Form
loads, the Windows form code calls this same ResourceManager
object and loads the picture image from the resource file, only this time the .resx file is embedded into the EXE or DLL file itself.
The ResourceManager
has two main methods for retrieving the values inside a .resource file. It has the GetString()
and the GetObject()
methods with overloaded signatures, that allow you to also specify what culture, if your resources contain different cultures of their perspective data. Basically one call to one of these methods and you're done.
Next we loaded the sJS
variable with the String
representation of data item named Show_Message
from the ResourceManager
. Clean and simple. No Jscript code to untangle inside our VB.NET code. Oh how neat it is!
OK, it is neat, so how do we generate resource files?
There are a couple of ways of generating resource files. One way is to use the ResourceEditor.exe program that comes with the VS.NET SDK samples. This is a Windows based program that allows you to add images, icons, and string resources. It is a program written in C# that comes with source code so that you can add your own types of files that you may want to include, to save as .Resources files.
Another way is to programmatically, use the ResourceWriter
object with its functions and properties, to dynamically generate resource files.
What about the solution being XCOPY aware? Versioning? And signing?
As noted by Dr. Heiko Voss (Thanks for your research), Microsoft recommends using resource files as satellite assemblies, instead of just the .resources files. These satellite assemblies, are basically the .resources file compiled into a library (DLL) .NET assembly. All the normal conventions can be used with satellite assemblies. You can give a strong name to them, publicly sign them and so on.
In order to create a satellite assembly, you first create the .resources file (or convert the .resx file to .resources) and then use the Assembly Linker Tool (AL.exe) that comes with the .NET SDK as such:
al.exe /t:lib /embed:JScript.resources /out:JScript.dll
Even though it is still difficult to link/embed the satellite assembly into the ASP.NET generated main assembly, you can still get to the ResourceManager
object by using code such as this:
Dim assm As Reflection.Assembly = _
Reflection.Assembly.LoadFrom(sbinDirectory _
& "\JScript.dll")
Dim rm As Resources.ResourceManager = New _
Resources.ResourceManager("JScript", assm)
Dim sValue As String = rm.GetString("Show_Message")
There is also the .resx file which is an XML based resource file that is eventually saved to the .resources format. However, it is saved inside the .EXE or DLL application that you�re writing. Using the .resx file inside the DLL generated by ASP.NET is kind of difficult, due to the fact that the ASP.NET engine recompiles your application upon execution (ASP.NET shadowing feature) which means that the names all get regenerated, thus your resource name, may not be the particular name you gave inside the design mode. Especially if you are using it inside VS.NET. Thus, you probably would want to convert your .resx file to a .resources file and then load the ResourceManager
using the .resource file instead, inside an ASP.NET application. Converting is as simple as loading the .resx file inside the ResourceEditor.exe program and clicking Save As� �name.resources� file.
Here�s the step by step process to create a String resource item named Show_Message
- Create your JavaScript inside Notepad, or an HTML editor. (Remove any tabs, line feeds, returns or escape characters from your text. You could use the search and replace feature from your editor to search for all tabs and line feeds and replace them with spaces.)
- Copy you JavaScript text with all escape characters removed into the clipboard.
- Compile the ResourceEditor.exe program that comes with the .NET SDK samples (Our version is included in the Downloads section of this article)
- Start, and running the ResourceEditor.exe program, you�ll see a screen like this:
- Inside the Resource Editor program, select the type of resource you want to add. Select
System.String
.
- Inside the
TextBox
next to add, type the name of the resource item you want to store. Type in: �Show_Message� and click on the Add button. After clicking Add, you�ll see a screen like this:
- Click inside the textbox next to the "Show_Message" listing and paste your JavaScript code you copied from the HTML editor.
- Next go to File--Save as--YourFileName.resources. Save the file as Jscript.resources
- Save this file to your bin directory inside your web application and you have just created your resource file.
Oh how neat it is!
As with everything this solution is not intended to be used for every possible problem. There will be times where the time put into creating a resource will not be beneficial. Thus, using the �messy� way will be a quick solution to the problem. Here are some other advantages and disadvantages of using the resource file based approach in ASP.NET. We�ll let you be the judge! Until next time, Hotep.
Advantages and disadvantages
This article explained how to use plain text files such as, .JS, *.vbs, and *.XML and others inside a resource editor program for your ASP.NET applications.
The benefits to do so are:
- You don't have to worry about multiple external files such as XML files your application may use, if they become corrupted by a virus or an experimental user. Just one .Resources file is all you are concerned with.
- Your external files are kept in one central location; inside your binary directory, or wherever you choose safe. You are not concerned over where the location of your external files are, again you just have one file to manage.
- During debugging, when using Jscript, your .NET code stays neat and you don�t have to intermingle script code, or XML code, making it easy to follow for fellow developers.
Now let's take a look at some disadvantages:
- The size of your .Resource file will increase in accordance to the size for resource file(s) you added. If your files are too big, you must be aware of the download time in a web environment dealing with your server controls etc.
- If any item in your resource file changes, you have to re-load your resource into the Resource Editor again, to make sure the changes are reflected, and overwrite the .resources file again. As far as the ASP.NET application is concerned, if the old .resource file is loaded into ASP.NET memory or cache, you will need to reload the resource file again to see the changes.
- The more complex your resource file is, and how it is used in your application, will undoubtedly mean that your code to use the resource file will be complex, and difficult to code, thereby making your code more messy.
So as we can see, there are certain situations where this might not be the best solution for the goal at hand. Yet, this does supply a viable solution to other types of applications.