BizTalk Server 2004 and Web Services
Applies to: BizTalk Server 2004
Summary: This white paper discusses how Microsoft BizTalk Server 2004 supports the use of Web services in building solutions. (15 printed pages)
Service-oriented architecture (SOA) is the mantra of current application development, and Web services are one of the key enabling technologies behind SOA. Web services, based on the widely used and industry-standard SOAP protocol, are becoming increasingly ubiquitous.
Past waves of application development have meant monolithic applications, created by teams of developers who worked in isolation with resources under their immediate control. Exchanging information between enterprises or divisions usually meant brittle hard-wired connections that required collaboration between both sides of the exchange. Service-oriented architectures break down monolithic applications into a suite of services, where elements of functionality are implemented in a modular fashion, and often are exposed as Web services.
Exposing functionality as Web services in such a granular fashion is a great first step toward providing the basic building blocks required to implement solutions, but more work is required. A management layer is needed—something that can orchestrate the Web services, controlling the flow and interaction between them and aggregating individual services into a larger composite solution. Microsoft BizTalk Server 2004 fills that role exceptionally well.
BizTalk Server fully supports all the open standards upon which Web services are built. With its core architecture based on XML and the .NET Framework, BizTalk Server supports Web services naturally. Web service support is tightly integrated into the product.
A BizTalk solution can use Web services in the following ways:
Consume existing Web services
Expose business processes (BizTalk orchestrations) as Web services
Expose the messaging engine through Web services (publishing schemas)
Invoke Web services as part of pipeline processing, a custom adapter, or map execution
This white paper examines the more common ways of working with Web services, discussing the principles and showing implementation examples where appropriate. This paper does not address the use of the Web Services Enhancements for Microsoft .NET (WSE) 2.0 adapter with BizTalk Server.
The scenario that we use throughout this white paper is a new hire process. As part of the process, we call a Web service at a payroll processing company to add the new employee to the payroll.
The use of Web services is a key enabler of service-oriented architectures (SOA). The tenets of SOA call for decomposing software solutions into a series of services that are aggregated to form a higher-level service or a complete application. This approach allows for greater reuse, because the services can be shared between applications and can be combined in different ways to meet other business needs. However, developers still need to write the "glue" layer that aggregates and choreographs the services, and must also be concerned about compensating for unavailable services, handling returned faults, and so on.
A BizTalk orchestration (a graphical way to model and implement processes) simplifies this task by providing the building blocks required to aggregate and manage Web service invocations, thereby providing the "higher brain functionality" required in a Web service solution. You can implement design patterns such as guaranteed delivery in an orchestration, allowing you to take appropriate action if a Web service is unavailable.
A BizTalk orchestration also provides a mechanism to group actions together in a transactional context, allowing appropriate compensation if the operations in a business transaction fail to complete.
How to Consume a Web Service
At a high level, the typical steps required to consume a Web service are:
Add a Web reference to the service you want to consume.
Add an orchestration.
Add a port to the orchestration, setting the port type to the Web port type that was created when you added the Web reference.
Create a new message of the same type as the Web service request.
Create a new message of the same type as the Web service response.
Send the request message.
Receive the response message.
Sign the assembly, deploy it, and test it.
Adding a Web Reference
Consuming a Web service with BizTalk Server is a natural act for experienced .NET developers. They add a Web reference just as they would do from any .NET Framework application that consumes a Web service. When you add a Web reference to a BizTalk project, BizTalk Server queries the service's Web Services Description Language (WSDL) to determine what types, operations, and ports it exposes. The following artifacts are then automatically created and become available from the orchestration:
Web port type
Web message types (request and response)
In addition, the following items are added as part of the reference itself:
Reference map (contains links to the cached service and discovery file URIs)
WSDL file (cached local copy of the Web service description, method signatures, and types)
DISCO file (cached local copy of the Web services discovery file, service, and contract URIs)
ODX file (the BizTalk orchestration file that contains the actual types from the Web reference)
HTML file (a human-friendly version of the WSDL file, hidden in the IDE)
Reference.xsd (optional, contains schemas for any complex types)
In the Microsoft Visual Studio integrated development environment (IDE) these items appear under the Web reference, but if you look at the project's folder in the file system you will see that a "Web References" folder has been added to the project. Each Web reference you add to the project has a corresponding subfolder under the Web References folder.
The Reference.odx file defines the types that are created for you after the WSDL is queried, and are subsequently available in your orchestration. If you double-click this file in Visual Studio, the file is not opened. Instead you see the corresponding HTML file. The HTML file gives you a more refined presentation of the method signatures and data types expressed by the WSDL.
Entry and exit points from orchestrations are through ports, which are of a specific port type. The Web port type has a series of read-only properties that were set as part of the Add Web Reference operation. These properties identify the Web service URI, methods, and parameters. In addition, a multipart message is created that reflects the request and, if appropriate, the response of the Web service. This eliminates the need for you to manually create the schemas, and ensures conformity with the request and response types.
|The default ASP.NET behavior is to return a response even if a method returns void, to allow the service to return a fault message. BizTalk Server creates a response message part for the void return. If you are in control of the Web service and it is a .NET Web service, you can specify that a response should not be returned by using the [SoapDocumentMethod(OneWay=true)] attribute, making it truly fire-and-forget.|
Web ports are visually identified in BizTalk Orchestration Designer by a small globe icon. A Web port can contain multiple operations, each of which represents a Web method call or response.
If the Web service you are using accepts complex types as parameters, or the return value is a complex type, then BizTalk Server needs a schema for those types. In this case, a Reference.xsd file is added to your Web References folder, and the schema file contains the definitions of the complex types as published by the WSDL file.
Adding a Web Port
To add a new Web port
Right-click the right or left port surface, and then click Add new configured port.
On the Select a port type screen, specify that you want to use an existing port type, and expand the Web Port Types node.
This shows you a listing of all available Web Port Types that were created when you added a Web reference to the project. Note that this dialog box also shows you which Web methods the port types expose.
Constructing Web Service Requests and Responses
When working with BizTalk Server you are working in a message-oriented paradigm. This means that you call a Web service by constructing a request message and sending it to the Web port. If a Web method does not accept a parameter, you still use the same approach, in that you create a multipart message that contains no parts. To do this you use a Construct shape to create the appropriate message, but without a Transform or Assignment shape inside the Construct.
Two techniques are used for creating a Web message request: transformation and assignment. Which one you use depends on the parameter type of the method you are calling. If it is a complex type, then you use a transformation (map) or assignment (programmatic) to create the request. If the Web service method you are calling requires a simple parameter type (for example, string), then you directly assign a value to the request message parameter in an expression shape (in this case, you cannot map).
Note that Web service requests and responses have several message context properties that may be of interest. A common use of the context properties is when you call a Web service that takes a long time to return a response. In this case you can adjust the time-out by using the context property as shown below:
WSRegistrationRequest(SOAP.ClientConnectionTimeout) = 20000;
|When setting the SOAP.ClientConnectionTimeout property, you specify the value in milliseconds. The default value is 90000 (90 seconds).|
When setting context properties of a Web service request message, the binding type of the port is important. Only the SOAP.ClientConnectionTimeout property can be changed for all port binding types. The other SOAP-related context properties can be set in an orchestration only if the send port binding type is set to Dynamic.
Sending and Receiving
Sending a Web service request and receiving a response is the same with Web services as with any other port type. You need to set the messages in the send and receive to match the messages you created for the request and response, and then you need to connect these shapes to the request and response operations of the Web port.
The following figure shows an example of consuming a Web service.
Figure 1 Consuming a Web service
In some cases you may want to set the Web service URI dynamically. You can do this by specifying that your Web port is dynamically bound (as opposed to "specify now" or "specify later"), and then setting the URI in a script expression as follows:
CallRegistrationService(Microsoft.XLANGs.BaseTypes.Address) = "http://PayrollCompany/RegisterEmployee.amsx";
Although the preceding example is an effective way to consume a Web service, this pattern is not appropriate for a production-grade solution because it does not take into account unavailability of the consumed Web service, or any other failures.
Adding Exception Handling
We will now add exception handling to our simple example of consuming a Web service to make it fault-tolerant and robust.
As defined by the SOAP specification, Web services communicate failures through fault messages. This is a well-documented and widely used mechanism that is required for a Web service to be considered SOAP-compliant. A fault can be anything that goes wrong, from infrastructure-level issues such as object creation failure to application-level errors such as failure to meet a business rule.
We can catch exceptions with the standard orchestration mechanism of using a Scope shape and adding an exception handler to catch the exception. The Scope shape must be either a long-running transaction or nontransactional.
Figure 2 Handling exceptions
If you want to retrieve SOAP protocol-specific information, such as the Actor, you can do so by adding a reference to System.Web.Services to your project and catching exceptions of type System.Web.Services.Protocols.SoapException.
For example, to create an entry in the Application event log that contains the message of the exception (as returned by the Web service that threw the exception), the Log SOAP Exception expression shape in the preceding figure could contain this code, assuming that the name of the exception object is "SOAPException":
It is important to note that there is no new underlying infrastructure required to support publishing BizTalk orchestrations as Web services. The BizTalk Web Services Publishing Wizard is a code-generation process that creates a standard C# Web service project. Everything that .NET developers know from creating .NET Web services applies here, from assigning application pools to adding SOAP extensions.
As stated earlier, this white paper does not address WSE 2.0.
How to Expose an Orchestration as a Web Service
There are two ways to launch the BizTalk Web Services Publishing Wizard: from the Start menu entry or from the Tools menu in Visual Studio. If the project you want to publish is the current project in Visual Studio, then launching the wizard from the Tools menu prepopulates the assembly location for you.
After you select an assembly, the wizard looks through it for schemas and orchestrations. Orchestrations containing public ports are listed on the wizard screen. Note that the default type modifier (which controls visibility) for port types is "Internal". You need to change this to "Public" for any ports that you wish to expose as Web services. These ports are published as Web methods, and the messages they send and receive are published as types. Note that you can change the type modifier of an existing port by changing the property in the Port Types node of the Orchestration View.
The SOAP protocol defines an extensibility mechanism whereby you can add SOAP headers to a message. This allows you to send additional information, such as a security token, with a message without modifying the content of the message. In addition, you can specify whether the headers must be understood, meaning that if a message arrives with an unexpected header then it should be treated as a failure and a SOAP fault should be returned. The publishing wizard includes a mechanism for both adding additional headers and specifying whether unexpected headers should be permitted.
When the wizard completes, the final screen gives you a link to the C# project that has been created. Note that you only need to do this generation process if the orchestration ports or schemas change. You can modify the orchestration and redeploy it, and as long as the public interface has not changed you do not need to regenerate the Web service.
The wizard process also generates the appropriate virtual root for your Web service, and the virtual root is configured for the default application pool. A best practice is to create a minimal permission application pool and assign your generated Web services to that pool. If your process is long running and synchronous, you may need to adjust the time-out of the service. For standard ASP.NET Web services you do this by setting the executionTimeout attribute of the httpRuntime element in the Web.config file.
Adding Fault Messages
Earlier in this white paper we saw how to detect and react to faults raised by Web services we consumed. To be a SOAP protocol-compliant service, we need to be able to report any faults back to the client that called us, and to do so in a manner that conforms to the SOAP protocol.
The framework does most of the hard work for us. We simply need to provide a fault message, and it is serialized and returned to the client as a standard SOAP fault. The steps required to implement a SOAP fault are:
Create a fault message
Add a fault message to the operation of the request/response port that is exposed as a Web service
Return the fault message in the event of an error condition
The fault message can be either a complex type or a simple string. Which one you choose depends on the needs of your particular solution. If all you need to do is return a simple message, then create a new message and instead of choosing a schema as the message type, choose System.String. If you need to return more comprehensive information as the fault detail, then specify a message schema. You can map and assign values to your fault message just as you would to any normal message. The content of the message is automatically serialized for you.
An orchestration that can return a SOAP fault when exposed as a Web service might look as shown in the following figure.
Figure 3 Returning a fault message
How to Create an Untyped Web Service
Normally, everything in BizTalk Server 2004 is strongly typed. When you create a receive port in an orchestration, you specify the type of the message being received.
There are, however, cases where you may want to receive multiple types of documents at a single endpoint. Consider the case of a supplier exposing a Web service that its partners can use for multiple purposes: to submit orders, send order change requests, and send cancellations. If these are all different schemas, as likely would be the case, then you need to create multiple endpoints. An alternative approach would be to have a single Web service receive documents, and then use the BizTalk Server publish/subscribe mechanism to route the received documents to the appropriate subscriber based on the type of document received.
The following steps are required to implement this approach:
Create a dummy orchestration that receives a message of type System.Xml.XmlDocument. Make sure that the port is Public so that the Web Services Publishing Wizard can expose it.
Run the Web Services Publishing Wizard, accepting all the defaults, specifying that you want BizTalk Server to create the ports, and granting it Anonymous access. (After you run the wizard, you no longer need the dummy orchestration. You only created it to have the publishing wizard generate the Web service project.)
Create additional orchestrations that receive a message of a known type, such as Order, Cancellation, and Order Change.
In the additional orchestrations created above, set the activating Receive shape's filter to only accept messages of the type you want to receive (for example, BTS.MessageType == "http://GenericXmlDocWS.Invoice#Invoice"). Note that if you do not do this, all documents received by the Web service are processed by all of the orchestrations bound to the Web port.
Build and deploy the project.
Bind the receive port of the additional orchestrations to the Web port that was created when you published the dummy orchestration.
Set the receive location to use the XmlReceive pipeline, so that the incoming document is identified.
To make this work, you need to make a slight code change to the generated Web service. (This is true up to and including BizTalk Server 2004 Service Pack 1, the current version when this paper was written.) Open the project and locate:
string bodyTypeAssemblyQualifiedName = "Microsoft.XLANGs.BaseTypes.Any, Microsoft.XLANGs.BaseTypes, Version=188.8.131.52, Cult" + "ure=neutral, PublicKeyToken=31bf3856ad364e35";
And change it to:
string bodyTypeAssemblyQualifiedName = string.Empty;
You can start the orchestration. You can submit any XML document to the Web service, but if it is of type Order then it is identified and routed to the appropriate orchestration.
So far we have looked at Web services only from an orchestration point of view. However, as BizTalk Server developers know, it is possible to build solutions based solely on the messaging engine, without using any orchestrations. Messaging-based solutions use content-based routing to route messages on the content of the message, the values of message context properties, or some combination of those two. Although messaging-only solutions do not allow you to inject business processes into a solution the way you can with orchestrations, you can apply maps and use custom pipelines, which in many cases is all you need to do.
To expose a messaging-only solution through Web services, you need a way to directly submit messages to the BizTalk MessageBox database. The message type needs to be determined when a message is put into the MessageBox so that BizTalk Server can identify subscribers to that message. This brings us to the second option of the Web Services Publishing Wizard, the option to publish schemas as Web services.
The way this works is similar to the act of exposing an orchestration as a Web service. You run the Web Services Publishing Wizard, it collects relevant information, and then it generates a proxy project. As was the case with publishing an orchestration, the proxy is a standard C# Web service application.
How to Expose a Schema as a Web Service
When publishing schemas as Web services with the Web Services Publishing Wizard, you see many of the same pages as when publishing an orchestration, but there are differences.
The following figure shows the wizard screen where you describe your Web service.
Figure 4 Web service description screen
The typical steps you follow to describe a Web service that can receive a document and return a response are:
Right-click and rename the BizTalkWebService node to something meaningful. This becomes the name of the WSDL file.
Right-click and rename the WebMethod1 node to something meaningful. This becomes the name of the exposed Web method.
Right-click the Request node, specify a DLL, and select a schema from the DLL that represents the document you will receive.
Right-click the Response node, specify a DLL, and select a schema from the DLL that represents the document you will return to the caller.
As was the case with publishing orchestrations, the properties screen allows you to specify a namespace URI, support for unknown headers, and whether to support Single Sign-On.
The Web service project screen allows you to specify what the proxy project should be named, where it should be located, whether anonymous access is permitted, and whether to automatically create the receive locations. Note that if you do not create the receive locations here, you will subsequently need to do so manually.
This section provides additional information about working with BizTalk Server 2004 and Web services.
Working with SOAP Headers
The SOAP protocol allows you to attach information to the message header. This is information that travels with the message, but is not part of the content. The following are examples of where you might want to use SOAP headers:
A system requires you to log on, and assigns a session identifier that must be part of each subsequent message in the conversation
You need to attach user credentials to a message
Data in the header enables use of network appliances that can route messages based on header information, without needing to understand the message itself (which could be completely or partially encrypted)
You want to use header information to determine processing priority (for example, silver, gold, platinum customers) and route messages accordingly
With BizTalk Server, headers can be accessed when:
Consuming a Web service
Publishing an orchestration as a Web service
Publishing a schema as a Web service
The fact that headers are present, and whether they are required, is expressed as part of the WSDL file that the Web service publishes. Headers are optional. In the case of a request-response message pattern, headers are accessible for both the request and response messages.
When you run the publishing wizard, you specify the SOAP headers that you support for both the request and response messages. Each header type is defined by specifying a schema. You can also choose to support unknown headers, in which case any unknown SOAP headers received as part of a request are added to a SOAP.UnknownHeaders context property of the message.
If headers are received that include the mustUnderstand attribute, the Web service always returns that they were understood.
Tips for Consuming Web Services
The following are useful points to be aware of when you are consuming Web services:
BizTalk Server 2004 does not support array parameter types. If you have control over the Web service you are consuming, you can change it to instead receive/return complex objects. For example, in .NET, create a class and use an instance of that as the parameter or return value. If you do not have control over the Web service, you can write a .NET helper class that interacts with it. In addition, the WSE 2.0 adapter supports calling methods that return arrays of complex types.
BizTalk Server 2004 does not directly support messaging-only solutions that accept a message coming in and route it to a Web service. However, you can achieve the same result by writing a pipeline component or custom adapter to interact with the Web service. In addition, the WSE 2.0 adapter supports content-based routing without orchestrations.
Under high stress the SOAP send handler for solicit-response should be placed in its own host. Otherwise the orchestration puts priority on sending SOAP requests and dehydrates the orchestrations while waiting for the SOAP responses to return through the MessageBox. Even when these responses return, the host is still too busy sending SOAP requests and dehydrating schedules to find time to rehydrate orchestration schedules so that they can pick up the SOAP responses. This is extremely important because you may see significant slowness in SOAP solicit-response under high loads due to this behavior. Adding a separate send host that is dedicated to SOAP send processing mitigates this performance bottleneck.
Tips for Publishing Web Services
The following are useful points to be aware of when you are publishing Web services:
For publishing orchestrations as Web services, the documentation contains useful information about how to enable tracing and report detailed error messages. See "Debugging Published Web Services" in BizTalk Server 2004 Help.
Make sure that an Isolated Host process exists. HTTP and SOAP adapter receive handlers must run in an Isolated Host because they are outside of the BizTalk process, which is hosted in Internet Information Services (IIS). Only one adapter can run in an Isolated Host, so if you are using both HTTP and SOAP adapters you need to create an Isolated Host for each.
If your SOAP send port accesses Web services through a firewall, be sure to specify proxy server information. You can do this either at the adapter level or on the send port itself (see the "proxy" tab of the address).
There are flags that can be set to enable reporting of more detailed SOAP and security error information from an orchestration exposed as a Web service. For more information, see "Debugging Published Web Services" in BizTalk Server 2004 Help.
Microsoft Windows Server 2003 security is locked down tighter than it was in Microsoft Windows 2000. The identity of the application pool under which the Web service runs needs to be a member of the IIS_WPG and BizTalk Isolated Hosts Users groups.
If you want to publish an orchestration as a Web service that exposes simple data types (for example, a single string request parameter and a Boolean response), create messages in the orchestration that are of that type and send/receive them in the port (in the example, have a request that is of type System.String and a response that is System.Boolean).
If you are not getting the results you expect, remember to check the event log.
Although it is easy to work with Web services and BizTalk Server, you do need to build several technology links in the chain. If any of these links is broken, then the entire process may fail. The BizTalk Server documentation includes comprehensive troubleshooting information that can help you diagnose common failure causes.
The most successful approach to developing Web service-based solutions built on BizTalk Server is to proceed in a systematic and unit-based manner. Build a test harness to make sure that a consumed Web service works, make sure the orchestration works as expected before exposing it as a Web service, and so on. If you follow a methodical and systematic development approach, you will be successful and you will benefit from the advanced capabilities BizTalk Server brings to Web services solutions.
Debugging Checklist for Orchestrations Published as Web Services
You can use the following checklist to debug issues with orchestrations that have been exposed as Web services running on Windows Server 2003.
First, isolate the problem. Is it a problem in IIS or BizTalk Server?
Debugging IIS Problems
Check the Application event log.
IIS hosts the SOAP receive adapter, and changes to receive ports and receive locations do not take effect immediately, but rather are subject to the Cache Refresh interval specified for the BizTalk group. Run IISRESET to restart the service and flush the cached settings.
Check the application pool for the generated Web service in the IIS manager MMC snap-in. Is it the application pool you have set up for BizTalk Web services?
Check the identity under which the application pool is running. Is it a member of the IIS_WPG and BizTalk Isolated Host Users groups? These two groups give the ASMX page (the proxy Web service that the BizTalk Web Service Publishing wizard generated) the appropriate rights to insert the SOAP request message into the BizTalk MessageBox in SQL Server that will then launch the orchestration. Symptom may be "SoapException: Internal SOAP Processing Failure".
Make sure the user account for the application pool has read/write permissions on the %temp% folder. This is the folder where the ASMX is just-in-time (JIT) compiled into a DLL with a random eight-character name (xxxxxxxx.dll). Symptom may be "SoapException: Internal SOAP Processing Failure".
Using the IIS MMC snap-in, can you "Browse" the ASMX file?
If you did not specify anonymous access to your Web service when you ran the publishing wizard, you can temporarily allow anonymous access by using IIS (properties of the ASMX file) to eliminate invalid credentials as a point of failure.
Make sure your Web service test client is sending credentials in the SOAP method call, because in Windows Server 2003 by default the virtual directory requires Windows authentication (unless you selected the "Allow Anonymous Access" check box when you ran the publishing wizard). When you test the Web service using Internet Explorer you are using your own logon credentials, which is why it works. If your test client does not add credentials to the SOAP method call you will get a SOAP exception due to security issues. Windows Server 2003 gives you very little information about this unless you enable additional debugging/tracing. The other option is to allow only anonymous access to the Web service, but again be careful and test it because anonymous access runs with a default identity that also has to be in the IIS_WPG and BizTalk Isolated Host Users groups, and may need access to read/write in the %temp% folder.
The BizTalk Server documentation lists the following three ways in which you can see tracing information as well as more extensive error details:
Use the ThrowDetailedError Switch for the published Web service web.config file
Enable SOAP Message Tracing
- Use the ThrowDetailedError Switch for the published Web service web.config file
Debugging BizTalk Server Problems
In Health and Activity Tracking (HAT), look at the Recent Services Instances. Did your message arrive?
Does the URI in the receive port match the URI of the Web service?
Is the orchestration started? Having the orchestration bound and enlisted is not enough. It must be started so that the Web service has a place to submit it to. If the orchestration is not started, you will receive a "SoapException: Internal SOAP Processing Failure" error.
Are the receive locations bound to your orchestration enlisted, and are the send ports bound to it started?
No discussion of how Web services relate to BizTalk Server would be complete without mentioning InfoPath, the newest member of the Microsoft Office suite of products. InfoPath is Microsoft's answer to the electronic forms question. It allows bundling XML data and presentation information in a single package, and provides a rich form development environment. An XML processing instruction can be added to an XML document to associate it with an InfoPath form, so that double-clicking the document shows the data in that form. Note that InfoPath is a client-side application, and as such needs to be installed on the computers that will be rendering the forms.
InfoPath is based on open-standards XML, and it uses standard XSD schemas for the XML data it renders, just as BizTalk Server uses XSD schemas. One facet of InfoPath that will interest BizTalk Server developers is the ability to create new forms based on a Web service. This means that you can create a BizTalk orchestration, run the Web Services Publishing Wizard, and use InfoPath to create an input form that can submit data to the Web service—all without writing any code. This is a quick and easy way to construct data input points while developing applications.
A common usage pattern for InfoPath is the case of messages that require human intervention. You can deposit the message in question into a file folder (or Windows SharePoint Services), users can make any edits or required approvals, and upon submission the form can be posted to a Web service created by the Web Services Publishing Wizard that returns the data into an orchestration's receive location.
The use of service-oriented architectures is currently the preferred approach to application design, and Web services can be a key enabler of SOA. BizTalk Server supports Web services in a native and intuitive manner for developers. This white paper has shown how BizTalk Server provides the building blocks required to build robust and agile business-critical applications using Web services.
Based in San Diego, Brian Loesgen is a Principal Consultant with Neudesic, a firm that specializes in .NET development and Microsoft server integration. Brian is a Microsoft MVP for BizTalk Server 2004. He has over 18 years of experience in building advanced enterprise and mobile solutions. He is a co-author of six books, including "BizTalk Server 2004 Unleashed," and has written technical white papers for Intel, Microsoft, and others. Brian has spoken at numerous major technical conferences worldwide. He is a co-founder and President of the International .NET Association (ineta.org). He is the President of the San Diego .NET user group, leads the San Diego Software Industry Council Web Services SIG, and is a member of the Editorial Board for the .NET Developer's Journal. Brian is also a member of the Microsoft BPI Virtual Technical Specialist Team. His blog can be found at blogs.ineta.org/bloesgen.