E-commerce components

advertisement
E-commerce components
Hello, and let me introduce myself. My name is Christian Gross and I am the author of the components
that you are about to use. I can be reached at cgross@eusoft.com or Serpent_Mage@csi.com. We will be
opening the news group component.microsoft at the server jupiter.eusoft.com where you can post any
question regarding these components. This way if you want to extend them or use them, we will answer
those questions. As a side line note, these components have not restrictions on their use, but there is no
warranty and I would prefer that you do not call them your own.
What are the purpose of these components? The purpose is to show you how Visual C++ can be used to
build professional components that are used in an e-commerce environment. The components that have
been authored are not pie in the sky components. They are components that we have used to solve
problems for our clients. There are of the utility type, and therefore reusable.
First how many components are there? There are four and they are:
 Notification: This component is used to supply a notification of action. When a client comes to a web
site they may buy something or register themselves to be on some kind of list. The notification
component is used to provide feedback by some kind of mechanism. In this example the feedback is
email (SMTP)
 Security: Logging onto a web site is a requirement. And providing a mechanism to logon is simple.
However, very often you will need to implement a need to know security mechanism. This component
provides both of those security requirements. The security database used is a physical database. Once
Windows 2000 becomes production code, it should be replaced with Active Directory.
 XML Components: These components are the biggest, and they provide the ability to consume and
publish XML. The publisher component will take a COM object and serialize it as a series of XML
nodes. The consumer component implements the XML SAX model and generates events when the
tree is being parsed.
 Generic Container: A container that has built in filtering mechanism. This makes it possible to keep
running totals on objects and filter information before the container is filled.
Before I dig into the details of using the components is there a way to understanding them? Yes and here is
the list:
Understand Visual C++ and ATL
Understand COM interfaces and how you implement them
Next the complexity order is Security, Notification and then the XML components
Some general notes on programming style
In most of the applications and components there is a general programming style that I use.
1.
2.
3.
IDL definitions: When there are COM interfaces that need to be implemented or reused they are
stored in the project’s common directory in an IDL file that has the naming convention
xxxcommon.idl.
Global definitions: There are three types of global definitions. The first is system wide. These sort of
definitions are stored in the project’s common directory in a header file that has the naming convention
xxxcommon.h. The second global definition is project wide and they are stored in the projects stdafx.h
file. Finally the last global definition is stored as a static within the implementation file.
COM compiler support: There is frequent and heavy use of COM compiler support. This is because
smart pointers make it much easier to manage the various COM interfaces. It also makes it easy to do
COM factoring. The one downside is that when COM interfaces are returned from a smart pointer an
additional reference count must be made. As well very often the data types _bstr_t and _variant_t are
used.
4.
5.
6.
STL: Whenever possible I have attempted to use STL.
Namespaces: Default namespaces are not used. This is to avoid name collisions, since an interface
could have different meanings to different contexts.
Test scripts: Within the common project directory very often test scenarios are created using the
Windows Scripting Host. Specially they are JavaScript files (xxx.js)
Generic Container Details
The purpose of the Generic container is to show how to write a shopping cart application. The problem
very often is that you surf to a web site and then you want to purchase or track multiple items. These items
need to be added to a container. This could be accomplished using a standard collection class. However,
in the case of a shopping cart example you will want to keep a running total. To do this you can
dynamically check each item and keep that tally in some other object.
The Generic Container simplifies this by adding the concept of a filter. The filter is associated with the
container. And then whenever any item is added to the container, the filter can either ok it or reject it.
Examples of rejecting included out of stock, wrong product id or credit limit is exceeded. The concept of
the filter makes writing a shopping cart simpler because the container is dynamic and you do not need to
constantly tally or query for correctness of the items in the container.
Project Location
GenContainer
Directories
 common: Contains the Filter and Generic Item interface definitions
 GenericContainer: Contains the Container project and a simple item value implementation
 ShoppingCart: Contains a sample filter CTotalFltImpl that tallies the total of the items currently
