The Wonderful World of Schemas

[Previous] [Next]

Your first consideration when building an Exchange Server 2000 application is whether you need to use the schema support that's built into the product. As mentioned earlier in the chapter, Exchange Server 2000 allows you to create schemas for your applications—meaning you can define classes of items, such as myproject or mycontact. On those classes of items, you can have default sets of properties, such as myname or mylocation.

You don't have to create schemas in order to use built-in or custom properties on items in Exchange Server 2000. For example, you could append new properties to an item using ADO and store that item in Exchange Server. You'll need to create a custom schema if you want to reuse your properties across multiple items, rather than with a single, one-off item. Also, if you want your users to easily discover your properties, you'll need to use a schema. This discoverability can be achieved through ADO when you run a SQL SELECT statement against your application, or it can be with the Web Storage System forms you create. Since the Training application uses many custom properties across many items, it creates schemas in its setup program. Let's discuss this part of the program now.

Overview of the Exchange Server Schemas

You need to know a few things before you attempt to create schemas. First, Exchange Server 2000 ships with some schemas already in place for the default items it understands, such as messages, documents, appointments, and contacts. The schemas for these items are stored in a hidden folder in your Exchange server. You can view this hidden folder either by writing a simple program or by looking at the folder through the Mdbvue utility. Figure 18-20 shows how to view the Schema folder using MDBVUE.

NOTE
You'll find the Schema folder under the Public Folders tree, in the non-ipm subtree. This folder contains XML files that define the Exchange Server 2000 schemas. Exchange Server 2000 does support defining schema through XML. However, in the setup program for the Training application, I used ADO to create my schema definitions.

click to view at full size.

Figure 18-20. Mdbvue browsing the hidden Schema folder for Exchange Server 2000.

Second, as part of the base Exchange Server schema, there is the idea of a content class. For example, a message has a content class of urn:content-classes:message. Content classes are groupings of properties that define a certain type of item. If you set the content class of a particular item to message, the item receives all the properties from your schema that are associated with the message content class.

If you're coming from the Exchange Server 5.5 development environment, you might be wondering how content class and message class correspond. There really is no explicit relationship between content class and message class; you can have a content class that's entirely independent from a message class. If you need to support Outlook or previous versions of OWA, just be sure to explicitly set both the content class and the message class in your application. Don't worry about the custom properties in your content class. Exchange Server makes those available in the PS_PUBLIC_STRINGS name space in MAPI so that Outlook or any MAPI application can retrieve those custom properties.

NOTE
Outlook supports field names of up to 32 characters in length in its Field Chooser. So if you create a property with a name longer than 32 characters, you might not be able to retrieve it from Outlook.

Creating Custom Content Classes

The first step when creating a custom content class is to decide what to call it. Make sure that the name you select for your content class doesn't clash with other content class definitions. Once you determine the name of your content class, you'll want to think about the properties contained in it. Since Exchange Server supports a wide range of built-in content classes, it allows you to inherit your content class from an existing one. For example, the Training application has training events. These events require properties that already exist on the appointment content class. However, the training events also need some extra properties that will exist on all training event items. Using inheritance, the Training application inherits the properties from both the appointment content class and the item content class.

Exchange Server 2000 supports both single and multiple inheritance for content classes. The following list contains all the default content classes supported by Exchange Server 2000:

  • urn:content-classes:appointment
  • urn:content-classes:calendarfolder
  • urn:content-classes:calendarmessage
  • urn:content-classes:contactfolder
  • urn:content-classes:contentclassdef
  • urn:content-classes:document
  • urn:content-classes:dsn
  • urn:content-classes:folder
  • urn:content-classes:freebusy
  • urn:content-classes:item
  • urn:content-classes:journalfolder
  • urn:content-classes:mailfolder
  • urn:content-classes:mdn
  • urn:content-classes:message
  • urn:content-classes:notefolder
  • urn:content-classes:object
  • urn:content-classes:person
  • urn:content-classes:propertydef
  • urn:content-classes:recallmessage
  • urn:content-classes:recallreport
  • urn:content-classes:taskfolder

Once you figure out which content classes you want to inherit from, you'll need to create some property definitions for your content class. Property definitions describe the name, type, value, and special characteristics of the properties you want in your content class. Be aware that when you do create a property definition, it can be used across multiple content classes. You'll see this in the Training application, where both instructors and training events share survey result property definitions.

