This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


This article assumes you're familiar with Active Server Pages, Visual Basic, Visual J++, and Visual C++.
Download the code (239KB)

Building a Web Knowledge Base with Visual Studio 6.0 Enterprise Edition
Bruce Shankle and Steve Zimmerman
     
With many powerful tools in one package, Visual Studio 6.0 lets you create solutions with the best tool for the job.
Everyone loves the convenience of being able to find information on the Web. It benefits your company as well; you can save time and money by having an easily accessible system your customers and employees can use to find answers to their questions.
      Let’s explore how you can use Visual Studio® 6.0 to create a sophisticated Web-based knowledge base for delivering information from your database to your online community. We’ll use a number of tools in the Visual Studio 6.0 Enterprise Edition—including Visual InterDev™, Visual Basic®, Visual J++™, and Visual C++®—to create every aspect of the application. What we’ll end up with is a three-tier distributed application: script-enabled HTML pages for the Web-based user interface, a handful of COM-based components for the business logic, and a SQL Server™ database to manage the data.
      Separating an application into several functional layers is certainly not a new idea. But until recently, "distributedness" has been nearly impossible to put into effective practice under Windows. Fortunately, the emergence of COM, the Internet, and the Windows® Distributed interNet Application (Windows DNA) architecture makes the goal of distributed, enterprise-ready software a reality. Visual Studio 6.0 makes it almost easy.

A Component-based Approach
      Since this article is about developing a Web application, you might be asking yourself why we’ve gone to the trouble of using so many different products from the Visual Studio suite—why not simply use Visual InterDev 6.0 or FrontPage® 98? First off, if you’ve taken even a cursory glance at the "What’s New" list for the products in Visual Studio 6.0, you know that Microsoft is working hard to ensure that every one of those tools is Internet-aware. That means that as your application moves to the Web, you’ll still be able to use the tools you are most comfortable with.
      Second, although Visual InterDev alone could be used to create a rudimentary knowledge base composed of Active Server Pages (ASP) and calls to the Active Data Objects (ADO) framework, what if the structure of the database changed or complex new business logic had to be added? It wouldn’t take long before you’d have to completely rewrite your ASP scripts and update your whole site. For small-scale systems this might not pose a problem, but if you had more than a few pages to update, you’d be in trouble because raw ASP script isn’t very easy to maintain.
      To avoid these pitfalls you should separate the rendering of the data on a Web page from its underlying database structure. One way to do that is to create carefully designed black-box components that encapsulate program logic and database access. These components should expose Web-friendly output to your ASP scripts via interfaces that rarely, if ever, change. Changes to the underlying data scheme may require encapsulated changes to your components, but not to your ASP code.
      Not coincidentally, separating the component interface from the implementation is the primary goal of COM and one of the chief directives of the Windows DNA architecture. Simply stated, Windows DNA distinguishes three areas of computing: the user interface, the business logic, and data storage. For more information, refer to the Windows DNA Web site at http://www.microsoft.com/dna. In our sample knowledge base, the user interface is the ASP-generated HTML displayed in the Web browser. The business logic layer consists of components that supply formatted data to our ASP pages. The data storage layer includes the database server and the set of components—namely ADO—that retrieve the raw data from the server (see Figure 1).

Figure 1: Knowledge Base Architecture
Figure 1: Knowledge Base Architecture


      You don’t have to be a rocket scientist to take advantage of the Windows DNA architecture. Even if you aren’t developing large-scale mission critical information systems, you can enjoy the benefits of having a component-based system, including improved debugging, maintainability, and scalability. Furthermore, component-based systems can be made more efficient and secure by putting components under the management of Microsoft® Transaction Server (MTS) technologies in Windows NT® Server.

The Scenario
      We’ll introduce our knowledge base using a fictional company scenario. Aircraft Incorporated is a fast-growing company that manufactures airplane components. It has a large corporate headquarters and a separate manufacturing facility for each of the components it sells—propellers, wings, and engines. Each division has established its own IT infrastructure and has its own software development groups.
      For improved customer support, Aircraft Incorporated has decided to create a Web-based knowledge base. The corporate sales office has set up several Windows NT-based servers to run Internet Information Server (IIS), SQL Server, and MTS, and will provide the initial database and core Web site. Development and content will be distributed so that each division provides information about its own components. Specifically, the software group from the Propeller Division is assigned to create a component to handle knowledge base articles about propellers, and so on. Each division can write its components with the tool of its choosing, so long as each component conforms to the guidelines set forth by the application architecture: each component must be a COM class that polymorphically implements the appropriate interface.