present in the container.
How it’s implemented
The core container is implemented in the COM object CContainer. It allows storage of COM objects called
items in the container. The items must be IDispatch derived and must implement the IGenContItem
interface. The items can be added to the container using the IContainer::add method. If the addition is
successful then the BOOL return code is TRUE. If it is FALSE, the item has not been added to the
container. To retrieve the reason why the item could be not be added reference the property
IContainer::errorMessage. It is possible to navigate through the various items using the methods
IContainer::next, IContainer::prev, IContainer::rewind. To retrieve the current item reference the property
IContainer::currItem.
The interface IGenContItem is a generic interface that all items must implement. The purpose of the
container is to be able to store different types of COM objects. Some items may reference products and
some items may reference credit limits. The point is that the container can handle an IDispatch based
object. With these varying objects the filters must have a common interface that they can use to see if the
item can be added to the container. This interface is called IGenContItem. This interface is like a variant
and it allows the possibility to store and retrieve indexed properties. In the GenericContainer project a
simple implementation of IGenContItem has been supplied.
How to extend it
To extend this project to fit your own situation you need to build the GenericContainer project. This is the
core. Then for your own filters you will need to implement the interface IGenContFilter. For custom items
you will need to implement IGenContItem. Once this has been done you are ready to use the
GenericContainer COM object.
Warnings
Currently the container project is marked to handle COM threading “both”. However, there is no
concurrency control when adding items. This would need to be added. Items cannot be removed, the only
way to do this is to delete the container and then recreate it.
Security Details
The purpose of the security component is to implement need to know security and logon in one component.
Typically the situation in a web site is that you need log-on and information filtering capabilities. One of
the ways to solve this is to use Web Server security and restrict access to specific files. The problem with
doing this is three-fold. First I myself am not overly enthusiastic about putting several thousand users in
my Windows NT security database. The problem that we face is that we need to be able to move users
from one machine in one domain to another machine in another domain. Using Windows NT security in
Windows NT 4.0 does not make this simple. As a side note this situation has been dramatically improved
with the release of Active Directory within Windows 2000. The second reason why we typically use
database access is because it gives us the ability to filter information based on the user’s information
viewing level. The last reason is very often we need to cross-reference the data with other platforms
(UNIX or CORBA as examples). And there is no compatibility between the various security schemes.
This component is a simple to use component that is added to the ASP page and then it handles everything
itself. It will check if the user is logged on and if not load up a login page. That page will then be used to
define a security level. Examples of security levels include user and administrator.
Project Location
Security
Directories
 NTKSecurity: Contains the Security COM object
 DBUsers: Contains sample Access database and SQL Server scripts to create the users table
 SecurityWeb: Contains a web site that shows how to use the component within an ASP page
(example1.asp)
How it’s implemented
This component is an example of a component that uses the ASP object model. It can only be used in IIS
4.0 or later. This is because it retrieves the Context and queries for the ASP properties. It does not use the
outdated ASP activation interface implementation. The core object is IUserClear. It is placed on the web
page and then the method IUserClear::logon is called. This method queries for the ASP object Session and
then asks for the value logonstate. If this value is NOT_LOGGED then the method will load the internally
define web page html1.htm. It is sent back to the client using the ASP object Response.Write. Once this
page has been sent the connection is terminated and the user only sees the logon web page. This is
accomplished by the component telling the ASP Response object that the request has ended. Now the
client must logon. The request is redirected back to the same page. This time the logon page queries for
the values of the logon, validates them, and then sets a security clearance level. If the logon is successful
this time the ASP script can continue. To retrieve the security level the property IUserClear::securityLevel
is called.
How to extend it
This component is self contained and does not need to be extended to suit the individual situation. What
does not need to be implemented are a set of components that add the user to the database.
Warnings
This component can only be used with IIS 4.0 or later. It is also vital that all pages that require security
clearance reference this component. The logon state is saved using the ASP Session object. It does mean
that if you use Windows 2000 web farming or multiple web sites logon will have to occur multiple times.
There is no simple solution for multiple web sites and web farms. When you build this component there
may be an error during registration since it requires mtxex.dll. This is something that you use on Windows
NT 4.0. If there are questions on how to implement this on a web farm, please post to the above mentioned
news group.
Notification Details
In one of the web site where we implemented a conference registration system, there has been the need to
implement notification functionality. The reason is because people do not regularly or timely visit a web
site. This is because people have better things to do than constantly visit a web site to check their
registration status. What people wanted was feedback via a fax or email. In this example the email part
has been implemented.
Notification may seem like a trivial task. You get the proper component (for example email) and then write
an email and send it. But in fact it is a bit more complicated. The reason is because for the various
notifications (email, fax) you have different components. So what we needed was a generic notification
interface that generated a document and then sent it via the notification transport system.
Project Location
Notification
Directories
 common: Contains the ISrvcNotification interface definition and common definitions
 aspemail: Free email component that is used to send email from the component
 NotificationWeb: An example website that generates the document that will be sent
 SMTPNotification: Implementation of the ISrvcNotification interface that using the SMTP protocol
 tstDispatcher: An example of using component within a Visual C++ console application