Let's look at some code from the setup program that creates the property definitions for a training event. We'll then step through exactly what's happening in the code.

 CreateSchemaPropDef "instructoremail", "string", False, True, _ False, CStr("") CreateSchemaPropDef "prereqs", "string", False, True, False, CStr("") CreateSchemaPropDef "seats", "string", False, True, False, CStr("") CreateSchemaPropDef "authorization", "string", False, True, False, _ CStr("") CreateSchemaPropDef "category", "string", False, True, False, CStr("") CreateSchemaPropDef "surveycount", "string", False, True, False, CStr("") CreateSchemaPropDef "discussionurl", "string", False, True, False, _ CStr("") CreateSchemaPropDef "materialsfilepath", "string", False, True, _ False, CStr("") CreateSchemaPropDef "materialshttppath", "string", False, True, _ False, CStr("") Private Sub CreateSchemaPropDef(strName, strType, bMultiValued, _ bIndexed, bReadOnly, varDefaultValue) Dim rec As New ADODB.Record With rec .Open strAppSchemaFolder & "/" & strName, , adModeReadWrite, _ adCreateNonCollection + adCreateOverwrite 'Create new property definition .Fields("DAV:contentclass") = "urn:content-classes:propertydef" 'Give it a name .Fields("urn:schemas-microsoft-com:xml-data#name").Value = _ strSchema & strName 'Set the data type for the property .Fields("urn:schemas-microsoft-com:datatypes#type").Value = _ strType 'Set the other fields for the property .Fields("urn:schemas-microsoft-com:" & _ "exch-data:ismultivalued").Value = bMultiValued .Fields("urn:schemas-microsoft-com:" & _ "exch-data:isindexed").Value = bIndexed .Fields("urn:schemas-microsoft-com:" & _ "exch-data:isreadonly").Value = bReadOnly .Fields("urn:schemas-microsoft-com:" & _ "exch-data:default").Value = varDefaultValue .Fields.Update .Close End With End Sub 

This code creates a new item for my property definition in the Schema folder for the Training application. My recommendation is that, unless absolutely necessary, you don't modify the built-in schema for Exchange Server 2000. Instead, create a Schema subfolder for your applications, and place your property and content class definitions in it. You can inherit from the built-in schemas in Exchange Server 2000 rather than modifying them.

NOTE
You need to create property definition names in a unique name space. The setup program asks you what name space you want to use. By default, you should include your Internet domain name, if you have one, since it's guaranteed to be unique. For example, a good name space might be http://yourdomainname/schema/. You can then append to that name space the names of the custom properties for your application.

You should also be aware that property names are case sensitive. I recommend lowercasing your entire property name to make your coding easier.

Once the new item is created, the code sets the content class property in the DAV name space to urn:content-classes:propertydef. Exchange Server 2000 defines a number of new name spaces for properties, such as DAV, http://schemas.microsoft.com/exchange/, or urn:schemas-microsoft-com:office:office. The code then sets the urn:schemas-microsoft-com:xml-data#name property to the fully qualified name of the property. Next, the code sets the data type, which can be one of a number of different values. The most common ones that you'll use are String, Float, Boolean, DateTime, i2, i4, i8, Uuid, Int, and Bin.base64. I've used strings throughout the Training application to shield me from changes in the underlying builds of Exchange Server. This is definitely not a best practice; after Exchange Server 2000 is released, I'll update the code to use the correct data type for the properties. You should always use the correct data type depending on the needs of your application.

Once the data type is set, you can set other values for your properties. One such value is the ismultivalued property. By setting this property to True, you tell the Web Storage System that this property supports multiple values of the data type you specified. When working with multivalued properties, you'll want to set and get the values using arrays. Examples of built-in multivalued properties are urn:schemas-microsoft-com:xml-data#element and urn:schemas-microsoft-com:xml-data#extends, which are properties on the content class definition item. We'll discuss creating a content class definition item in a little bit.