Designing the Database
      Owing to the lack of support for database development in previous versions of Microsoft tools, software developers have traditionally resorted to various third-party products for database design. Although those tools were an improvement over hand-coded database definition language (DDL), developers have long been asking for a consistent, integrated, visual tool for database design. Fortunately, the 6.0 release of Visual Studio offers that functionality. The Microsoft Visual Database Tools—which ship with the Visual Studio 6.0 Enterprise Edition—include the Data View, Query Designer, Database Designer, and Stored Procedure Editor. Furthermore, this release of Visual Studio comes with new OLE DB providers for several popular databases including SQL Server and Oracle.
      Since the knowledge base application will encapsulate access to our database tables via COM objects, we could have implemented the schema using just about any database management system—that’s one of the nice things about the Windows DNA architecture. But since SQL Server 6.5 Developer Edition is included with Visual Studio 6.0 Enterprise Edition, that’s the DBMS we chose to use. Incidentally, if you are planning to use SQL Server, it would be a good idea to have your database administrator create a separate database device for you.

Figure 2: WebKB
Figure 2: WebKB


      To get started, we used Visual InterDev 6.0 to create a new database project. We followed the project creation wizard to create a new SQL Server data source named WebKB (see Figure 2). We added new tables by choosing the New Table option from the Tables context menu. Using the table designer, we created three identical tables (one for each manufacturing division) with the data layout shown in Figure 3. Notice that we used a built-in SQL Server stored procedure, getdate, for the default value of the date_created field. When we saved the resulting database scheme, Database Designer gave us the option to save the equivalent SQL statements before executing them on the server (see Figure 4). Having the SQL database definition is especially useful if you don’t have permission to create tables on the server machine, as is the case in many large organizations. In that case, you would design the tables and then send the generated script to a database administrator with the rights to execute it for you on the server.

Figure 3: Table Designer
Figure 3: Table Designer


      As you can see, our WebKB database is quite simple. You’ll most likely use a significantly more complex database design for your own projects. Although the Microsoft Visual Database Tools make it easy to design a good database, they also make it easy to design a bad database. If you are developing a new application, you should spend a significant amount of time on design. Most developers simply throw together database tables without giving any thought to key design issues like normalization, extensibility, and scalability.

