Building a Multiple Agent Solution

 < Day Day Up > 

A Remote Access Problem

Chapter 3 introduced a fictional company named Slugger Sports. The company produces a wide variety of sports equipment for T-ball and youth baseball games. It employs dozens of regional sales representatives who work almost entirely on the road. These salespeople utilize laptops and mobile phones to communicate with the central office about sales opportunities. Because they are remote, they do not always have consistent and reliable Internet access.

Marketing people and sales managers located at the central office often produce documents that may be useful to the sales representatives. The remote reps need a reliable way of accessing all this changing information as quickly as possible. In addition, new or updated sales opportunities are constantly being added to the central database. The sales representative needs a way of being notified when a change has occurred.

Loading the Sales Scheduling Database

To run the code accompanying this chapter, you will need to create a database in Microsoft SQL Server named SalesScheduling. You may have already done this if you ran the code for Chapter 3. This chapter will utilize the same database used in that chapter, and the SalesScheduling.mdf file can be downloaded from the book's Web site.

To attach the SQL database, execute the following steps:

1.

Copy the SalesScheduling.mdf and SalesScheduling.ldf files from the book's Web site to a local directory on the server where Microsoft SQL Server is installed.

2.

Open Microsoft Enterprise Manager

3.

Right-click the Databases node and click All Tasks. . . and Attach Database. . .

4.

From the Attach Database dialog, browse to the directory where you copied the database files in step 1 and select the SalesScheduling.mdf file. Click OK.

5.

Click OK to attach the database.

6.

To see the newly added database, you will need to click Action and Refresh.

Loading the Sample Application

Figure 8.1 is a diagram representing the remote access solution presented in this chapter. The solution consists of a remote agent and a server agent. Table 8.3 is a listing of the different projects that make up the solution. To execute the sample code available for download from the book's Web site, you will need to execute the following steps:

1.