How it’s implemented
In this project all notification components must implement the ISrvcNotification interface. This interface
has several properties to define the destination and the sender. There is only one method Send, which
sends the notification as per the protocol defined by the implementation.
The implementation needs to generate documents on the fly. For example there is a standard document and
certain fields need to be replaced. In our case it would have been the cost of registration, to whom the
registration is addressed, etc. In this simple example it is a simple Hello to and from document. To do this
replacement the simplest way is to use ASP and pass the required parameters via the CGI parameters. In
this class there is a helper function CSrvcNotification::addCGIParameter that builds the CGI command
string automatically. The output of this command is then defined as the body of the email, which is then
sent.
It is also required to add the file notification.ini to the windows root directory. This file serves as a
configuration file for the notification component. You will need to add the following values
[SMTPDispatch]
server=[name of where the SMTP server that sends the email]
[ name of the template that holds the server reference data set by the property notificationTemplate ]
address=[ The URL where the template document is held]
title=[ When the email it is given a subject that is this value]
server=[ The DNS of the server where the template is held]
How to extend it
In this example you only see the SMTP implementation. In our website we had fax capabilities. This
version could not be released because it used “for cost” components. In our case we used the fax server
product from Computer Associates. However, it is possible to use Exchange and the Fax connector. To
add fax capabilities you would need to implement the ISrvcNotification interface and then define a proper
send command. I would still advise using ASP to generate your document dynamically, since this is the
easiest. Most fax components do have the ability to send text or formatted text. Otherwise the component
can be used as is. Please note that the SMTP component used is for free and I have included all materials.
Warnings
The email component is good, but is limiting. For example if you desire to send formatted HTML emails,
you will need to understand MIME and how to build MIME encoded sections. The CGI encoding must be
thoroughly tested for your situations, because it uses the GET version of HTTP posting. There are length
and data type limits. If you want to use binary data, then you will need to encode the data and send it using
a HTTP post command.
XML Components Details
One of the newest technologies and hypes is XML. If you do not understand XML, please reference the
Microsoft web site at www.microsoft.com/xml. The problem that we were facing is how to transfer data
between the client and server. While it was possible to use a binary format, it was complicated. Often the
UNIX box and the NT box would not order the data the same (Sparc vs Intel). Therefore, it was necessary
to use a text format. XML was chosen because it was a readable format and a standard.
The problem with using XML is bridging it from the COM object to either reading or writing it. Very often
reading it was not a problem. Writing was a bigger problem. And when it had to be read you had to
navigate a tree, which was not fun. The reason is because with XML the data can exist or it may not exist.
It is a dynamic hierarchy. And as well, it cannot be determined when the data would appear. Since XML
is a nested concept, nodes at the same level need not have a specific order of appearance. In other words
parsing becomes a situations of if’s and’s or but’s.
The reading or parsing problem was solved using an event driven architecture. In the XML world there is
something called the SAX event interface model. Using this interface definition model you would
implement them and wait for the various elements to appear.
The writing problem was solved by associating COM properties with XML properties. For example if an
object is called Exampleobject and has to COM properties childProperty and exampleProperty then the
XML is:
<ExampleObject>
<childProperty>some value</childProperty>
<exampleProperty>another value</exampleProperty>
</ExampleObject>
If one of the properties is another object then that object is serialized and nested within the root XML tree.
Using this approach the programmer did not need to write any additional serialization code or writing XML
specific code.
Project Location
XMLComponents
Directories
 common: Contains the SAX event interface definitions in IDL form and various common headers that
define the serialization routines to generate XML
 ExXMLImpl: Example implementations of objects that serialize to XML and an implementation of a
