Resolving the unknown: building custom xmlresolvers in the .net framework

xiaoxiao2021-03-06  108

Click

Here to Download The Code Sample for this Article.

Introduction

There are three great pillars of abstraction in System.Xml in Version 1.1 of the Microsoft .NET Framework for working with XML. The XmlReader class provides an abstraction for streaming-based read, the XmlWriter class provides an abstraction for streaming-based write, and the XPathNavigator provides an abstraction for a cursor-style, read-only random access. However, there is a lesser used forth abstract class called the XmlResolver, which, if you develop XML-aware applications for long enough in .NET, will eventually come To Your Rescue!

The xmlresolver class is described in the msdn documentation as, "Resolves External XML Resources Named by a Uri." HOWEVER, A More Complete Definition Would Be As Follows:

XmlResolvers resolve external data sources that are identified by a URI and then retrieve the data identified by that URI, thereby providing an abstraction for accessing data sources such as files on a file system.

In V1.1 of the .NET Framework there are two XmlResolver implementations The XmlUrlResolver resolves data sources using the file:. // and http: // protocols or any other protocols supported by the System.Web.WebRequest class The XmlUrlResolver is the. default XmlResolver for all classes in the System.Xml namespace and is used to resolve external XML resources such as entities, DTDs, or schemas. It is also used to process include and import elements found in Extensible StyleSheet Language (XSL) stylesheets or XML Schema Definition language (XSD) schemas. Since the XmlUrlResolver is the default XmlResolver for components such as the XmlTextReader, you do not typically have to instantiate one in order to load XML documents.

The XmlSecureResolver was introduced in V1.1 of the .NET Framework and comes into effect when you start to realize that there are several malicious, typically luring attacks when processing and parsing XML on any platform. The W3C XML 1.0 specification was written with little or no regard to security considerations back in the heady pre-security days of 1998. As its name implies, the XmlSecureResolver secures another implementation of an XmlResolver by wrapping the supplied XmlResolver and restricting the resources to which it has access. For instance, the XmlSecureResolver has the ability to prohibit access to particular internet sites or zones. When you construct an XmlSecureResolver, you provide an XmlResolver implementation along with either a URL, some System.Security.Policy.Evidence, or a System.Security.PermissionSet, which is used by The xmlsecureresolver to determine security access. Either a permissionset IS generated or the support one is buy and a permitonly is called on it to secure the access of the underlying XmlResolver.The example below illustrates getting a FileIOPermission to the root of the C:. drive, and then denying access to this permission even though the application could be fully trusted By supplying this permission set to the XmlSecureResolver .

Using system;

Using system.io;

Using system.net;

USING SYSTEM.XML;

Using system.security;

Using system.security.permissions;

Using system.security.policy;

Public Class Test