If IIS has already been installed on the machine, then you will have by default a directory named C:\Inetpub\wwwroot. Create a new folder in this directory named Chapter8 and copy the contents of the code directory (from the book's Web site) to this location.

2.

You will then need to open the Internet Information Services Manager and browse to the Default Web Site node. Right-click the AgentWebService directory (within the Chapter8) folder and click Properties. From the Directory tab, click the Create button. When finished, click OK and exit Internet Information Services Manager.

3.

If Visual Studio .NET has already been installed on your machine, you can open the code sample by double-clicking the solution file named Agent.sln from the C:\Inetpub\wwwroot\Chapter8\Agent directory using Microsoft Windows Explorer.

Figure 8.1. Diagram of the remote access solution presented in this chapter. The server agent is responsible for publishing information about changing files and directories on the central server. The remote agent is responsible for retrieving desired changes from a Web service when an Internet connection is available. Files are transferred asynchronously using Microsoft's Background Intelligent Transfer Service (BITS).


Table 8.3. Code Listing for the Chapter 8 project. The files can be accessed by opening the Agent.sln file, located in the Agent subdirectory. There are four different projects associated with this solution. One represents the remote agent (Agent), one represents the Web service (AgentWebService), one represents the C++ code needed to set the credentials for BITS (BITSCredentials), and the last one represents the server agent (ServerAgent).

Project

File Name

Description

Agent

Agent.sln

Solution file

 

Components/Background Copy.vb

Contains Visual Basic code used to create and manage file downloads using BITS.

 

Components/Database.vb

Contains Visual Basic code used to get new opportunities from the database using a call to a Web service.

 

Components/File Monitor.vb

Contains Visual Basic code used to monitor files being copied manually to the local start path or files that are created new in the start path.

 

Components/Inet Connection.vb

Contains Visual Basic code used to check for the existence of an Internet connection on the client.

 

Components/Settings.vb

Contains Visual Basic code used to read values from and write values to the AgentSettings.xml file.

 

AgentSample.vb

Contains Visual Basic code and represents the main code file for the project. Using a timer control it will poll for a connection every two minutes and if found will execute methods from the other code files in the components folder.

AgentWeb Service

AgentWebService.asmx

Main file used by the Web Service. Contains Visual Basic code used to retrieve the contents of the FileInfo.xml file and new sales opportunities form the database.

BITS Credentials

Source Files/BITS Credentials.cpp

Main code file used by BITS to set the credentials of the client when initiating a new transfer job. Contains C++ code.

 

Header Files/BITS Credentials.h

Header file that corresponds to the BITSCredentials.cpp code file.

Server Agent

Components/File Monitor.vb

Contains Visual Basic code used to monitor files being added or updated on the central server. Changes will be written to the FileInfo.xml file.

 

ServerAgentSample.vb

Contains Visual Basic code and represents the main code file for the project. It will call methods from the FileMonitor code file.


The remote agent is responsible for pulling files and database updates from the central server. The sales representatives will all execute the same remote agent code on their local machines. The application will behave differently depending on the values stored in the user configuration file. The server agent is responsible for producing an XML file used by each remote agent to determine which files it needs to pull. The Web service is the method by which the remote agent will access information from the central server. It is essentially the interface to the data.

Remote Agent

The remote agent (represented by the project named Agent) will execute continuously as a Windows service and thus can operate independently. If it encounters errors, it will log them in the Windows Event Log and continue processing. Because it is a Windows service, it can be configured to start automatically so that the user is not responsible for executing it specifically.

The agent will periodically check to see if the laptop is connected to the Internet. The InternetGetConnectedState function is used because we do not want the sales representative to be prompted to provide connection details every time the agent polls for a connection. This function is exposed by the Windows Internet (WinInet) API. The code that uses this function to poll for a connection is encapsulated inside the InetConnection class file and is seen as follows:

 Public Shared Function CheckInetConnection() As Boolean     Dim lngFlags As Long     If InternetGetConnectedState(lngFlags, 0) Then        Return True     Else        Return False     End If End Function 

If CheckInetConnection returns a true value, it will begin the process of checking for updates. If it determines that specific files the user is interested in have been updated or new files added, it will initiate a BITS job. The BITS job is responsible for asynchronously transferring files over a network despite network interruptions or bandwidth restrictions. BITS is covered in more detail in the section titled "Background Intelligent Transfer Service (BITS)."

The agent is customized for each sales representative through the use of an XML-based configuration file (see Figure 8.2). The configuration file, named AgentSettings.xml, should be located in the application data directory for all users. Typically, this path is C:\Documents and Settings\All Users\Application Data\Agent.

Figure 8.2. Screenshot of the Services dialog on a Windows XP machine. The Background Intelligent Transfer Service listed in Services allows Windows Update to automatically download the latest updates to your machine. It will also be used by the remote agent in this chapter to download file updates.


This file contains information about which documents the user is interested in. The remote agent determines which files the user wants based on certain predetermined file attributes, such as extension, author, and keywords. Thus, if the configuration file contains a node for an author named Mark Peters, the remote agent will pull all the files in which Mark Peters is the author.

The sales representative is required to select an existing directory on the local hard drive in which to store all transferred documents. This value is stored in the node named LocalStartPath. This path may contain as many nested subdirectories as necessary.

The configuration file will be modified by the remote agent every time the sales representative copies a new file into the local directory. This is because the agent will assume that the representative is interested in knowing about future updates to the file. A sample configuration file is shown as follows:

 <?xml version="1.0" encoding="utf-8" ?> <UserSettings>  <LocationSettings>     <ServerName>CentralServer</ServerName>     <ServerStartPath>AgentServerPath</ServerStartPath>     <LocalStartPath>C:\AgentLocalPath</LocalStartPath>  </LocationSettings>  <FileSettings>     <Authors>        <Author>mark peters</Author>        <Author>lauren jones</Author>     </Authors>     <FileTypes>        <FileType>.xls</FileType>        <FileType>.doc</FileType>     </FileTypes>     <Keywords>        <Keyword>2003</Keyword>        <Keyword>budget</Keyword>        <Keyword>spalding</Keyword>        <Keyword>t-balls</Keyword>     </Keywords>  </FileSettings> </UserSettings> 

For the sample file shown, the local start path is C:\AgentLocalPath. The configuration file also specifies that the user is interested in all files with an .xls or .doc extension.

Using the Windows FileSystemWatcher class supplied by .NET (covered in more detail in the section titled "Detecting File Changes"), the remote agent will look for files being added to this directory and all the subdirectories within it. As a result, each sales representative's configuration file will be unique. Thus, the agent assumes another characteristic listed in Table 8.1 personalization.

Note

In the sample application, the remote agent is only concerned with author, extension, and keyword. The code could be extended to include additional file attributes. It might also include an interface that allows users to specify which file attributes they are interested in and assign priorities to each attribute. The remote agent would then select files based on this weighted assignment.


Microsoft Agent

Microsoft Agent, version 2 (available at www.microsoft.com/msagent) is a set of software services that developers can use to add animated characters to their applications. This can be a nice feature for agent applications that do a lot of interacting with the user. The use of animated characters can add personalization and uniqueness to an agent-based application.

You can download the core components for Microsoft Agent at www.microsoft.com/msagent/downloads/developer.aspx. In addition to the core components, the download page has links to download documentation, samples, and an Agent Character Editor. It also lets you download any one of four animated characters.

The four characters available for download are:

  • Genie A blue-skinned genie that can appear and disappear in a puff of smoke.

  • Merlin A white-haired magician with a stars-and-moon cape.

  • Peddy The green parrot seen at the top of this profile box.

  • Robby A robot that looks like it came straight from an old science fiction movie.

The agents display emotions like boredom and excitement that make them seem lifelike. They will gesture and refer to certain areas of the screen to make it appear as if they live inside the user's computer.

If you wish to create your own animated character, you can do so using the Agent Character Editor. There are also third-party vendors, such as E-Clips (www.e-clips.com.au), that offer additional Microsoft Agent characters. They will even design a custom character for you. Each character can have its own unique look and personality.

Microsoft Agent utilizes the Lernout & Hauspie TruVoice text-to-speech engine to render the characters' voices. The default language is American English, but you can also download other languages at www.microsoft.com/msagent/downloads.htm##s. You can use any text-to-speech engine you wish as long as it supports the Microsoft Speech API (SAPI) version 4. Note: Windows XP users have SAPI version 5 installed by default and will need to specifically download SAPI version 4 from the Microsoft Agents downloads page.

Agents can be developed in multiple environments, including Microsoft Office, Visual FoxPro, and older versions of Microsoft Visual Studio. Since it is COM-based, it can also be referenced from a Microsoft .NET application. The Web site contains a code sample using Microsoft .NET and C# at www.microsoft.com/msagent/dev/code/dotnet.asp.

The Web site also contains information regarding Microsoft Agent licensing and distribution. You will be required to include a notice that your site "Uses Microsoft Agent technology." An additional copyright notice is required if you use any of the four characters Microsoft provides.

Using Microsoft Agent gives your interface a natural look and offers the user an alternative to the traditional point-and-click style interface. This could be nice for software agents that need to gently inform the user of certain events. The agent will be more an assistant and not just another piece of software.


Server Agent

The second agent (represented by the Windows service project named ServerAgent) is responsible for producing an XML file (named FileInfo.xml) that lists all the files and directories that have recently changed on the central server. The agent utilizes the FileSystemWatcher class to raise events every time a file or directory is added, modified, or deleted. This is covered in more detail in the section titled "Detecting File Changes."

As changes are detected, the FileInfo.xml file is updated. This file should be located on the central Web server and will be exposed to the remote agent through a Web service call. A sample version of this file is seen as follows:

<?xml version="1.0" encoding="utf-8" ?> <agentserverpath lastupdated="7/23/2004 12:41:23 PM">    <subdirectory1a type="dir">        <subdirectory2a type="dir">           <SR01.doc type="file">            <createddate>7/20/2004 4:20 PM</createddate>            <modifieddate>7/17/2004 5:44 PM</modifieddate>            <extension>.doc</extension>            <author>Sara Rea</author>            <keywords>2003 Sales</keywords>           </SR01.doc>           <licensekey.txt type="file">            <createddate>7/22/2004 3:30 PM</createddate>            <modifieddate>7/21/2004 4:48 PM</modifieddate>            <extension>.txt</extension>           <author></author>           <keywords></keywords>          </licensekey.txt>        </subdirectory2a>        <postinfo.html type="file">           <createddate>7/23/2004 12:29 PM</createddate>           <modifieddate>6/9/2003 9:17 AM</modifieddate>                 <extension>.html</extension>           <author></author>           <keywords></keywords>        </postinfo.html>   </subdirectory1a>   <subdirectory1b type="dir"></subdirectory1b>      </agentserverpath> 

The FileInfo.xml file contains an attribute named lastupdated. This is used by each remote agent to determine whether changes have taken place. The remaining information is used by the remote agent to determine whether new or updated files need to be updated.

Detecting File Changes

As stated earlier, file changes are detected using the FileSystemWatcher class. This class allows you to specify a directory and watch for any changes to the files and subdirectories within it. Both the server and the remote agent will utilize this class.

For the remote agent, the class is used to monitor the local hard drive. Sales representatives can configure their agents by initially copying files they are interested in to a subdirectory within their local start path. Upon startup, the remote agent will instruct the FileSystemWatcher class to monitor the local start path and kick off code whenever a new file is added.

The code to initialize FileSystemWatcher is seen as follows:

 Public Shared Sub SetLocalFileWatcher(ByVal StartPath As  String)   'Create a new FileSystemWatcher object and set it's   'properties. This watcher will be set to monitor files   'being copied manually to the local start path or files   'that are created new in that start path   Dim fw As New FileSystemWatcher   fw.Path = StartPath   fw.IncludeSubdirectories = True 'Include subdirectories   fw.Filter = ""                  'Watch all files   fw.NotifyFilter = (NotifyFilters.LastWrite _                 Or NotifyFilters.FileName)   'Add the event handlers indicating that we want to   'be notified of file creations   AddHandler fw.Created, _     New FileSystemEventHandler(AddressOf LocalFileCreated)   'Tell it to start watching   fw.EnableRaisingEvents = True End Sub 

In this code, we create a new FileSystemWatcher object and set its properties to include all subdirectories and file types. We also restrict it to look only for changes to the last write time stamp and file name. Since file changes can trigger a number of different events, this prevents the event handler from being called unnecessarily.

A handler is added to indicate what method should be called when a new file is created. This handler points to a method named LocalFileCreated, which contains code to collect the file attributes and add them to the AgentSettings.xml file. The last line of code is used to initiate the monitoring process.

The server agent utilizes the FileSystemWatcher class to monitor the server start path and record changes to the files and directories within. Upon startup, the agent will initiate two FileSystemWatcher objects. One is used to monitor file changes, and the other monitors directory changes. In both cases, the objects will be configured to watch not only for the creation of files and directories, but also for any changes, renamings, and deletions.

Every time an event handler is executed, it will modify the FileInfo.xml file to match the change that has taken place. If someone at the central office changes a file named SalesFigures2003.doc, for example, the event handler will update the modifieddate node for that file.

Each event handler utilizes the Document Object Model (DOM) XML parser that is part of Visual Studio .NET. By using this parser, we can easily modify the contents of FileInfo.xml. In each handler the xml document is loaded and the correct node located with an XPath query. For example, the code executed when a file is renamed is as follows:

 Private Shared Sub FileChanged(ByVal source As Object, _         ByVal e As FileSystemEventArgs)   'The last write time would have changed since this   'is what we are monitoring for we will want to   'alter the modified date entry for this file   Dim ext As String = ""   'Get the attributes to determine what type of file we have   Dim fi As New FileInfo(e.FullPath)   If fi.Exists Then      ext = fi.Extension.ToLower      'We will ignore temporary files      If e.Name.IndexOf("~") < 0 And ext.ToLower < > ".tmp" Then         'Load the XML         Dim doc As New XmlDocument         doc.Load(Service1._FilePath)         'Split the path so we can parse it back for the query         Dim arrDir As Array = e.Name.Split("\")         Dim oldfile As String = arrDir(arrDir.GetUpperBound(0))         'replace spaces with a dash so XML remains well formed         oldfile = oldfile.Replace(" ", "-")         'Loop through the array and rebuild string for XPath query         Dim rootpath As String = ""         Dim pos As Int16 = 0            Do Until pos = arrDir.GetUpperBound(0) + 1               rootpath += arrDir(pos) + "/"               pos += 1            Loop            rootpath = Service1._RootDir + "/" + rootpath _                   + "modifieddate"                'Do an XPath query            Dim oldnode As XmlNode = _                 doc.SelectSingleNode("/" + rootpath.ToLower)            oldnode.InnerText = fi.LastWriteTime.ToShortDateString + _                 " " + fi.LastWriteTime.ToShortTimeString            'update the lastupdated attribute of the root node            Dim root As XmlNode = _                 doc.SelectSingleNode("/" + Service1._RootDir.ToLower)            Dim lastupdated As XmlAttribute = root.Attributes(0)            lastupdated.Value = Date.Now            'Save the file            doc.Save(Service1._FilePath)            doc = Nothing          End If        fi = Nothing      End If    End Sub 

Utilizing the FileInfo.xml file eliminates the need for each remote agent to scan the entire file tree every time it looks for updates. The burden of detecting file changes has been offset to the server agent. When it detects that a change has taken place, it modifies the FileInfo.xml file and updates the lastupdated attribute.

When the remote agent kicks off its processing because an Internet connection is available, it begins by using the Web service to get a copy of the FileInfo.xml file. It will examine the lastupdated date and determine whether a change has taken place since the last time it checked. Only then will it attempt to look for new files to pull.

This is one example of the potential power of multiple agents. Since each agent can assume a separate responsibility, a group of associated agents is capable of accomplishing large tasks. In our remote access solution, the server and the remote agents assume separate responsibilities that together allow them to keep each sales representative up to date.

Using the Background Intelligent Transfer Service (BITS)

Background Intelligent Transfer Service (BITS) provides the perfect way to access files remotely. Not only does BITS transfer files even after the application that initiated it exits, but it does not force a connection. Files are transferred asynchronously between an HTTP server and a remote client. BITS will adjust the transfer rate to ensure that the machine's resources are not all consumed. Most important, if an Internet connection is lost in the middle of a transfer, all is not lost. BITS will simply pick up where it left off when the connection is reestablished. Even if a file transfer takes hours or even days to complete, the system will not be compromised.

With BITS, the agent is able to function independently despite bandwidth restrictions or network interruptions. These are all-too-common problems for remote salespeople, and therefore a dependable transfer method is a must-have for remote agents.

How to Access BITS

If you have ever used the Windows Update feature, you have already used BITS. Available with Windows XP, Windows Updates automatically searches the Microsoft servers for the latest updates and patches, and then checks to see whether your machine is up to date. If it is missing any updates, BITS transfers them to your machine without interrupting or otherwise detracting from your user experience. In fact, you may have noticed the engine that allows BITS to function in the Services dialog (see Figure 8.2).

It's a great idea, and fortunately Microsoft exposes the functionality used to accomplish Automatic Updates through a set of API's. The bad part is that for now, the API's are not exposed through a Visual Studio .NET wrapper. Therefore a little work is required to get to the functionality.

Tip

BITS is utilized by one of the applications available from the Microsoft Patterns and Practices group (http://www.microsoft.com/resources/practices/default.mspx). The Updater Application Block can be used to quickly create self-updating applications. This feature can be invaluable for Windows Forms applications in which deployment is often a major hurdle. The application block is responsible for polling a central location for application updates. When one is available, it uses BITS to download the files and then updates the client.


For starters, you must download the latest version of the Platform SDK from MSDN. This will give you access to the BITS.idl file. From there, you can use the Microsoft Intermediate Language (MIDL) compiler that is included with Visual Studio .NET to compile a type library. Next you will need to use the Type Library Importer (Tlbimp.exe) to convert the type definitions into a form useable by COM. The result of all these steps is a binary file (BackgroundCopyManager1_5.dll) that is available to you on the book's Web site. We can now add a reference to the binary file through References and thereby access the BITS functions.

Tip

Adding a reference to the BackgroundCopyManager1_5.dll file gives you access to the BITS functions directly but can be cumbersome to use. You may want to consider using a wrapper for BITS. This can be especially useful when you have an application that utilizes many of the complex features of BITS, such as concurrent foreground downloads or downloading ranges of files. To find out how to create your own BITS wrapper, refer to the article on MSDN titled "Using Windows XP Background Intelligent Transfer Service (BITS) with Visual Studio .NET."


Creating a Transfer Job

The transfer job is the central object in BITS. A job can consist of one or more files, and it is used to specify how files are to be transferred. The remote agent creates a transfer job using the CreateJob function, seen below:

 Public Shared Sub CreateJob(ByVal FileList As ArrayList, _    ByVal RemoteURL As String, ByVal LocalStartPath As String)   Dim bcm As New BITS.BackgroundCopyManager1_5   Dim job As BITS.IBackgroundCopyJob   Dim jobId As BITS.GUID   Dim bcc As New BackgroundCopyCallback   Dim jobname As String = ""   Dim username As String = "BITSUser"   Dim password As String = "bitsuser"   'The job will be named the machine name along with   ' a date time stamp   jobname = Environment.MachineName + "-" + _     Date.Now.ToShortDateString + "-" + Date.Now.ToShortTimeString   'Create the download Job that will be added to the queue   bcm.CreateJob(jobname, BITS.BG_JOB_TYPE.BG_JOB_TYPE_DOWNLOAD, _      jobId, job)   'Set the job priority to normal   job.SetPriority(BITS.BG_JOB_PRIORITY.BG_JOB_PRIORITY_NORMAL)   'Associate all the files in the FileList with this job   Dim strFile As [String]   For Each strFile In FileList      job.AddFile(RemoteURL + strFile, LocalStartPath _            + "\" + strFile)   Next   'Set a reference to the BackgroundCopyCallback Interface   'This is used to receive notification about the jobs state   job.SetNotifyInterface(bcc)   'Tell BITS which events we want to be notified about   job.SetNotifyFlags(Convert.ToUInt32(Flags.IsTransferred _      Or Flags.IsError))   'Set Credentials by calling out BITSCredentials wrapper   Dim wrapper As New BITSWrapper   Dim iunknown As IntPtr = Marshal.GetIUnknownForObject(job)   wrapper.BITSSetCredentials(iunknown, username, password)   Marshal.Release(iunknown)   'Activate the job in the queue   job.Resume() End Sub 

Once the remote agent determines which files will be added to the transfer job, it calls the CreateJob function and passes it an array list containing all the files to be transferred. To make the job name unique, it is named as the machine name along with a date and time stamp.

The job is created as a download type, which is the default type for new jobs. The other job types are upload and upload-reply. Both of these types are used if uploading files to a server. The upload-reply type is also used to receive a reply from the server application.

For this example, we set the priority to normal, which means that all files will be marked with the same importance level. The alternative priority values are foreground, high, low, and normal. A job marked with a high priority value will transfer out of the queue before one with a low or normal value. The foreground priority is the highest value, but you should take care when using it. A job with this priority will directly compete with other applications on your machine.

BITS Authentication

Even though BITS supports secure connections over HTTPS, you will most likely want to provide additional security. You can do this by specifically setting the credentials that BITS uses to access the files on the server. BITS supports Basic, Challenge/Response, and Passport authentication schemes.

To execute the sample application, you need to create a virtual directory on your Web server from which the server files will be available. You can access directory security by executing the following steps:

1.

Open Internet Information Services from Control Panel and Administrative Tools.

2.

Right click the Default Web Site and click New. . . and Virtual Directory.

3.

From the Virtual Directory Creation Wizard dialog, click Next.

4.

Specify an alias name for your virtual directory and click Next.

5.

Browse to the directory where the server files are located and click Next.

6.

From the Access Permissions dialog, click Next.

7.

Right-click the newly created virtual directory and click Properties.

8.

From the Properties dialog, click the Directory Security tab and then click Edit.

9.

From the Authentication Methods dialog (seen in Figure 8.3), uncheck Anonymous access and make sure Integrated Windows Authentication is the only item checked.

Figure 8.3. Screenshot of the Authentication Methods dialog, accessible from the Directory Security tab in Internet Information Services. When configuring the virtual directory for the sample application, make sure that Anonymous access is unchecked.


Once security is configured for the virtual directory, we will need to explicitly declare credentials using the SetCredentials method. BITS uses the Crypto API to protect credentials. The Crypto API is part of the core cryptography functionality in Windows and, like BITS, is available to developers through the Platform SDK.

Unfortunately, the SetCredentials method is not included when the MIDL compiler compiles the BITS type library. To use this functionality, you have to perform an additional step. This involves writing a managed C++ wrapper to call the SetCredentials method from the native BITS library.

A C++ wrapper is included with the agent solution file on the book's Web site. It is embedded in the BITSCredentials project. The code for the BITSSetCredentials method is seen as follows:

 void BITSWrapper::BITSSetCredentials(System::IntPtr ptr, String* _         userName, String* password) {    HRESULT hr = S_OK;    void* pv = ptr.ToPointer();    IBackgroundCopyJob2* job;    BG_AUTH_CREDENTIALS creds;    const wchar_t __pin* user = PtrToStringChars(userName);    const wchar_t __pin* passwd = PtrToStringChars(password);    creds.Scheme = BG_AUTH_SCHEME_NTLM;    creds.Target = BG_AUTH_TARGET_SERVER;    creds.Credentials.Basic.UserName = (LPWSTR)user;    creds.Credentials.Basic.Password = (LPWSTR)passwd;    hr = ((IUnknown*)pv)->QueryInterface_     (__uuidof(IBackgroundCopyJob2),(void**)&job);    if (SUCCEEDED(hr))       hr = job->SetCredentials(&creds);    if (FAILED(hr))      {       BITSCredentials::BITSWrapperException* e = _        new BITSCredentials::BITSWrapperException(hr);       throw e;       } }; 

In this code, the BITSSetCredentials method accepts the user name and password as input parameters. It also accepts a pointer to the BITS transfer job. The method defaults to use the Windows challenge/response scheme (BG_AUTH_SCHEME_NTLM). Alternatively, we could have specified that it use basic authentication with the BG_AUTH_SCHEME_BASIC value. The drawback of this authentication method is that the user name and password are sent as clear text and therefore authentication is not as secure.

Note

When attempting to run the sample application available for download from the book's Web site, you may have to use basic authentication in order to successfully execute the code. Depending on where you execute the application and the login rights granted to the logon user, you may receive an authentication error. If this happens, change the Directory security to use basic authentication and modify the value in BITSSetCredentials.


Register for Notification

After a job has been added to the transfer queue, the next step is to determine when the files were transferred. This can be done in one of two ways. The first is to create a timer and poll for the state of the job. The job will either be in a Transferred, Disabled, Error, or Notification state. The problem with this method is that it is synchronous and requires that the job be transferred or in error before it can complete the job.

A sales representative may terminate an Internet connection at any time, even during the transfer of a job. A synchronous process would cause problems if the connection was dropped before the transfer was complete.

The remote agent instead implements the IBackgroundCopyCallback interface to maintain asynchronous processing. This allows us to register for notification whenever the job reaches a certain state. The following code from our CreateJob function is used to set a reference to the interface and tell it which events we are interested in.

 'Set a reference to the BackgroundCopyCallback Interface 'This is used to receive notification about the jobs state job.SetNotifyInterface(bcc) 'Tell BITS which events we want to be notified about job.SetNotifyFlags(Convert.ToUInt32(Flags.IsTransferred _             Or Flags.IsError)) 

For the sample application, we have asked to receive notification whenever a job is transferred or an error occurs. When the job has transferred, we will call the Complete method. This enables the user to see the files. Until this method is called, the files will only appear as empty temp files on the remote agent's machine.

When an error occurs, the following code is executed:

 Sub JobError(ByVal job As BITS.IBackgroundCopyJob, _      ByVal jobError As BITS.IBackgroundCopyError) _    Implements BITS.IBackgroundCopyCallback.JobError    'The job received an error, but we need to determine what type of    'error it was    Dim jobname As String = ""    Dim ErrorMsg As String = ""    Dim BITSError As String = ""    Dim LanguageID As Integer = &H409 'Indicate language is English(US)    If Not job Is Nothing Then      'Get the name of the job       job.GetDisplayName(jobname)      'Get the error       job.GetError(jobError)       jobError.GetErrorDescription(Convert.ToUInt32(LanguageID), _            BITSError)      'Log the error using the Exception Manager application block       ErrorMsg = "The following error was encountered trying to "       ErrorMsg += "process the BITS job " + jobname + " : "       ErrorMsg += BITSError       ExceptionManager.Publish(New Exception(ErrorMsg))      'Cancel the job       job.Cancel()    End If End Sub 

In this code we get the display name of the job, which should be the machine name and a date/time stamp (this was defined in the CreateJob function). We also get the error description and then publish the error using the Exception Management Application Block. Finally, we cancel the job so that it will no longer appear in the transfer queue. At this point, any empty temp files on the local machine should disappear.

Monitoring New Opportunities

New leads are constantly being added to the central database. The salespeople all have access to a Web application that allows them to work these new opportunities. Unfortunately, most salespeople only check the Web application once a day. In some cases it may take several hours or days for a sales opportunity to be discovered.

The remote agent contains a CheckDatabase function that is used to check for new opportunities. The function is initiated as soon as an Internet connection becomes available. CheckDatabase will make a call to the Agent Web Service and pass in the remote salesperson's e-mail address. The Web service will search the leads table for leads located in the zip code assigned to the salesperson. If the salesperson has the status of 'N' (new) and also has a notify date older than forty-eight hours, the contact information is returned.

Note

The Web Service featured in the sample solution is not considered secure. At a bare minimum, a production application would want to consider enabling point-to-point security using SSL (Secure Sockets Layer). To enable SSL, readers would need to request a certificate from a certification authority utility on the Web server.

Readers can obtain a certificate from a recognized authority like Verisign (http://www.verisign.com), or they can generate their own using the secure certificate wizard in Internet Information Services Manager.

Once a certificate is downloaded, a pending certificate request can be installed on a Web server using the IIS Manager. At this point, requests made to the Web service would have to include the HTTPS header instead of HTTP. This will ensure that any traffic between the Web service and the client is encrypted.


Every time the CheckDatabase function finds new leads, it displays a message box to the user (see Figure 8.4). Thus, the remote agent exhibits one more agent characteristic the ability to communicate with the user.

Figure 8.4. Screenshot of the dialog box used to notify the remote salesperson of new sales opportunities. A notification will be sent to the salesperson every forty-eight hours until the lead is worked or no longer has the status of new.


     < Day Day Up > 


    Building Intelligent  .NET Applications(c) Agents, Data Mining, Rule-Based Systems, and Speech Processing
    Building Intelligent .NET Applications(c) Agents, Data Mining, Rule-Based Systems, and Speech Processing
    ISBN: N/A
    EAN: N/A
    Year: 2005
    Pages: 123

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