reader object that parses an XML file. The project does both generating and parsing of the same data.
 tstXML: The test program that tests the COM objects in the project in ExXMLImpl
 XMLConsumer: The basis implementation of the SAX event object model using COM

XMLPublisher: The basis implementation of the XML serialization routines using COM.
How it’s implemented
To understand how everything is implemented, lets first focus on the generation of the data. It was defined
that the COM object should not need extra programming effort to implement XML serialization. In our
first implementation privately we did the implementation using IStream and ISequentialStream. However,
now that we are releasing the code to the public we cannot use IStream. The reason is because IStream is
used for OLE structured storage. Therefore the interface IXMLSerialize was defined and needs to be
implemented by any COM object that intends to generate XML data.
To simplify this process of implementing the IXMLSerialize interface a template that does the hard work
was created. It is called XMLSerializeImpl< class impl> and accepts as parameter the class name. The
only other requirement to use this class is to call in the FinalConstruct method setObjectName. This needs
to be without spaces and is used to create a root node in the XML. The COM properties are associated to
XML items using the macros XML_xxx_PROPERTY. The xxx is replaced with either LONG, BSTR or
DISPATCH. These macros implement properties as defined in a COM idl file. Consider the following
IDL
[
object,
uuid(37555201-CCAE-11D2-B708-0010A4F15EA7),
dual,
helpstring("IExampleChildObject Interface"),
pointer_default(unique)
]
interface IExampleChildObject : IDispatch
{
[propget, id(1), helpstring("property someValue")] HRESULT someValue([out, retval] long *pVal);
[propput, id(1), helpstring("property someValue")] HRESULT someValue([in] long newVal);
[propget, id(2), helpstring("property anotherValue")] HRESULT anotherValue([out, retval] BSTR *pVal);
[propput, id(2), helpstring("property anotherValue")] HRESULT anotherValue([in] BSTR newVal);
};
This is implemented as follows within the object
XML_BSTR_PROPERTY( anotherValue, m_anotherValue)
XML_LONG_PROPERTY( someValue, m_someValue)
private:
char m_anotherValue[ 64];
long m_someValue;
This makes implementing properties very simple. The way these macros functions is that they will
serialize to XML if they have been set using the put property operator. Therefore, it is absolutely important
in your implementations to set the values using the COM properties and not the values directly. Another
catch is that the properties must be get and put. The macros are defined to implement both of them.
The reader of the XML is a bit different. It implements the various SAX interfaces. First the content is
parsed using the Microsoft XML parser in the object CParserImpl::parse. Then the parser walks the XML
tree and calls the various SAX events. There are many interfaces, but the only one that you need to
concern yourself with is IDocumentHandler. This one is called for the various elements.
How to extend it
The examples shown are very simple. However, it is not so difficult to write your own. First decide what
you want to do, publish XML or consumer XML. For the consumer you need to implement the SAX event
object model. The minimum interface that you need to implement is IDocumentHandler. This one is
triggered whenever there is an element. For the publisher you need to implement the IXMLSerialize
interface using the template XMLSerializeImpl and then add the properties you want to expose. The best
way to understand this fully is to look and inspect the code.
Warnings
There are several major warnings




Do not attempt to combine publisher and consumer of XML in the same COM object. It leads to
complicated COM objects.
The serialization process only serializes the data within the COM object. When the XML is sent, it
does not send the COM object with it.
The MS parser does allow referencing of the XML attributes using an index notation. You must know
the name of the attribute. Therefore in the SAX IAttributeList interface the only method that works is
the property value with a variant of BSTR. Everything else does not work. In fact quite a bit of the
SAX model is unused. This is not peculiar to this implementation, but is peculiar to most SAX
implementations. There is discussion of SAX2 with filtering capabilities
Use properly formatted XML. For example stay away from the notation <tag attr=”value” />. I
personally do not find this proper XML, even though it is accepted XML. There are situations for it,
but if you use it constantly your data is not properly formatted.
And there you have it, four components that we have used constantly in our web sites. I hope you like
them. Look at them, use them and if you have questions, please post them on the above mentioned news
group. If you want immediate attention, send the question to me with a high priority marker.
Christian Gross
March 31, 1999
Download