|
Introduction
This second article in a two-part series will further explain how simple it is
to set up custom Web controls in the new Microsoft .NET platform to consume an XML Web service. (See Part I at http://www.15seconds.com/Issue/020117.htm.) I will show you how to get data returned from an eXtensible Markup Language (XML) Web service and transform that data using XSL transformations (XSLT) into HTML.
download source code
view demo
Step 1: Choosing the Service and Planning the Flow
For this article I've chosen to show how to query Santra.com's replication of the Web service based on the Microsoft Knowledge Base (see http://www.mysantra.com/MyService_Details.asp?service_id=372). Let's examine this service more closely. Most Web services developed using the .NET Framework have an HTTP port for GET and POST, meaning that you can explore and test the Web service in a normal browser window. In the service profile, click on the link to the "Port Address." This will bring you to the HTTP interface to the Web service.
For this service we see that there are three methods exposed:
- KBFullList
Retrieve full knowledge base (KB) information given a single KB ID
- KBSearch
Search KB content
- KBTitle
Retrieve KB Title
With the two methods KBSearch and KBFullList, you see that we can send the Web service a query ("KBSearch") that will list the titles that match, and allow for the end user to drill down and view the entire contents (KBFullList) of the specific item.
Step 2: Setting Up the Environment
Creating controls is such an easy task that I chose not to use the Visual Studio.NET development environment, but to use a simple text editor, instead. You will need two core files for this project, the actual source file for the control (mskb.cs) and a test page for the control (index.aspx).
Here's more detail about what this control will do exactly. When the control is first rendered, we will simply show a search form where the user can enter a query. Once a search has been initiated, we will show a list of links that match the criteria specified. And then, after a link has been chosen, that will take the users to the full listing of the KB item. We keep the search form a static item at the top of the page at all times.
First, we need to create a Proxy class for the Web service. For this, we use the tool provided within .NET Framework, , "wsdl.exe", and the WSDL end point of the service we found earlier on Santra's Service Details page.
wsdl.exe /namespace:MSKB_Proxy http://rob.santra.com/webservices/public/mskb/index.asmx?wsdl
This command will create the MSKBSearch.cs file in my current directory. Open this up, and take a quick look. In this file, we will need to pay attention to two important details, the namespace and the class name. Take some time now to have a quick look through this file.
namespace MSKB_Proxy {
public class MSKB : System.Web.Services.Protocols.SoapHttpClientProtocol {
In order to use that specific class in our control, we will need to create an object of type "MSKB_Proxy.MSKB". Compile this Proxy class and ensure that it is available for our application by placing the library in the bin directory off of our Web root. (My current directory is C:\Inetpub\wwwroot\UserControl\MSKB.)
csc /t:library /out:../../bin/MSKB_Proxy.dll MSKBSearch.cs
Step 3: Creating the Control
We begin by coding the basics for the control. This is done in a few quick steps:
- Import the few namespaces that we will need, including our MSKB_Proxy namespace that we discovered in the Proxy file we created earlier.
- Create our Control's namespace (arbitrarily named "MSKB").
- Create our Public class with inherits from System.Web.UI.Control.
- Create our Render method, which overrides the Render method in System.Web.UI.Control.
using System;
using System.Web.UI;
using MSKB_Proxy;
namespace MSKB {
public class SearchControl : System.Web.UI.Control {
protected override void Render(HtmlTextWriter output) {
}//end method Render
}//end class SearchControl
}//end namespace MSKB
Now let's create an instance of our Proxy object within the SearchControl class.
MSKB_Proxy.MSKB mskb = new MSKB_Proxy.MSKB();
We will create the two methods to handle the appropriate actions (search and full listing), but in a new class within this same namespace. This is done so the class and the two methods can be reused in other portions of our application.. In other words, we won't be limiting usage of these methods to this specific control. Our first method will take the search criteria and use the Proxy object we created above to execute the Web service query.
//perform search by keywords
public string SearchService(string keywords) {
string[] xmlresults;
string xslDoc;
if (keywords!="") {
xmlresults = new String[5];
xmlresults[0] = "<?xml version=\"1.0\"?><results keywords=\"";
xmlresults[1] = keywords;
xmlresults[2] = "\">";
xmlresults[3] = mskb.KBSearch(keywords);
xmlresults[4] = "</results>";
xslDoc = "c:\\inetpub\\wwwroot\\usercontrol\\mskb\\results.xsl";
return utils.Transform(System.String.Concat(xmlresults), xslDoc);
} else {
return "";
}
}//end method SearchService
The second method will take a KB ID and return the full listing of the KB item that it receives back from the Web service request via the Proxy object.
//show full listing of any KBID
public string ShowFull(string kbid) {
string[] xmlresults;
string xslDoc;
xmlresults = new String[5];
xmlresults[0] = "<?xml version=\"1.0\"?><results kbid=\"";
xmlresults[1] = kbid;
xmlresults[2] = "\">";
xmlresults[3] = mskb.KBFullList(kbid);
xmlresults[4] = "</results>";
xslDoc = "c:\\inetpub\\wwwroot\\usercontrol\\mskb\\fullview.xsl";
return utils.Transform(System.String.Concat(xmlresults), xslDoc);
}//end method ShowFull
The most important thing that you will notice in these two methods is that we are taking the XML result from the Web service (xmlresults[3] = mskb.KBFullList(kbid);), and transforming (return utils.Transform(System.String.Concat(xmlresults), xslDoc);) this into HTML with an XSLT document that I have provided. This allows you to change the interface without having to recompile the object.
Removing the presentation items from the assemblies allows us to distribute this control to other people without having to create a new object each time someone wants to change the layout. This gives control of the layout to the person that is implementing the control, which could be a vital necessity in some distributions.
At last we come to the Render method in our SearchControl class. This is where we will grab the few inputs from the end user coming in over HTTP, and then call either method defined above to render the content using our HtmlTextWriter named output. The Render method is actually initially defined in the class that we inherit, and we are simply overriding it and providing our code for its behavior.
//render the control
protected override void Render(HtmlTextWriter output) {
string[] searchForm;
searchForm = new String[5];
string results="", kbid="", keywords="";
kbid = utils.GetHttpVariable(Page.Request, "kbid", "");
keywords = utils.GetHttpVariable(Page.Request, "keywords", "");
searchForm[0] = "Search the Microsoft Knowledge Base:<br />";
searchForm[1] = "<form action=\"index.aspx\" method=\"post\">";
searchForm[2] = "Search Terms:<input type=\"text\" name=\"keywords\" value=\"" + keywords + "\" />";
searchForm[3] = "<input type=\"hidden\" name=\"kbid\" value=\"\" />";
searchForm[4] = "<input type=\"submit\" name=\"btnSearch\" value=\"Search!\" />";
searchForm[5] = "<br /><hr width=\"100%\" />";
if (kbid!="")
results = search.ShowFull(kbid);
else
results = search.SearchService(keywords);
output.Write(System.String.Concat(searchForm) + results);
}//end method Render
Notice a few references to this RobChartier.Utils (Utils) object. This is a handy library of mine that is in constant development and is included in the download for this project, or to get a more recent copy see http://rob.santra.com/nothingmn/codelibrary/asp.net/utils.cs.txt.
The Utils object's primary function is to simplify some of the redundant tasks that we do, like simple input and validation of HTTP variables, XML-XSLT transformations, HTTP requests, etc.. If you create any new methods that you think should be part of this library, post them to the ASPFriends.com's ASPNGCodeGiveAwaySwap mailing list at http://www.aspfriends.com/aspfriends/aspngcodegiveawayswap.asp.
The utils.cs must also be compiled into utils.dll:
csc /out:../../bin/utils.dll /t:library utils.cs
The last thing we need to do is compile our control.
csc /r:../../bin/MSKB_Proxy.dll /r:../../bin/utils.dll /out:../../bin/MSKBControl.dll /t:library mskb.cs
Let's examine this in more detail.
csc is our C# compiler, part of the .NET Framework
/r:../../bin/MSKB_Proxy.dll is adding a reference to the Proxy library we created.
/r:../../bin/utils.dll is a reference to my utilities library.
/out:../../bin/MSKBControl.dll is instructing the compiler to send the output library to the bin directory off of the Web root of this application.
/t:library indicates that this is a library.
mskb.cs is our source file for the control.
Step 4: Using the Control
The last step in creating any control is testing it. In our index.aspx page we need to add two simple lines:
<%@ Register TagPrefix="MSKB" Namespace="MSKB" Assembly = "MSKBControl" %>
@Register directive is used to associate aliases with namespaces and classes for custom server controls.
TagPrefix is the attribute we used to associate the control with our namespace.
Namespace is the namespace to associate with the TagPrefix.
Assembly is the assembly that the TagPrefix is referring to. Notice that we didn't indicate the extension (.DLL).
<MSKB:SearchControl id="SearchControl" runat="server"/>
MSKB is taken from the TagPrefix indicated in the @Register directive above.
SearchControl is the class name that we want to use in the assembly we compiled above.
runat="server" instructs the ASP.NET page to run this item at the server.
Load up the page in the browser and you should see our default search form that you can use to search the Microsoft Knowledge Base.
Conclusion
In the download package are all the files necessary for creating this control. Take time to review all of the code in the mskb.cs file because you need to understand how all of the namespaces and classes work together in this application. If you have any comments or questions, please feel free to contact me at any time.
About the Author
Robert Chartier has worked in the information technologies field for more than seven years. While studying at college, he began his career working as a software and hardware technician at the college, supporting a user base of thousands of students and hundreds of instructors. Once his college days were finished he moved on to full-time studies at a university in the lower mainland of British Columbia, and landed a full-time job developing large projects for distribution on many platforms, mediums, and languages.
His next position enabled him to tap into the Internet development market on a larger and more focused scale. In his spare time he began writing and producing content for developer-specific sites focusing on Microsoft technologies (ASP, COM/COM+, etc.). He has also been a part of many open forums on cutting-edge technologies, such as the .NET Framework and Web services (SOAP), and has been invited to speak at large developer conferences and contribute to many technical publications.
His next step was to take a position with a large B2B training marketplace, where he developed many tools, including a very comprehensive search engine with custom business rules for weighting, sorting, and analysis (COM+). This led him into strong development with beta versions of Commerce Server 2000 and BizTalk Server 2000. His next opportunity included a large Internet development effort using technologies such as JSP (Java Beans, J2EE), Oracle, WebLogic, etc. His current position as vice president of technology for Santra Technology (http://www.santra.com) has allowed him to focus more time on the Web services market space. Santra is an award-winning, industry leader in this cutting-edge technology, focusing on Web service monitoring, alerting, and performance measurement.
Robert Chartier can be reached at rob@aspfree.com.
|