Creating Web Pages with Visual InterDev 6.0
      We used Visual InterDev 6.0 to build our initial Web site and ASP pages. If you’ve never used Visual InterDev, you owe it to yourself to find out more about it. We recommend the introductory article by Ken Spencer that appeared in this magazine earlier this year (see "Visual InterDev 6.0,"; MIND, May 1998). Ken does a good job of explaining the ins and outs of designing a Web site using Visual InterDev 6.0.
      The Visual InterDev project wizard outlines the steps required to create a Web site, including a site theme and layout style. One of our favorite features is the Site Diagram. A way to create the structure for your site quickly, it works in conjunction with the FrontPage NavBar (a server-side bot that is installed with the FrontPage server extensions). When you use the Site Diagram to build an ASP page, Visual InterDev adds the PageNavbar design-time control to the page, which in turn generates the script needed to integrate it seamlessly with the FrontPage VINavBar component. This component runs on the server and generates the navigation HTML for your Web page whenever a browser requests it.
      We like the PageNavbar design-time control because it adds a consistent, well-understood navigation metaphor to each page without requiring a mess of custom JavaScript. When we designed our own company’s Web site (http://www.codemarine.com), we decided to display a navigation column at the left of each page, but we didn’t have Visual InterDev 6.0 back then. To make the site work correctly—especially the must-have feature that makes the headings change color whenever the mouse passes over them—we had to put slightly modified copies of messy JavaScript on every page. As a result, our site has been difficult to update and expand because each page has its own code (see Figure 5). If we had used Visual InterDev, we would have been able to use the PageNavBar and Site Diagram and we’d have a better site.

Figure 5: Manually Generated Navigation Bar Figure 5: Manually Generated Navigation Bar
Figure 5: Manually Generated Navigation Bar


      We developed the knowledge base application using the VINavBar component for its navbar. We get the same features as on our own site, but we didn’t have to write any code! We used the PageNavBar and Site Diagram components to quickly lay out a site containing a home page and three branches—one for each knowledge base area (see Figure 6). Figure 6: Using PageNavBar and Site Diagram
Figure 6: Using PageNavBar and Site Diagram
Figure 6: Using PageNavBar and Site Diagram


      If you want to use the NavBar component in your own Web applications, you need to make sure you’ve installed the FrontPage server extensions properly. If you don’t, you’ll see the less than informative message "[FrontPage vinavbar Component]" in your browser where the navigation bar should appear. Fortunately, you can resolve this problem by running the Visual Studio setup program and selecting the Server Application option, which launches the BackOffice® Installation Wizard. After installing the FrontPage server extensions, remember to reboot and refresh the project links.

Database Access Then and Now
      We used Visual Basic 6.0 Enterprise Edition to develop the propeller component and were pleasantly surprised at how easy it was. Although we’re not Visual Basic programmers at heart, we’ve followed the evolution of Visual Basic and its database support over the years. As you may recall, Visual Basic was originally developed to make writing Windows-based applications easy. Unfortunately, even though Visual Basic was a revolutionary product for rapidly developing user interfaces, built-in support for databases was not one of the product’s strong points.
      In the spring of 1993, during the era of Visual Basic 2.0, many developers used a product called MultiLink-VB, a set of VBXs—smile if you remember those—for working with relational databases. This was before ODBC had gained the popularity it enjoys today, of course, but there are still companies that use MultiLink-VB for the 16-bit applications they maintain. If you’re a veteran of programming with Visual Basic, chances are good that you have used MultiLink-VB at one time or another because it was one of the only tools around for importing relational data into programs built with Visual Basic 2.0. MultiLink was largely successful because it gave developers three things: controls with which to connect to a relational database, data-bound widgets, and a simple programming model for working with relational data.
      Eventually Microsoft realized that programmers working with Visual Basic wanted easy access to data. In Visual Basic 3.0, Microsoft introduced the Jet data control, data-bound widgets, and the Data Access Objects (DAO). This level of database support was a huge leap forward, but its usage model encouraged some programmers to resort to hacks like querying data into invisible controls. For many developers, working with DAO wasn’t as easy as it was meant to be.
      Furthermore, Jet 1.1 imposed significant performance penalties when working with database servers because of the required round-trips through the Jet engine. To address performance issues, Visual Basic 4.0 introduced Remote Data Objects (RDO), a thin layer of objects atop the ODBC API. RDO answered the call for better performance and shielded developers from the complexities of the ODBC API. Jet, DAO, and RDO have continued their evolution since then.
      By the time Visual Basic 5.0 was released, COM components were finally becoming widespread. Taking advantage of the benefits of COM, Microsoft introduced the notion of Universal Data Access (UDA)—a consistent model for accessing data across multiple languages and data sources. The UDA poster child was ADO, a COM-based object model that provides consistent, easy access to data across all COM-compliant programming languages. Although ADO evolved from frameworks like DAO and RDO, it has several features that make it an attractive choice. First, because it’s a collection of COM objects, it is tool-independent. Second, it is not as complex as DAO and has a simpler—and flatter—object model. Third, unlike RDO, which relies heavily on the ODBC API, ADO treats all data sources polymorphically. It simply requires that data providers implement a well-defined set of interfaces (OLE DB) without regard to their underlying implementation.
      Using ADO you can get data from any source that implements OLE DB, including email software, spreadsheets, and word processors. ADO is still evolving. It still lacks some of the advanced capabilities of RDO and DAO, but Microsoft is continually adding to its feature set. (Version 2.0, which ships as a component of Visual Studio 6.0, has pulled virtually even with RDO.) For most applications—especially distributed applications composed of several small components written in different environments—we recommend ADO over any other data access framework. For a thorough explanation of UDA and ADO, visit the Universal Data Access Web site at http://www.microsoft.com/data.

Using Visual Basic 6.0 and ADO
      One of the nicest productivity features in Visual Studio 6.0 Enterprise Edition is the Visual Basic 6.0 Data Environment Designer. With the Data Environment Designer we were able to effortlessly create sophisticated wrapper objects to get at our data. Just because the Designer is easy doesn’t mean it’s not powerful. It allows you to quickly build complex SQL statements and stored procedures. You can even hierarchically build complex Data Command objects for your project. If you are developing complex database applications, we think you’ll be pleasantly surprised at how easy it is to design databases and manipulate data using Visual Basic 6.0 Enterprise Edition.
      We used Visual Basic 6.0 to create the knowledge base Propeller component—an ActiveX DLL (COM server) named VBWebKB.PropellerArticles. Like the Wing and Engine components, the Propeller COM object exposes an IDispatch-derived interface containing two methods: GetArticleList and GetArticle. The former simply outputs a list of articles available from the propeller_table database table. The latter retrieves the details of an individual article.
      To create the database access necessary for these components, we did almost everything visually using the Data Environment Designer. First, we added a data environment called DataEnvironment1. To that we added a connection called Connection1. In the properties of the connection we chose our WebKB data source name, then we added the two commands shown in Figure 7: cmdGetArticleList, which retrieves a recordset using a regular SQL query, and cmdGetArticle, which gets its recordset using a custom stored procedure called spGetArticle.

Figure 7: Data Environment Designer
Figure 7: Data Environment Designer


      After using the Data Environment Designer, the rest of the code for the Propeller object was straightforward and required no embedded SQL statements (see Figure 8). When ASP invokes either of the Propeller object methods, that component simply creates an instance of the DataEnvironment1 object and calls the appropriate command. Then the recordset returned by the command is used as the source of the data passed back to ASP.

Creating Components with Visual J++ 6.0 and WFC
      Visual J++ 6.0 introduces a rich form-based design environment much like the one found in Visual Basic, along with a new extended Java language, a new extended Java virtual machine, and a set of class libraries called the Windows Foundation Classes (WFC). WFC is designed to provide Windows-specific replacements for many traditional cross-platform Java class libraries, while making it easy for developers to exploit key operating system features such as COM, DCOM, MTS, and the myriad Win32 APIs.
      Visual J++ is elegant, simple, and has seamless support for COM. Indeed, the combination of Java and WFC will provide nearly the same power and flexibility enjoyed by C++ developers with a level of simplicity and productivity approaching that of Visual Basic. We built our Wing component with the remarkably solid prerelease version of Visual J++ 6.0 that ships with Visual Studio 6.0. Our understanding is that the final release version will soon be available to all Visual Studio licensees at no extra charge.
      Our Wing component is functionally equivalent to the Propeller component, but there are some minor implementation differences. For database access we used the new WFC package com.ms.wfc.data, a set of classes for working with ADO. Because the Java language doesn’t natively support the variant data type, we used the com.ms and com.ms.com packages for creating the variants expected by the ASP Response object.
      At press time, the WFC documentation for the ADO wrapper classes was still under construction. However, Visual J++ has a data-form wizard that generates all the code necessary for getting data with WFC. With the help of the wizard-generated code and the nifty IntelliSense? technology, we were able to successfully create our Wing component without any additional documentation. Our impression is that WFC is a much-needed framework for developing sophisticated Windows-based applications with Java.
      We like the built-in Visual J++ support for debugging COM objects. On our first attempt to run the Wing component, our code threw an unhandled exception. When we loaded the Wing ASP page, the Java virtual machine displayed a message box asking if we wanted to debug our component. When we said yes, Visual J++ took us right to the offending line. We put in code to catch the exception, and quickly isolated the problem. As it turns out, we had a typo in the data-source connection string. Now that’s productive debugging!
      Visual J++ is great for building COM objects like the Wing component (shown in Figure 9). Visual J++, like Visual Basic, takes care of many of the rote details of COM like registering your components and implementing IDispatch and IUnknown. If you’re willing to trade a little of the control you get with C++ for increased productivity—but you still want to use an elegant programming language—Visual J++ is probably the right COM development tool for the job.

Creating Components with Visual C++ 6.0 and ATL
      The tools we’ve discussed so far—Visual InterDev, Visual Basic, and Visual J++—focus on giving you the power to build complex systems as quickly and as easily as possible. The tradeoff is that making things simpler nearly always means adding layers of runtime support. When size, speed, and low-level control are a top priority, you should consider using Visual C++ 6.0 and ATL.
      One of the new features in ATL is a set of wizards that helps generate the complex code required to work directly with an OLE DB provider. When performance is key, you may prefer to work directly with an OLE DB provider rather than using a layered object model like ADO. To demonstrate this, we developed the Engine component using the Data Access Consumer object provided by the ATL Object Wizard, a new feature introduced with Visual C++ 6.0. Although the Engine component is functionally equivalent to the previously described components, its implementation focuses on high performance and a lean footprint. Instead of using the ADO object model, we used the ATL Object Wizard to create a data consumer object for our control that talks directly to the SQL Server OLE DB ODBC driver. To allow the component to interact with the ASP object model, we used the ActiveX Server Component provided by the ATL Object Wizard.
      Although some of the other Visual Studio tools have recently stolen the spotlight with their glitzy user interfaces and fancy productivity features, Visual C++ 6.0 remains an effective workhorse. We could be wrong, but it is our belief that most off-the-shelf software is still written using Visual C++. As the saying goes, if you want something done right, you have to do it yourself. Visual C++ and ATL give you the complete control to develop COM components that work exactly the way you want them to. Combine that freedom with the productivity enhancements offered by the new IntelliSense and Edit-and-Continue features, and Visual C++ 6.0 is still one of our favorite development tools.

Putting it All Together
      After developing all of the necessary components for our knowledge base, we went back to Visual InterDev and added a couple of lines of script to each top-level page. To invoke the Visual Basic-based component used with the Propeller page, we added the following script:


 <%
 set vbWebkb=Server.CreateObject("VBWebKB.PropellerArticles")
 vbWebkb.GetArticleList Response, "propdetail.asp"
 %> 
Now when we view the site in a browser, the Propeller component generates the appropriate HTML to display the list of knowledge base articles that pertain to propellers. Each entry in the list is represented as a hyperlink to propdetail.asp, with the specific article identifier being passed to the page as a response parameter named oid (for Object ID). This identifier is used by propdetail.asp to get the full text of the article from the component. To make it work, we added these lines of script to propdetail.asp:

 <%
 set vbWebkb=Server.CreateObject("VBWebKB.PropellerArticles")
 vbWebkb.GetArticle Response, Request.QueryString("oid")
 %>
We followed the exact same process for the Wing component and a similar process for the Engine component. The one difference between the Engine component and the others is that we don’t pass it the ASP Response object. Instead, the Engine component retrieves and stores the Response object as a member variable automatically when it is loaded into the ASP environment.

A Word About Web Server Debugging
      When developing ASP-hosted components, you might find that you get sharing violations when trying to do successive debugs and builds. This happens because IIS typically loads your component into the same address space as all of the other IIS services. Instead of immediately unloading each component when its usage count drops to zero, IIS caches it in memory to improve performance. If IIS has loaded your component DLL into memory, your compiler won’t be able to output a new version during your code-build-test cycle.
      The quick and dirty way to work around this is to restart your Web server, thereby flushing all components from the IIS object cache. That approach does the job, but you’ll probably find that you quickly get tired of restarting the Web server every time you rebuild. Another approach is to use the process isolation feature available in IIS 4.0. Process isolation allows you to load your components into a separate process that you can shut down independently of the rest of the Web server. It’s a little work to set up and there are several issues you should be aware of—including security, fault isolation, and performance. You can read about these issues in the Visual Studio documentation in an article titled "Simplifying Development With Process Isolation."

Conclusion
      Due to the rich set of features available in Visual Studio 6.0 Enterprise Edition, we could have used any number of approaches to build our Web-based knowledge base. Our goal was to keep the architecture simple and minimize the amount of ASP script. Our purpose for doing so was twofold. First, we’ve found that encapsulated components are much easier to update, improve, and maintain than large chunks of ASP script. Second, we wanted to position the knowledge base so that it would be poised to take advantage of the resource pooling and transaction support provided by MTS. We felt that a discussion of that technology was beyond the scope of this article, but we encourage you to investigate it. We strongly recommend David Chappell’s article, "How Microsoft Transaction Server Changes the COM Programming Model," that appeared in the January 1998 issue of MSJ.
      Although our knowledge base is a relatively simple example, it demonstrates an effective approach to developing a cross-language, distributed Web app that uses SQL Server, IIS, ASP, and the tools from the Visual Studio family. Our intent was to illustrate that the focus of Visual Studio 6.0 is to make it easy to develop component-based applications that use the Windows DNA architecture. Happy coding!

From the October 1998 issue of Microsoft Interactive Developer.