Another property you can set is the isindexed property. This property has nothing to do with content indexing (which we'll look at later); instead, it corresponds to the Exchange Server database index. If you set this property to True, Exchange Server will create an index for the property so that sorting, grouping, and other operations on it execute quickly. One caveat for using isindexed: if you are concerned about load on your Exchange server, don't set this property to True for all your properties. Instead, just determine which properties you really need indexing on, and set this property to True for those properties. To create the index for your custom properties, you will have to issue the CREATE INDEX command in ADO. We'll learn more about this command and ADO access to Exchange Server 2000 later in this chapter.

The next property you can set is the isreadonly property. You don't need to set this property because only properties provided by the Web Storage System can be set to read-only. However, I threw this property in here just to expose you to it. You can query the value of this property from your applications to see whether a Web Storage System property is read-only.

The final property that you'll want to set is the default property. This property specifies what the default value, if any, should be for your property when it's created by the application or user. Although you don't have to set this property, you will want to do so in order to initialize your properties to a default value.

Once the code finishes setting these properties using ADO, a call to the Update method of the Fields collection is required. When we talk about ADO support in Exchange Server 2000 later in the chapter, we'll discuss the use of transactions with ADO and Exchange Server. I highly recommend that you use transactions where appropriate in your application. For example, you should use transactions in case you receive an error while processing your ADO commands. This allows you to roll back the transaction rather than leaving your application's data in an inconsistent state. Although the previous code segment doesn't show it, the entire schema creation process is wrapped in a local OLE DB transaction.

Creating Content Class Definition Items

Now that we've created the custom property definitions for our content class, we need to create a content class definition in our schema. To do this, we must create an item in the Schema folder that has the correct content class and properties set so that Exchange Server knows we want to create a custom content class. The following code shows how to create a definition of a custom content class:

 arrTrainingEventProps = BuildSchemaArray(Array("instructoremail", _ "prereqs", "seats", "authorization", "category", "surveycount", _ "discussionurl", "materialsfilepath", "materialshttppath", _ "publiccomments", "overallscore")) CreateContentClass "trainingevent", _ "urn:content-classes:trainingevent", _ Array("urn:content-classes:item", "urn:content-classes:appointment"), _ arrTrainingEventProps Private Function BuildSchemaArray(arrProperties) Dim tmpArray() For i = LBound(arrProperties) To UBound(arrProperties) ReDim Preserve tmpArray(i) tmpArray(i) = strSchema & arrProperties(i) Next BuildSchemaArray = tmpArray End Function Private Sub CreateContentClass(strItemName, strContentClassName, _ arrExtends, arrFields) Dim rec As New ADODB.Record With rec 'Create item in application Schema folder .Open strAppSchemaFolder & "/" & strItemName, , adModeReadWrite, _ adCreateNonCollection + adCreateOverwrite ' 'Create new content class definition ' .Fields("DAV:contentclass") = "urn:content-classes:contentclassdef" 'Name the content class .Fields("urn:schemas-microsoft-com:xml-data#name").Value = _ strContentClassName 'Enter what other content classes this one extends .Fields("urn:schemas-microsoft-com:xml-data#extends").Value = _ arrExtends 'Enter the fields that exist on the content class .Fields("urn:schemas-microsoft-com:xml-data#element") = arrFields 'Save change .Fields.Update .Close End With End Sub 

The code first calls the function BuildSchemaArray to create an array containing the custom schema properties that the new content class will contain. This is an example of how you create values for a multivalued property.

Once the array is built, the code calls the CreateContentClass subroutine, which creates a new item in the Schema folder using ADO. The code sets the content class of the item to urn:content-classes:contentclassdef, which tells Exchange Server that this is a new content class definition item. The code then sets the name of the new content class definition to the name passed to the subroutine. In this example, the content class name is urn:content-class:trainingevent.

The code next sets the extends property. This multivalued string property contains a list of all the other content classes that this content class inherits from. A content class can either have no inheritance or can inherit from one or more content classes. What you want to accomplish in your application and the set of properties you need on your custom content class will dictate which content classes you inherit from. Since the trainingevent content class is so similar to the appointment content class in terms of properties required, the code inherits from the appointment content class. The code also inherits from the item content class, which most other content classes inherit from.

Finally, the code sets the element property. This property is multivalued and should contain all the custom fields that your content class implements. Once this property is set, you can call the Update method on the ADO Fields collection to write the data to Exchange Server.

You can also use XML to create content class definitions and property definitions. If you create a correctly structured XML document and place it into the schema folder for your application, Exchange Server will allow you to use these new content classes and properties. The following example shows what two XML files—one for the content class definition and one for the property definition—look like in XML.

 This XML file would be for the content class definition <?xml version="1.0"?> <Schema name='ExchangeSchema' xmlns="urn:schemas-microsoft-com:xml-data" xmlns:d="DAV:" xmlns:ex="http://schemas.microsoft.com/exchange/" xmlns:cc="urn:content-classes:" xmlns:dt="urn:schemas-microsoft-com:datatypes" xmlns:s="urn:schemas-microsoft-com:exch-data:" xmlns:m="urn:schemas:httpmail:" xmlns:h="urn:schemas:mailheader:" xmlns:cs="http://customschemaname/"> <ElementType name="cs:customprop" d:contentclass="cc:contentclassdef"> <extends type="cc:item"/> <element type="cs:mycustompropname"/> </ElementType> </Schema> This XML file would be for the property definition <?xml version="1.0"?> <Schema name='ExchangeSchema' xmlns="urn:schemas-microsoft-com:xml-data" xmlns:d="DAV:" xmlns:cc="urn:content-classes:" xmlns:dt="urn:schemas-microsoft-com:datatypes" xmlns:s="urn:schemas-microsoft-com:exch-data:" xmlns:m="urn:schemas:httpmail:" xmlns:cs="http://customschemaname/"> <ElementType name="cs:PNAC" dt:type="string" s:ismultivalued="0" d:contentclass="cc:propertydef" s:isindexed="1" s:isreadonly="0" s:isrequired="0" s:isvisible="1"> </ElementType> </Schema> 

Setting the expected-content-class Property

You need to take a few more steps when using custom schemas. First, you must set the property urn:schemas-microsoft-com:exch-data:expected-content-class on the folders for your application. This multivalued property tells Exchange Server what content classes to expect in the folder. This property can specify multiple content classes. The query processor in Exchange Server will use this list of expected content classes when you issue a SELECT * statement in the folder to determine which properties—besides the built-in schema ones—the query should return.

You should try to limit your use of SELECT * statements if possible, because the query processor will have to retrieve every built-in and custom property in your content class, which can take a long time. If you know the specific properties you need to retrieve as part of your resultset, you should specify them in your query. Here's an example of setting the expected-content-class property in code:

 oFolderRecord.Fields _ ("urn:schemas-microsoft-com:exch-data:expected-content-class").Value = _ Array("urn:content-classes:appointment", _ "urn:content-classes:mycontentclass") 

Setting the schema-collection-ref Property

In addition to setting the expected content class property, you need to set the urn:schemas-microsoft-com:exch-data:schema-collection-ref property on your application's folders. This property contains a URL that links to the first folder in which you want the Exchange server to look for schema definition items. In your custom applications, you'll set this property to the Schema subfolder. When we discuss using ADO with Exchange Server later in the chapter, you'll see how to determine the URL to set the value of this property to. If you do not set this property on your folders, Exchange Server will default to its built-in Schema folder in the non-ipm subtree. Here is an example of setting this property in code:

 oFolderRecord.Fields _ ("urn:schemas-microsoft-com:exch-data:schema-collection-ref").Value = _ "file://./backofficestorage/domain/public folders/myapp/schema" 

Setting the baseSchema Property

You have one final task to perform to make your application's schema work well: you need to set the urn:schemas-microsoft-com:exch-data:baseschema property on your schema subfolder. This multivalued property provides URLs that Exchange Server will search if it doesn't find schema definitions in your schema subfolder. The server will search the set of URLs you provide in the order they're set in the property. So if Exchange Server finds the correct schema definition, it will stop searching subsequent URLs. By setting the schema-collection-ref property for your folders, you can have Exchange Server search your schema folder first and then search the built-in schema folder. The following is an example of setting this property:

 strBaseSchemaFolder = _ "file://./backofficestorage/domainname/public folders/" & _ "non_ipm_subtree/schema/" With oSchemaFolder .Fields("urn:schemas-microsoft-com:exch-data:baseschema") = _ Array (strBaseSchemaFolder) .Fields.Update End With 



Programming Microsoft Outlook and Microsoft Exchange
Programming Microsoft Outlook and Microsoft Exchange, Second Edition (DV-MPS Programming)
ISBN: 0735610193
EAN: 2147483647
Year: 2000
Pages: 184

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