Over the past few weeks I have taken the advice of a few people and have started using Community Server as a model for the applications I am working on. Community Server is a very complex application and as I study it more, the more I learn and start to see how I can integrate some of their designs into my applications. To check out the latest code tree for CS, visit CoJax at http://code.communityserver.org or visit http://www.communityserver.org to download the source code.
One thing that caught my eye was the way they read configuration values for their application. In the past when I needed this functionality in my application I would write my own configuration handler for the web.config file, and then write a custom object that the xml data from the config file could be serialzied into. I saw this approach done in other articles and applications and it was pretty easy and "SEXY" to implement. One drawback that I saw to this approach though was the fact that the data was stored in the web config file so when a change was made to the configuration the application would be restarted. Another drawback that I was always concerned about was the cost of the serialization of the xml data into the custom object.
In community server they have their own configuration file that gets loaded into a CSConfiguration object. Instead of serializing the data into a custom object, they process the xml document using the DOM and populate the properties of their custom configuration object. What I really like about this approach is the fact that it provides a clean and straight forward way to set the default values of the object. You can also establish your own config file that will not cause the application to restart. Instead, what you can do, which is what Community Server does, is store the custom config object into the cache, and create a cache dependency against the config file so when changes are made to the config file the cache reference will expire.
To see an example of this check out the links above and look for the CSConfiguration.cs class file located at "CS Tree \ CS 1.1 \ Components \ Configuration \ CSConfiguration.cs
Well, I took Dave up on his offer to setup a new blog for me and so far I am happy with my new home. I am very excited to be running on the latest version of Community Server. I just brought over a few of my blog posts from DotNetJunkies and I am happy to report that I did not get any of those nasty errors, but I did get them while trying to retrieve the posts from DotNetJunkies.
I'm glad to make the jump. While I don't post a whole lot, I am really trying to start posting more but my problem has always been topics. What I am going to start doing though is start blogging more about what I am currently working on, and how I accomplished certain tasks. Then, hopefully through other blog posts or comments, people may suggest better/different ways of doing things.
Happy Blogging!
I just got done reading Peter's post about a limitation he ran into about sharing session variables across web applications, and thought I would blog about an approach we recently took with one of our web apps to get around this problem.
We got our solution from this MSDN article, which shows you how to separate out your web applications into smaller web applications. The first step is to create an IIS application and this is the root of your web application. Under this root, you create your smaller modules as virtual directories, but don't configure them to have their own web application. (now refer to the article to see how to make this friendly to VS.Net) Now, because the root is setup as a web application, this is the guy that manages your session state for all of the modules below it, and our session state can no be shared across all of the different modules.
Now I understand that this won't be for everyone, but in our case it has worked out great. We are currently building a pretty large web system that consists of various modules, and one requirement we would like to satisfy is to allow us to deploy each module separately but also be able to share session state across all of the modules. We have a main IIS root application and each module is setup as a virtual directory under it. The root, and each of the modules each has its own ASP.NET web project and can be compiled separately. This would allow us to only update specific modules when needed. So now when we make changes to just module A, we can build the web app for module A, plus all of its supporting assemblies. By having all of the modules under the root, all of the modules can now also share session state.
Hope this makes sense, but if it doesn't the MSDN article will really clear things up since they provide good instructions on how to get everything configured.
Clarke Scott just posted about some free tools that could be found at http://devcenter.infragistics.com/. While I was there I noticed an article about JavaScript debugging and decided to see if there was anything new there. (A direct link to the article is http://devcenter.infragistics.com/Articles/ArticleTemplate.Aspx?ArticleID=2183 I have never seen this technique for debugging JavaScript before and it will be a true time saver for me to help debug all the JavaScript we do in our apps. If you are looking for a way to debug JavaScript you need to check this article out. While the IE script debugger has always been available it has never worked well enough for me as I had numerous problems with it and it also did not debug JavaScript include files. This technique does just that.
Here is a snipped from the article as a reference. I did this just in case they ever take down the article.
--------------------------------------------------------------------------------
ASP.NET has many advantages over classic ASP in the area of debugging. You can now easily debug your server-side code using the full power of a modern debugger such as Visual Studio .NET. This, along with the introduction of server controls and a postback architecture, has simplified Web-based development. But what about the other half of a Web application, the client-side script?
Although server controls and postbacks have reduced the need for Web developers to interact with JavaScript in an ASP.NET application, many developers are learning that they cannot forget about client-side scripting altogether.
Developers creating Web pages designed to display even a moderate amount of data know the cost of posting back to the server. Using JavaScript to perform simple tasks minimizes the number of roundtrips to the server, potentially avoiding unnecessary queries to the database and reducing the number of times the ViewState is pushed over the wire.
Besides reducing the amount of network traffic, the use of client-side JavaScript enables ASP.NET developers to provide a richer and more interactive experience to the end-user. By moving appropriate functionality from the server to the client you provide the user with instant responsiveness and feedback without the latency implicit in a postback. Balancing functionality between both the client and the server helps reduce some of the load on the Web server, which in turn yields better server response times.
A substantial roadblock to using JavaScript, though, is that it can be difficult to write and debug.
First, IntelliSense for JavaScript is limited at best, which leads to errors in the initial coding stage. Because JavaScript is case-sensitive, the lack of IntelliSense can be aggravating - particularly for developers turning to ASP.NET from a case-insensitive language like Visual Basic.
Also, when a browser's JavaScript error message provides a line number to look at, it often doesn't match the line numbers indicated in the code. The line number will get you in the right area, but after that, it often becomes a guessing game.
Furthermore, if you try putting a breakpoint in the JavaScript in your ASPX, you'll find that when running the project, control will not stop on it and, at best, you may get the not-so-helpful message, "Breakpoint will not be hit, symbols have not been loaded for this document."
Tap into HTML
With Internet Explorer 6 and VS .NET, Microsoft has provided a way to tap into the HTML and JavaScript that Internet Explorer is running, thereby closing the loop in the debugging cycle. By closing this hole developers can now debug their entire application in a single IDE - from client-side script to server-side code, and possibly right through to the database.
Unfortunately for most developers, this won't work without some basic set up. To verify that Internet Explorer is set up correctly, open Internet Explorer, choose Tools | Internet Options. Click the Advanced tab and find Disable script debugging about halfway down the list. Make sure there is no check in the box next to this option. Click OK and close Internet Explorer. The browser is now ready to work with Visual Studio .NET to debug your application.
To begin exploring the basic functions of the debugger, start a new WebForms project and run it without adding any controls or code. When the empty project loads in Internet Explorer, return to Visual Studio and open the Running Documents window by selecting Debug | Windows | Running Documents from the Debug menu.
The Running Documents window will appear docked on the right edge of the IDE. The name of the page, "WebForm1.aspx", will appear in the window. Double-click the page and the HTML rendered to the browser when the ASPX page was evaluated by the server will be shown in a code window on the left.
The code provided by the Running Documents window is where a developer can set breakpoints and step through the code, just like in server-side code.
Debug Startup Code
Unfortunately, the technique described above breaks down when you try to debug code that executes on start up, such as from a server-side Page.RegisterStartUpScriptBlock method in the page load event. Because the JavaScript code runs as the page loads, you have no opportunity to return to the IDE to set a breakpoint.
Debugging startup script code requires a different method for debugging. There are three ways to debug startup script. First, start your project with F10. Pressing F10 will load your default startup page in the browser and immediately put you in break mode on the first line of JavaScript. You can then set another breakpoint elsewhere in your code, or you can step through line by line until you reach the line of interest.
Next, run the page, let the error occur, then set the breakpoint and hit F5. This method comes in handy when you receive an unexpected error. After the page has loaded in your browser and you get an error or incorrect behavior, open the appropriate Running Documents window and place a breakpoint where you would have wanted execution to stop. Return to the browser and hit F5. Visual Studio .NET will recognize that this is the same page you loaded before and will keep your breakpoint in place. When execution reaches the breakpoint, control will return to the IDE.
Finally, use the debugger keyword. The debugger keyword works just like a breakpoint. When the JavaScript interpreter reaches this keyword, it halts execution and returns control to the IDE.
Debugging startup script is a little more difficult than debugging script behind a button click or a validation routine because it is hard to insert a breakpoint at the right place. Starting the page with F10 or using the debugger keyword can help break into the code. From that point, a developer can find the errors in his logic using the same powerful tools he is accustomed to using with server-side code.
Visual Studio .NET provides the same powerful and flexible tools for debugging your client-side code as it does for server-side code. Get the most out of Visual Studio .NET by using the techniques described here to close the loop and debug your entire ASP.NET application in one IDE.
I just saw Dino's post on his wish list for ASP.Net tracing and saw he wanted the tracing window in a popup window. This is something we wanted for our web apps as well, so here is how I tackled the problem. I know its not perfect and the output is still put out to the main page, but the reason why I had to come up with this scheme was because in our web apps we are using absolute positioning. When we did this our content was placed over the top of the trace div.
Here is the code.....
============== Parent ASPX Page =================
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<TITLE>Parent Page</TITLE>
<SCRIPT>
function SetupTraceWindow()
{
var div = GetTraceDiv();
if(div==null) return;
win = window.open("Trace.htm","Trace");
if(win==null) windown.status="The trace window was blocked. Please make sure popup blockers are off.";
}
// Called by the child window to get the html of the trace output and also hides the trace output on the parent page.
function GetTraceHTML()
{
var div = GetTraceDiv();
if(div==null) return "";
var html = div.outerHTML;
div.style.display="none";
return html;
}
// Returns the div that is created by the ASP.Net trace function
function GetTraceDiv()
{
var div = document.getElementById('__asptrace');
return div;
}
</SCRIPT>
</HEAD>
<BODY ms_positioning="GridLayout" onload="SetupTraceWindow();">
<FORM id="Form1" method="post" runat="server">
This is the parent page.
</FORM>
</BODY>
</HTML>
======================= Trace.htm =======================
<!DOCTYPE html public "-//w3c//dtd html 4.0 transitional//en">
<HTML>
<HEAD>
<TITLE>ASP.Net Trace Output Popup</TITLE>
<SCRIPT language="javascript">
function SetupTrace()
{
var html = opener.GetTraceHTML();
document.writeln(html);
opener.focus();
}
</SCRIPT>
</HEAD>
<BODY onload="SetupTrace()">
<DIV id="myTrace"></DIV>
</BODY>
</HTML>
I just came across a post on the asp.net forums about wanting to control how view state is saved with a page. As we all know by default view state is rendered as a hidden element on the page, but that can easily be changed and you can set your pages up so that viewstate is saved to the cache, session, or the database.
The first step I would suggest is to create a base page for your aspx pages and override two methods, LoadPageStateFromPersistenceMedium and SavePageStateToPersistenceMedium. As you can tell by their names, these are the two methods responsible for determining how view state is actually handled in the page.
The following is what I put together for the SavePageStateToPersistenceMedium method. This method will take the viewstate object that is passed in and run it through a special formatter to serialize the object. According to MSDN, the LosFormatter object is designed for highly compact ASCII format serialization and serializes the view state for a WebForm page. Once the object has been serialized, I then save the viewstate to a session variable. I used a session variable for demonstration purposes only, but once the object has been serialized, it can be saved to session, cache, or a database. Here is the code for the SavePageStateToPersistenceMedium method:
protected override void SavePageStateToPersistenceMedium(object viewState)
{
// Saftey check to ensure we have a valid object
if( viewState==null) return;
// Instantiate the formatter used by the framework to serialize viewstate
LosFormatter formatter = new LosFormatter();
// We need a stream writer to write the viewstate text to
StringWriter writer = new StringWriter();
try
{
// Serialize our view state to the string writer
formatter.Serialize( writer, viewState );
// Save the view state to session state
Session["ViewState"] = writer.ToString();
}
catch
{
throw new HttpException("Invalid view state");
}
finally
{
// Clean up
writer.Close();
}
}
The next step is to override the LoadPageStateFromPersistenceMedium and load the viewstate data from the same location it was saved to in the SavePageStateToPersistenceMedium method. This is where we take the data out of our session object and then deserialie the data. Here is the code for the LoadPageStateFromPersistenceMedium method:
protected override object LoadPageStateFromPersistenceMedium()
{
object viewStateObj = null;
// Instantiate the formatter used by the framework to serialize viewstate
LosFormatter formatter = new LosFormatter();
// Grab our viewstate from session
object sessionViewState = Session["ViewState"];
try
{
// Deserialize the object
viewStateObj = formatter.Deserialize(sessionViewState.ToString());
}
catch
{
throw new HttpException("Invalid view state");
}
return viewStateObj;
}
Once you implement this code, you will notice that a hidden viewstate field is still dumped out into your page, but its empty.