Handling a New Extension The XmlHandler Example


Handling a New Extension ”The XmlHandler Example

In this section, we'll show you how to create an HTTP handler to handle an extension that isn't handled by ASP.NET in its default configuration. The sample we will implement is named XmlHandler . This example handles the .xml extension and enables you to optionally run an XSL transform before the XML data is returned to the browser. Once this handler is implemented and registered within an application, it will be invoked to handle requests to all .xml files within that application.

An .ashx file can handle only requests to itself. On the other hand, the XmlHandler needs to handle requests for all .xml files. Therefore, this handler cannot be implemented inside an .ashx file. Instead, XmlHandler is implemented in a code file and precompiled into an assembly that is placed into the application's bin directory. The handler class is then associated with the .xml extension in the application's web.config file.

Listing 19-2 shows the code for XmlHandler . This code is compiled into the MSPress.ServerComponents assembly.

Listing 19-2 XmlHandler.cs
 usingSystem; usingSystem.IO; usingSystem.Web; usingSystem.Web.Caching; usingSystem.Xml; usingSystem.Xml.XPath; usingSystem.Xml.Xsl; namespaceMSPress.ServerComponents{ //XmlViewerallowsviewingofXMLfilesontheserveralongwith //acustomizedtransformusinganXSLstylesheet. publicsealedclassXmlHandler:IHttpHandler{ publicboolIsReusable{ get{returntrue;} } //Retrievesthecontentsofafile. privatestring GetFileContents(HttpContextcontext,stringfilePath){ stringcacheKey="XmlHandler."+filePath.ToLower(); //Firstlookitupincache. stringcontent=(string)context.Cache[cacheKey]; 
 if((content==null)&&File.Exists(filePath)){ FileStreamstream=null; try{ //Readinthefilebecauseitwasn'tfoundin //thecache. stream=newFileStream(filePath,FileMode.Open, FileAccess.Read,FileShare.Read); StreamReaderreader=newStreamReader(stream); content=reader.ReadToEnd(); reader.Close(); //Storeitintocacheforfutureuse,and //associateitwithafiledependencysothat //thecacheisfreedifthefileischanged. context.Cache.Insert(cacheKey,content, newCacheDependency(filePath)); } catch{ } finally{ if(stream!=null){ stream.Close(); stream=null; } } } returncontent; } //Handlestherequestandgeneratestheresultingresponse. publicvoidProcessRequest(HttpContextcontext){ //Thestandardrequest/responseobjects. HttpRequestrequest=context.Request; HttpResponseresponse=context.Response; //Getthepathtothe.xmlfilethatisbeingrequested //andloaditscontent. stringxmlFile=request.PhysicalPath; stringxmlContent=GetFileContents(context,xmlFile); if(xmlContent==null){ thrownewHttpException(404,"NotFound"); } //ExtractthenameoftheoptionalXSLtransformtobe //appliedtotransformtheXMLdataintoHTML. stringxslFile=request.QueryString["xsl"]; 
 if((xslFile!=null)&&(xslFile.Length!=0)){ //StartwritingouttheresponseHTML. response.ContentType="text/html"; //Loadupthe.xmland.xslfiles,performthe //transform,andwriteoutthetransformeddata. xslFile=request.MapPath(xslFile); stringxslContent=GetFileContents(context,xslFile); if(xslContent==null){ thrownewHttpException(404,"NotFound"); } XslTransformxsl=newXslTransform(); xsl.Load(newXmlTextReader(newStringReader(xslContent))); XPathDocumentxmlData= newXPathDocument(newStringReader(xmlContent)); xsl.Transform(xmlData,null,response.Output); } else{ //RenderouttheXMLdirectly. response.ContentType="text/xml"; response.Write(xmlContent); } } } } 

The XmlHandler can be used in one of two ways. When an .xml file is requested along with an xsl argument in the request URL (as shown later in this section), the XML content is transformed by using the specified XSL transform on the server and the resulting HTML content is returned as the response so that it can be displayed in a browser. In this case, the handler specifies the ContentType property of the response as "text/html" . The handler uses functionality provided by the classes in the System.Xml.Xsl.XslTransform and System.Xml.XPath.XPath ­Document namespaces in the .NET Framework to perform the transformation. When an .xml file is requested by itself, the handler sets the ContentType to "text/xml" and writes out the contents of the .xml file directly.

This example also demonstrates how an HTTP handler can retrieve the physical path of the file being requested via the PhysicalPath property of the HttpRequest object retrieved from the HttpContext instance that is provided to the handler. The implementation uses the MapPath method of the HttpRequest object to determine the physical path of the .xsl file passed in as an argument. It is important to use this method instead of directly using the argument as the full file path. The MapPath method ensures that the specified .xsl file is located within the application. This method prevents access to files outside the application (such as system files) by throwing an exception because doing so would create a security hole in the handler.

The XmlHandler example also demonstrates using the ASP.NET cache to improve performance. The GetFileContents method in Listing 19-2 first attempts to retrieve the cached content. When this content is not found, the implementation reads in the file contents by opening it and stores the contents in the cache, thereby improving performance in a subsequent request. In addition, the cache entry is associated with a file dependency so that the cached file contents are automatically removed from the cache if the file is changed on the disk. In general, an HTTP handler should never perform file access during each request ”it should use the caching functionality built into ASP.NET to improve performance when appropriate.

Because this handler is not implemented by using an .ashx file, you need to add the appropriate mapping to the application's web.config file so that the HTTP runtime can locate and route requests for .xml files to this handler. The following fragment from the web.config file shows the relevant portions that create this mapping between all .xml files and the handler implementation:

 <configuration> <system.web> <httpHandlers> <addverb="*"path="*.xml" type="MSPress.ServerComponents.XmlHandler, MSPress.ServerComponents"/> </httpHandlers>. </system.web> </configuration> 

There is one final step you need to perform before you can use the handler. IIS stores information about each application in its metabase. The script map of an application stored in the metabase needs to be updated to include an entry that specifies .xml as another file type handled by ASP.NET. This script map entry is similar to the mapping that exists for .aspx files. You can perform this update manually by using the IIS administration tool, as shown in the Figure 19-2.

Figure 19-2. IIS administration user interface for adding a script map entry

graphics/f19hn02.jpg

You can also make the same settings programmatically. Consider providing a setup script with your HTTP handler if you plan to deploy it widely. The VBScript code in Listing 19-3 uses IIS Active Directory objects to add mapping for the .xml extension by copying the entry for .aspx files in the BookWeb application.

Listing 19-3 AddXmlMapping.vbs
 DimiisObject SetiisObject=GetObject("IIS://localhost/w3svc/1/root/BookWeb") AddXmlMapping() SubAddXmlMapping() DimscriptMapsObject DimxmlMapping DimnewMappings DimmappingCount Dimi mappingCount=0 scriptMapsObject=iisObject.Get("ScriptMaps") ForEachmappingInscriptMapsObject mappingCount=mappingCount+1 
 If(Left(mapping,5)=".aspx")Then xmlMapping=".xml"+Right(mapping,Len(mapping)-5) mappingCount=mappingCount+1 EndIf Next ReDimnewMappings(mappingCount-1) i=0 ForEachmappingInscriptMapsObject newMappings(i)=mapping i=i+1 Next newMappings(mappingCount-1)=xmlMapping iisObject.Put"ScriptMaps",newMappings iisObject.SetInfo WScript.Echo".xmladdedtoscriptmap" EndSub 

Listings 19-4 and 19-5 show the .xml and .xsl files used as sample files. Figure 19-3 shows the HTML resulting from the XSL transformation.

Listing 19-4 MarketData.xml
 <?xmlversion="1.0"encoding="utf-8"?> <marketDatadate="11/03/2001"> <indexname="Dow"> <value>9323.54</value> <change>59.64</change> </index> <indexname="NASDAQ"> <value>1745.73</value> <change>-0.57</change> </index> <indexname="S&amp;P"> <value>1087.22</value> <change>3.12</change> </index> </marketData> 
Listing 19-5 MarketData.xsl
 <?xmlversion="1.0"encoding="utf-8"?> <xsl:stylesheetversion="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:templatematch="/"> <html> <body> <xsl:apply-templates/> </body> </html> </xsl:template> <xsl:templatematch="marketData"> <tablestyle="font-family:verdana;font-size:8pt"> <tr> <tdcolspan="3">MarketDatafor<xsl:value-ofselect="@date"/></td> </tr> <trstyle="font-weight:bold"> <td>Index</td> <td>Value</td> <td>Change</td> </tr> <xsl:apply-templates/> </table> </xsl:template> <xsl:templatematch="marketData/index"> <tr> <td><xsl:value-ofselect="@name"/></td> <td><xsl:value-ofselect="value"/></td> <td> <xsl:iftest="change&lt;0"> <xsl:attributename="style"> <xsl:text>color:red</xsl:text> </xsl:attribute> </xsl:if> <xsl:iftest="change&gt;0"> <xsl:attributename="style"> <xsl:text>color:green</xsl:text> </xsl:attribute> </xsl:if> <xsl:value-ofselect="change"/> </td> </tr> </xsl:template> </xsl:stylesheet> 
Figure 19-3. HTML resulting from the XSL transformation by making a request to MarketData.xml

graphics/f19hn03.jpg



Developing Microsoft ASP. NET Server Controls and Components
Developing Microsoft ASP.NET Server Controls and Components (Pro-Developer)
ISBN: 0735615829
EAN: 2147483647
Year: 2005
Pages: 183

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net