{

Public static void main ()

{

Try

{

// Create file permission to the c: drivefileiopermission fp = new fileiopermission (fileiopermissionaccess.read, "c: //");

// and the deny the user this fileio permission

fp.deny ();

// and add the file permission to a permission set

Permissionset ps = new permissionSet (permissionstate.none);

Ps.Addpermission (FP);

// now Try to access a file tmp.xml on the c: drive

XMLTextReader Reader = New XMLTextReader (@ "c: /temp/tmp.xml);

// and Secure Access Through The Xmlsecureresolver.

Reader.xmlresolver = New Xmlsecureresolver (New XMLURLRESOLVER (), PS);

// Access the data source

While (Reader.Read ());

Console.writeline ("Successful Read Access");

}

Catch (Exception E)

{

Console.writeline ("Unsuccessful Read Access");

Console.writeline (e);

}

}

}

When the Above Code Is Run The Following Exception Occurs.

Unsuccessful Read Access

System.security.securityException: Request for the Permission of Type

'System.Security.Permissions.fileiOpermission, Mscorlib,

Version = 2.0.3600.0, Culture = neutral, publickeyToken = B77A5C561934E089 'FAILED.

The Action That Failed WAS:

Demand

The Type of The First Permission That Faled WAS:

System.security.permissions.fileiopermission

The First Permission That Failed WAS:

Read = "c: /temp/tmp.xml" />

The Demand Was for:

The Grand Set of the Failing Assembly WAS:

The Refused Set of the Failing Assembly WAS:

Read = "C: /" />

The Method That Caused The Failure WAS:

Void OpenURL ()

Which is the long way of saying this you cannot Access The file c: /temp/tmp.xml Since You do not have fileiopermission.

Under the hood of the xmlresolver

The XmlResolver abstract class has a small API, consisting of two methods called ResolveUri () and GetEntity () along with a Credentials property. The design of all XmlResolvers is that the ResolveUri method is called to return an instance of a System.URI class, and the GetEntity method returns a stream of data from the resolved URI that can then be parsed as XML. This two-stage process provides the abstraction through which a class such as the XmlReader can request XML from data sources other than, say, just the file system, and implement schemes other than those supported in the .NET Framework.Let's look at the XmlUrlResolver as an example of how it operates; this is best illustrated through a Data Flow Diagram (DFD), which shows the interaction of method calls in a numeric sequence.

Figure 1. Data Flow Diagram for the XMlurlResolver Class

The design pattern for a component using the XmlResolver is to first call the ResolveUri method and then, with this resolved URI, retrieve the XML data source as a stream through the GetEntity method In this DFD the XmlUrlResolver differentiates between the file:. // and http: // schemes based on the URI that is supplied to the GetEntity method, and returns either a file stream or stream from the System.Web.WebResponse class DFDs like this are useful for understanding the flow of data and the order of method. calls in a system or component. in order to implement a custom XmlResolver it is simply necessary to decide on the scheme to use and then implement the ResolveUri and GetEntity methods to support the scheme's syntax.

A Custom XMLURLRESOLVER IMPLEMENTATION

With our understanding of how XmlResolvers work we are going to implement a custom XmlResolver that understand two additional schemes The first scheme is the res:. // scheme, which allows you to retrieve embedded XML documents from a named CLR assembly The second scheme is. The DB: // Scheme, Which Allows You to Retrieve XML Documents from a named column in a named Table from a SQL Server Database.accessing XML Embedded in an assemblyMBL

Adding XML documents such as XML schema and XSL stylesheets as embedded resources in an assembly is a great approach when distributing a project, as there are fewer files to copy on installation and you do not need to have different directories to keep data files. Figure 2 shows the books.xml document as an embedded resource in the XmlResolvers project, which is achieved by selecting the Build Action property and choosing the Embedded Resource option in the drop down list.

Figure 2. The books.xml Document Embedded as a resource in a project

The same is also done for the XML schema, books.xsd Now we have to determine a scheme for retrieving these embedded assembly resources The scheme we are going to create is res: // scheme; it has the following syntax...

Res: // ?

For example, to retrieve the books.xml document from the xmlresolvers assembly we would.

Res: // xmlresolvers? books.xml

OR To RETRIEVE The Books.xsd Document From The Filestore Assembly, Which May Be a Separate Assembly from The Project Assembly

RES: // filestore? books.xsd

NOW That We Have Embedded Resources And a Scheme For Retrieving Them, We can Design The Xmlresolver for Accessing Them.

The XmlResourceResolver

We are going to create an XmlResourceResolver class that is able to resolve the res:. // scheme The XmlResourceResolver class is derived from the XmlUrlResolver class This enables us to do the following:. Take advantage of the XmlUrlResolver.ResolveUri () implementation Provide. Default support for the file: // and http: // Schemes.

The code below shows the usware of the xmlresourceresolver.geeTentity Method.

Public Override Object GetEntity (Uri Absoluteuri, String Role, Type OfObjectToreTurn)

{

Stream stream = null;

String Origstring = Absoluteuri.originalString;

INT Schemestart = OrigString.lastIndexof ("//") 2;

INT Start = Origstring.lastIndexof ("/") 1;

Int end = Origstring.indexof ('?');

Console.Writeline ("Attempting to Retrieve: {0}", Absoluteuri;

Switch (absoluteuri.scheme)

{

Case "RES":

// Handled res: // Scheme Requests Against

// a named assembly with Embedded Resources

AskEMBLY Assembly = NULL;

String assemblyfilename = Origstring.substring (start, end - start);

Try

{

IF (String.Compare (Assembly.Getentryassembly (). getName (). Name, assemblyFileName, true) == 0)

{

askMBLY = askEMBLY.GETENTRYASSEMBLY ();

}

// Requested Assembly Is Not Loaded, So loading IT

Else

{

askEMBLY = ask (askMBLYNAME.GETASSEMBLYNAME (AssemblyFileName ");

}

String resourceename = ask resourcefilename "."

Absoluteuri.Query.substring (absoluteuri.query.indexof ('?') 1);

Stream = askMBLY.GETMANIFESTRESOURSTREAM (ResourceName);

}

Catch (Exception E)

{

Console.out.writeline (E.MESSAGE);

}

Return stream;

DEFAULT:

// Handle File: // and http: //

// Requests from the xmlurlresolver base classstream = (stream) Base.GeTentity (Absoluteuri, Role, OfObjectToreturn);

Try

{

IF (CacheStreams)

CacheStream (stream, absoluteuri);

}

Catch (Exception E)

{

Console.out.writeline (E.MESSAGE);

}

Return stream;

}

}

First, the GetEntity method parses the supplied absoluteUri parameter into values ​​taken from the supplied URI. The URI.OriginalString property is used (as opposed to the URI.AbsoluteUri property) since the System.URI class converts the supplied URI into all lower case characters By default, and we need to preserve the case in order to load an embedded resource.

Since we will add further supported schemes to this XmlResourceResolver there is a switch on the scheme type, in this case the "res" string. In the body of the case statement we use the System.Reflection.Assembly class to determine whether the assembly is Already loaded Into memory (as this is the project assembly) by Comparing this to the support.

IF (String.Compare (Assembly.Getentryassembly (). getName (). Name, assemblyFileName, true) == 0)

{

askMBLY = askEMBLY.GETENTRYASSEMBLY ();

}

If it is not already loaded you load the requested assembly, ensuring that you have specified the correct path to find it In the code below the assembly to be loaded is assumed to be in the same directory as the project assembly;. You may want to Add a Different Path, INSTEAD.

Else

{

askEMBLY = ask (askMBLYNAME.GETASSEMBLYNAME (AssemblyFileName ");

}

Once the assembly is loaded, calling the GetManifestResourceStream method conveniently returns a stream to the named embedded resource, which is then returned from the case statement. If this stream is null indicating that the embedded resource can not be found, then the calling component needs to throw an exception.Finally, the default in the switch statement calls the GetEntity method on the XmlUrlResolver base class so that we have a single XmlResolver class that can resolve three schemes: file: //, http: //, and res: //.

Both XML documents and XML schemas can be embedded into an assembly. The following example validates the books.xml document against the books.xsd schema using the XmlResourceResolver to specify the URI for each.

Public static void loadingXmlandschemafromassemblyResource ()

{

XMLTextReader DocReader = New

XMLTextReader (@ "res: // xmlresolvers? Books.xml");

XmlResourceResolver resourceresolver = new xmlresourceReSolver ();

DocReader.xmlresolver = ResourcesResolver;

Xmlschemacollection Schemas = new xmlschemacolection ();

Schemas.validationEventHandler = New

ValidationEventHandler (Schemas_ValidationEventhandler);

XmlTextReader SchemareAder = New

XMLTEXTREADER (@ "res: // xmlresolvers? Books.xsd");

Schemareader.xmlresolver = ResourcesResolver;

Schemas.Add ("BookStore.Books.com", Schemareader;

XMLValidatingReader ValidReader = New XmlvalidatingReader (DocRead);

ValidReader.validationType = validationType.schema;

ValidReader.Schemas.Add (Schemas);

ValidReader.validationEventHndler = New

ValidationEventHandler (ValidReader_ValidationEventHndLer);

While (ValidReader.Read ())

{}

}

Accessing XML Stored in a SQL Server DatabaseWhereas the res: // scheme is very useful in shipping a solution that contains a number of embedded XML documents (it is especially good for XSL stylesheets, for example), it is not very updateable and not ideal for large numbers of documents. As with most data, a better place to store documents is in a database. We can further extend the XmlResourceResolver to support the retrieval of XML documents that are stored in a SQL Server database. We are going to develop solutions .

From a developer perspective, using SQL Server 2005 Express Edition makes for a very convenient and dynamic application-building platform. SQL Server 2005 Express Edition (SQL Server Express) is an easy-to-use version of SQL Server 2005, and is designed for building simple, dynamic applications and, best of all, is free to use and redistribute. It is limited to using a single CPU and up to 1GB RAM, with a 4GB maximum database size. SQL Server Express does not include any of the advanced components Of SQL Server, But It Does Support The XML Data Type, Which Is Ideal For Acting AS A More Scalable Local XML Document Repository. SQL Server 2005 Express Beta 2 Can Be Downloaded Here.

A Typical Scenario Is Storing A Large Number of XML Schemas in Order To Validate XML Documents. New Schemas Can Be Added or Existing One Updated SIMPLY by Changing The Entries In a Database Table.

As previously with the XmlResolver assembly, we need to come up with a scheme to access the XML schemas in the database tables. Here we have to be more careful, since databases are a significant resource and need to be protected. For instance, we could Create a Scheme That Enables You to Provide a SQL Statement Access To The Database Like this.Query: // ? query =

The Following Query Selects The Xmlschema from The xsdschema Table, Wherespace Value IS bookstore.books.com from the xmlschemarepository database.

Query: // xmlschemarepository? query = select xsdschema from xmlschema where namespace = bookstore.books.com

HOWEVER, IN ORDER TO Prevent SQL Injection or Just SQL Attacks, We Are Going to Implement A More Constrained Scheme Called The DB: // Scheme with The Following Syntax,

DB: //

/ ?

WHERE THE OPERATOR Used with the generated sql where clause is always the equals operator using the support value.

.

DB: // xmlschema / xsdschema? bookstore.books.com

By only allowing certain string values ​​for the table and column names, you severely restrict the types of queries that can be generated and make the XmlResourceResolver implementation more secure to potential SQL injection security attacks.

Adding XML Documents Into SQL Server

XML documents can be stored in SQL Server 2000 as a column of type [n] varchar (max) / [n] varbinary (max). We will also look at the ability to store XML documents as the new XML data type that is introduced into SQL Server 2005, which is also supported in the SQL Server 2005 Express Edition. There are advantages and disadvantages to both these storage formats when working with XML documents.We are going to store XML Schemas (XSDs) in a database called xmlschemarepository in a Table Called Xmlschema. The T-Sql To Create this Table is shown bellow.

Create Table Xmlschema (Namespaces NVARCHAR (MAX) Primary Key, Xsdschema Nvarchar (max))

In SQL Server 2005 We can Also Create A Table with an An XML Data Type, Instead Using The Following T-SQL Statement.

Create Table Xmlschemaxmlcol (Namespaces NVARCHAR (MAX) Primary Key, Xsdschema XML)

Of The Following T-SQL STATEMENT for we can.................

INSERT INTO XMLSCHEMA VALUES (N'Bookstore.books.com ','

AttributeformDefault = "unqualified" ElementFormDefault = "Qualified"

Targetnamespace = "BookStore.books.com"

XMLns: xs = "http://www.w3.org/2001/xmlschema">

')

.

Select xsdschema from xmlschema where namespacs = 'bookstore.books.com'or for the xml data type column,

Select xsdschema from xmlschemaxmlcol where namespacs = 'bookstore.books.com'

Now We are ready to retrieve Xml Schemas from the client by extending the xmlresourceresolver to handle our new db: // scheme.

Extending the XmlResourceResolver to support the db: // Scheme

We are going to extend the xmlresourceresolver to becom The xmlschema table. The code below shows how to use the db: // Scheme to load an Xml Schema with a given namespace.

Public static void loadingXmlschemaFromDatabase ()

{

XMLTextReader DocReader = New XMLTextReader (@ "db: // xmlschema / xsdschema? Bookstore.books.com");

XmlResourceResolver resourceresolver = new xmlresourceReSolver ();

ResourceResolver.connectionInfo = ConnectionInfo;

DocReader.xmlresolver = ResourcesResolver;

While (DocReader.Read ())

{

IF (DocReader.IstartElement ("XS: Schema"))

{

DocReader.MovetoAttribute ("TargetNameSpace");

Console.writeline ("Retreived Schema with TargetNamespace: {0}",

DocReader.Value);

}

}

}

In Order to Achieve this, The Following Code Was Added to The Switch Statement In The XmlResourcesResolver Class.

Case "DB":

// Handled DB: // Scheme Requests Against A KNown Database

SqlDataReader DataReader = NULL;

MemoryStream Xmlstream = NULL;

String cmdtext = string.empty;

SQLCommand CMD;

String Tablename = OrigString.substring (Schemestart, Start - (Schemestart 1));

String columnname = Origstring.substring (start, end - start);

// Get the XML Schema Namespace

String name = absoluteuri.query.substring (absoluteuri.query.indexof ('?') 1); using (SqlConnection Connection = New SqlConnection))

{

Try

{

// security check on the allowed table names

// in Order to Prevent Any SQL Injection Attacks

Switch (TableName)

{

// Switch On XML Documents Stored in SQL Server 2000

Case "Xmlschema":

// security check on the allowed column names

Switch (columnname)

{

Case "xsdschema":

CMDText = @ "SELECT" ColumnName "from" Tablename "Where namespaces = @Name";

Break;

DEFAULT:

Throw New SecurityException ("Security SQL Injection: Invalid Column Name Used);

}

CMD = New SQLCOMMAND (CMDText, Connection);

Cmd.Parameters.Add (New Sqlparameter ("@ Name", Name)

Console.writeline (cmd.commandtext);

Connection.open ();

DataReader = cmd.executeReader ();

While (DataReader.Read ())

{

// Return A Memory Stream

UTF8ENCODING Uniencoding = new utf8encoding ();

Byte [] XMLBuffer =

Uniencoding.getbytes (DataReader [ColumnName] .tostring ());

Xmlstream = New MemoryStream (XMLBuffer, 0,

XMLBuffer.Length;

}

Break;

// Switch On XML Documents Stored in SQL Server 2005

Case "XMLschemaxmlcol":

// security check on the allowed column names

Switch (columnname)

{

Case "xsdschema":

CMDText = @ "SELECT" ColumnName "from" TableName

"Where namespaces = @name";

Break;

DEFAULT:

Throw New SecurityException ("Security SQL Injection:

Invalid Column Name Used ");

}

CMD = New SQLCOMMAND (CMDText, Connection);

Cmd.Parameters.Add (New Sqlparameter); console.writeline (cmd.commandtext);

Connection.open ();

DataReader = cmd.executeReader ();

While (DataReader.Read ())

{

// Return A Memory Stream

Console.writeline (DataReader [ColumnName] .tostring ());

SQLXML XML = DataReader.getsqlxml (0);

XMLStream = New

MemoryStream (DataReader [ColumnName] .tostring (). Length);

XmlTextWriter Writer = New XMLTextWriter (XMLStream,

Encoding.unicode);

Writer.writenode (Xml.createReader (), FALSE);

// flush the xmlwriter to the stream and close it.

Writer.flush ();

// set the position to the beginning of the stream.

XMLStream.seek (0, seekorigin.begin);

}

Break;

DEFAULT:

Throw new securityException ("Security SQL Injection: Invalid

COLUMN Name Used ");

}

}

Catch (Exception E)

{

Console.out.writeline (E.MESSAGE);

}

Finally

{

// Close Data Reader Object.

// the database connection closed by Going Out of Scope with "Using" Keyword

IF (DataReader! = NULL)

DataReader.Close ();

}

}

Return XMLStream;

.........................

Some benefits to storing the xml schema as an [n] varchar (max) or an [n] varbinary (max) include The Following:

This approach provides textual fidelity for XML documents when used to store XML. This is a requirement for applications that deal with legal documents such as insurance documents. It does not depend on XML support that is offered by the database and can be extended to support multiple database servers. It uses the processing power of the client system, thereby reducing the load on the server. By performing CPU-intensive XML processing on the middle-tier, the server is relieved of some load and is available for other important tasks. It Offers The Best Possible Performance for XML Document Level Insertion And Retrieval; That IS, Parts of Documents Cannot Be Retrieved Or Updated.Some Be Retrieved Or Updated.Some Benefits of Storing The XML Schema As an an XML Data Type Are:

You can offer significantly better querying capabilities using the W3C XQuery language, with the ability to perform fine-grained queries and to modify operations on XML data. XML documents stored as [n] varchar (max) in the database do not offer fine-grained updates, inserts, or deletes on an XML document. It is a simple and straightforward way of storing your XML data at the server while preserving document order and document structure. It offers the ability to create indexes on XML data type columns for significantly faster query -processing. it offs the ability to easily enforce XML Schema Validation and continraints on the xml data.

In Order to Load The XML Schema from The XML Data Type Xmlschemaxmlcol Table, IT IS SIMPLY A Matter of Amending The Uri As Shown In The Code Below.

XMLTextReader DocReader = New XMLTextReader (@ "db: // xmlschemaxmlcol / xsdschema? Bookstore.books.com");

Using this XmlResourceResolver class, XML documents and XML schemas can be embedded either into an assembly or a database. The following example validates the books.xml document that is embedded in the XmlResolvers assembly against the bookstore.books.com XML schema that is retrieved from A SQL Server Database.public static void loadingXMLFROMAMAMBLYRESOSCHEMAFROMDATABASE ()

{

XMLTextReader DocReader = New XMLTextReader (@ "res: // xmlresolvers? Books.xml");

XmlResourceResolver resourceresolver = new xmlresourceReSolver ();

DocReader.xmlresolver = ResourcesResolver;

ResourceResolver.connectionInfo = ConnectionInfo;

Xmlschemacollection Schemas = new xmlschemacolection ();

Schemas.validationEventHandler = New ValidationEventHandler (Schemas_ValidationEventHandler);

XMLTextReader Schemareader = New XMLTextReader (@ "db: // xmlschema / xsdschema? Bookstore.books.com");

Schemareader.xmlresolver = ResourcesResolver;

Schemas.Add ("BookStore.Books.com", Schemareader;

XMLValidatingReader ValidReader = New XmlvalidatingReader (DocRead);

ValidReader.validationType = validationType.schema;

ValidReader.Schemas.Add (Schemas);

ValidReader.validationEventHandler = New ValidationEventHndler (ValidReader_ValidationEventHandler);

While (ValidReader.Read ())

{}

}

Adding Local file system caching

A final feature we are going to add to this XmlResourceResolver is the ability to perform local file caching for http:.. // requests This is achieved with a hashtable of absolute URIs and retrieves a previously stored file, if there is one This caching approach is straightforward and does not provide an aging mechanism to the files, which I will leave as an exercise for you, the reader, to add just like your school days.The code below shows the CacheStream function, which takes a stream and an absolute URI as input, creates a local file, and then stores the path to the local file with the absolute URI as the key In this way remote http:. // requests such as for DTD or XML schemas found on the internet can be automatically stored locally On The First Access.

Private FileStream CacheStream (Stream InputStream, Uri Absoluteuteuri)

{

// The path and filename what the cached stream will be stored to.

String path = absoluteuri.absolutepath;

INT i = path.lastIndexof ("/");

IF (i> 0) Path = path.substring (i 1);

Path = cachelocation path;

Console.writeline ("CACHING FILE:" PATH);

Console.writeLine ();

// Create a new stream representing the file to be written to,

// and write the stream cache the stream

// from the extel location to the file.

FILESTREAM FILESTREAM = New FileStream (path, filemode.openorcreate,

FileAccess.write, fileshare.none;

StreamReader Sread = New StreamReader (InputStream);

StreamWriter Swrite = New StreamWriter (fileStream);

SWRITE.WRITE (SREAD.READTOEND ());

// add the information about the cached uri to the hashtable.

UriTable.Add (Absoluteuri.absoluteuri, PATH);

// Close Any Open streams.

Swrite.close ();

Sread.Close ();

Return New FileStream (Path, Filemode.open, FileAccess.Read, Fileshare.Read);

. For example, the W3C XML schema for schema contains two DTD references Run the code shown below, and then look in the local directory C:. / FileCache / and examine what local files have been downloaded and stored You will be surprised to find a couple of DTDs, each of which required the use of the XmlResolver to download. Going through the code in the debugger is a great way to see the XmlResolver class in action, during which it finds resource references that need further resolution.

Public static void loadingXMLFromNetworkAndcache ()

{

XmlTextReader docreader = new xmltextReader (@ "http://www.w3.org/2001/xmlschema.xsd");

XmlResourceResolver resourceresolver = new xmlresourceReSolver ();

ResourcesResolver.cachelocation = @ "c: / filecache /";

ResourcesReSolver.cancachestreams = true;

DocReader.xmlresolver = ResourcesResolver;

While (DocReader.Read ())

{

}

// read the Same Xml Document and this time the xml Document is Read

// from the file cache.

XMLTextReader DocReader2 = new xmltextReader (@ "http://www.w3.org/2001/xmlschema.xsd");

DocReader2.xmlresolver = ResourcesResolver;

While (DocReader2.read ())

{

}

}

You Can Also Wrap The XmlResourceResolver in AN Xmlsecureresolver in Order To Limit, for Example, Which Internet Sites can be accessed.

A Dynamic XMLResolver Implementation

Although the XmlResourceResolver provides support for several schemes, there may be times when you want to have a more dynamic behavior where, for example, a local configuration file determines which schemes are supported by which XmlResolver. In these cases it is useful to have a dynamic .

Class XMLDynamicResolver: XmlResolver

{

Hashtable resolvercollection = new hashtable ();

Public Void Add (String Scheme, XmlResolver Resolver)

{

ResolverCollection.Add (Scheme, Resolver);

}

Public override system.net.icredentials Credentials

{

Set {throw new global :: system.notsupportedException ();

}

Public Override Object GetEntity (Uri Absoluteuri, String Role, Type OfObjectToreTurn)

{

Console.Writeline ("Attempting to Retrieve: {0}", Absoluteuri;

Xmlresolver resolver = (xmlresolver) resolvercollection [absoluteuri.scheme];

Return Resolver.geeTentity (Absoluteuri, Role, OfObjectToreTurn);

}

Public Override Uri Resolveuri (Uri Baseuri, String Relativeuri)

{

URI Actualuri = Baseuri;

IF (actualuri == null)

Actualuri = New URI (TRUE, RELATIVEURI);

Xmlresolver resolver = (xmlresolver) resolvercollection [actualuri.scheme];

Return Resolver.Resolveuri (Baseuri, Relativeuri);

}

}

To use this XmlDynamicResolver you add an instance of the XmlResolver for the given scheme. The example below shows the addition of the XmlResourceResolver for the "db" and "res" schemes, and the XmlUrlResolver for the "http" and "file" schemes. "Yes," the XmlResourceResolver can in fact handle all four of these schemes, so this is a somewhat contrived example;. it does illustrate the class, however Note that in this case the XmlDynamicResolver is derived from the XmlResolver abstract class.public static void LoadxmlwithdyNamicResolver ()

{

// Register Schemes with the Dynamic XMLResolver

XMLDynamicResolver DynamicResolver = new xmldynamicResolver ();

DynamicResolver.Add ("DB", New XmlResourceResolver ());

DynamicResolver.Add ("res", new xmlresourceresolver ());

DynamicResolver.Add ("File", New XMLURLRESOLVER ());

DynamicResolver.Add ("http", new xmlurlverse ());

XMLTextReader DocReader = New XMLTextReader (@ "res: // xmlresolvers? Books.xml");

DocReader.xmlresolver = DynamicResolver;

While (DocReader.Read ())

{

IF (DocReader.IstartElement ("price"))

Console.writeline ("Book Price" DocReader.Readinnerxml ());

}

}

Conclusion

This article has provided an in-depth review of the versatile XmlResolver class. XmlResolvers resolve external data sources identified by a URI and then retrieve the data identified by that URI, and so provide an abstraction for accessing data sources such as files on a file system . System.Xml in the .NET Framework provides two implementations of the XmlResolver: the XmlUrlResolver for file: // and http: // requests, and the XmlSecureResolver for limiting access to specified resources.The beauty of the XmlResolver is that you can build them to retrieve XML from anywhere;.. all you need to do is return a stream in this article we walked through XmlResolver implementations that pull XML documents that are embedded in a CLR assembly or are stored in a SQL Server database If you want to see TWO More Examples of Xmlresolvers, Chris Lovett Describes An Xmlaspresolver for Resolving Files Store in Microsoft ASP.NET Virtual Directories and an Alternative Implementation of An XmlcachingResolver TH at performs in memory caching rather that local file caching. All interesting XML projects create some form of XmlResolver and it would be good to hear about your implementations. Send an e-mail message describing them to mfussell@microsoft.com. ¡ Viva La XmlResolver!

转载请注明原文地址:https://www.9cbs.com/read-103928.html

New Post(0)
CopyRight © 2020 All Rights Reserved
Processed: 0.055, SQL: 9