WebLogic and .Net: Building a Web Service
Your company wants to build Web services, but you've got a heterogeneous computing environment. Find out how you can achieve true interoperability
by Heinrich Gantenbein

Posted June 25, 2004

It didn't take long for the major software vendors to realize that none of them would dominate the enterprise platform market. Thus interoperability became a necessity.

The software industry has attempted interoperability with various technologies (see sidebar "A Brief History of Interoperability.") However, one shortcoming of these efforts was that they pretended that you could treat remote objects the same as local objects, which just isn't the case. Additionally, parameter type compatibility would imply semantic compatibility and no provisions were made to allow systems to be composed of building blocks for service level agreements (SLAs). So something more was needed.

Then Extensible Markup Language (XML) emerged as a data expression language, and a more service-oriented architecture for software development was born. These developments lead to Simple Object Access Protocol (SOAP), Web services, and all of the WS-* standards. Additionally, the Web Services Interoperability (WSI) organization was created to ensure compliance to the standards. The major industry players (including BEA and Microsoft) embrace standardized XML and SOAP-based Web services. Does this mean that true interoperability is possible today?

Follow us as we show how you can build a Web service using Microsoft .Net and BEA WebLogic in a standards-compliant way. Let's start with some service-oriented architecture (SOA) basics.

SOAs and Web Services
SOAs implemented as Web services are fundamentally different from object-oriented architectures (like CORBA and Java RMI). They are also different from component-oriented technologies such as COM and DCOM. COM+ and J2EE session beans exhibit some elements of SOAs, such as loose coupling, SLAs, and SLA composition.

Service-oriented architectures require that all contracts be validated, either structurally and semantically with schemas (XML Schema Definition [XSD]), Web Service Definition Language (WSDL), and Business Process Execution Language for Web Services (BPEL4WS), or with SLAs through WS-Policy and related standards.

Web services may be composed of other Web services, and Web service SLAs may be composed of other multiple policies. Web services also are standards-based and must be loosely coupled, which means they are message-based and platform-independent. Failure scenarios are expected.

The access to Web services is coarse-grained because of the potential cost of a round trip. No access to individual fields in the "object" is allowed, and Web services have few interface methods with large amounts of data.

Figure 1 shows an overview of today's Web services standards. These standards are changing rapidly.

Project Overview
BEA Systems hired IDesign (a .Net architecture consulting and training company) to study how .Net and WebLogic interoperate in a standards-compliant way. The project reuses an implementation of chapter 1 from BEA WebLogic Platform 8.1 Evaluation Guide—a reference application for evaluating WebLogic 8.1. In the chapter, the developer is guided in developing a Web application and set of Web services for the fictitious company Avitek, which sells cameras and accessories (see Figure 2). The architecture for the Avitek application in WebLogic is depicted in Figure 3. As a comparison, the .Net version architecture is shown in Figure 4. The purpose of this study is to:

  • Show that true interoperability between Workshop and .Net with Web services is a reality today
  • Prove that it can be done in a secure manner
  • Provide Microsoft and BEA programmers with a practical guide to Web services interoperability
  • Show how Visual Studio .Net and WebLogic Workshop provide highly productive environments to achieve this interoperability
  • Suggest best practices and highlight tips, tricks, and pitfalls
  • Venture a guess about the future of interoperability.

One note before getting started: BEA's Workshop, WebLogic Server, and Visual Stuidio.Net 2003 are all power user applications. To achieve acceptable performance, your development workstation should have 1 GB of RAM.

Mixed-Environment Application
The Avitek application contains a smart client using .Net WinForms. This client calls a synchronous version of the order entry Web service in WebLogic 8.1 with SSL transport security and WS-Security for the username and password. The PricingService in the Workshop version has been replaced with a call to an ASP.Net-hosted Web service. This leads to the architecture shown in Figure 5.

For interoperability to be a reality in this project, we followed some general guidelines. We used standard Web services (.Net to WebLogic or WebLogic to .Net). We used "Document" style SOAP between WebLogic and .Net. (It is the standard for both environments.) We maintained security by using SSL for privacy (encryption), and a WS-security username/password token without signing the message. Finally, we disabled MustUnderstand (which is used for routing headers in .Net clients; at the time of this writing, WebLogic does not know how to handle the routing headers in Microsoft's Web Services Enhancement [WSE]).

Now take a closer look at these aspects.

.Net to WebLogic. Consuming WebLogic-hosted Web services from .Net applications is trivial. You just add a Web reference to your .Net application. A wizard guides you through the process (copy the URL for the WSDL from Workshop's test browser). Next instantiate the proxy class for the Web service (VS.Net creates the proxy class when adding a Web reference) and call the method(s).

WebLogic to .Net. Consuming ASP.Net-hosted Web services from WebLogic applications is equally trivial. You add a Web service control (.jcx) to your WebLogic client application. A wizard guides you through the process (copy the URL for the WSDL from VS.Net's test page). Next use the control (Workshop adds the instantiation) to call the service's method(s).

Document- versus RPC-style Web services. .Net and WebLogic use document-style SOAP by default. BEA can consume and produce RPC-style SOAP; however, there is no need to do this unless you have an external requirement when calling a platform unable to support document literal encoding.

SSL for security. SSL works well for data privacy. However, you need a real certificate. The test certificate distributed with BEA's platform is great for testing BEA to BEA applications. However, .Net does not like this certificate. A work-around has been posted on www.interopwarriors.com.

WS-Security and policy files. X509-based signatures and encryption are not interoperable. SSL is still the best choice for privacy. WS-Security with username token (contains a username and password) interoperates if you use WSE 1.0; however, you must set the MustUnderstand flag for the routing header to "false" and avoid adding a username based signature. Policy files are not interoperable yet. You must manually translate them. This project contains the policy files for both environments; therefore a simple copy and paste should be enough.

At the time this article was written, we could not use X509 signing and encryption. A patch should be available from BEA by the time this article goes to print. Although the standards are still in flux, policy files should be interoperable in the near future, as well. At that point, Web services will be able to negotiate the desired protocols without intervention.

Asynchronous Web services, which are just SOAP messages bound together with a coordination ID, are considered by many the future for loosely coupled interoperable Web services. BEA supports this through WS-Conversation, although WS-Conversation is not standardized. For .Net, Microsoft recommends using .Net's built-in asynchronous invocation while using a request/response pattern on the wire. WS-Addressing and WS-BusinessActivity will replace these proprietary implementations. (Note: The names of the WS standards are still changing.)

The Implementation
Let's go through the project step-by-step. We used the Avitek example from chapter 1 of the BEA WebLogic Platform 8.1 Evaluation Guide. (Alternatively, you can start with Chapter 2 of the project, which contains the completed Chapter 1 source code. For a list of the included technology, see the sidebar "Technology Stacks.")

The first step is to create, in Visual Studio.Net, an empty solution AvitekInterop to contain the two projects required and any test projects.

Call a WebLogic 8.1 Web service from .Net 1.1. Begin by adding a new Web service OrderEntryWebService2 (right-click on Avitek/webServices/orderEntryInterface). Alternatively, you could modify the existing OrderEntryWebService; however, if you make a mistake you will lose the working copy. Next add control "Avitek Order-Entry Service" from Avitek Controls (right-click on darker section in the designer and select Add Control).

Now, add a getAllProducts Web method (WebLogic), which allows the Windows smart client to retrieve a product catalog. Do this by dragging the OrderEntryService method getAllProducts from the Data Palette. Then modify the name of the function to getProductCatalog. Add an XML schema file to /Avitek/Schemas named ProductCatalog.xsd (see Listing 1).

This data set hides the Avitek private data from the outside world. Now map this data to the internal data by right clicking on the getProductCatalog method in the Web services designer, then selecting Edit XML Schema. Click on the Return XML tab, click Choose, and find and select ProductCatalog.xsd in the list. Click OK, then click Edit XQuery. Now draw data mapping as shown in Figure 6. Accept by clicking OK on both dialog boxes, then test your Web service (you should see the new type returned from getAllProducts).

BEA calls this loose coupling and it is great for interoperability. If you have predetermined external schemas, this method allows a simple way of adapting your application's API.

Now we need to add a createOrder Web Method (WebLogic), which allows the Windows smart client to create an order. Add this by dragging the OrderEntryService method createOrder from the Data Palette.

Next, you'll modify the function to use a hard-coded customer ID (instead of the parameter):

public java.lang.String createOrder(
	OrderEntryServiceFolder.OrderInfo order) 
{ 
	int customerID = 1; 
	return orderEntryService.createOrder(
	customerID, order); 
} 

Now let's build a .Net smart client to consume OrderEntryWebService2. Use VS.Net 2003 to build a Windows application client named AvitekOrderEntryUI. You may also use VB.Net or C#. We used VB.Net for the Windows client and C# for the PricingService later on.

Next, fix the default generated names (good coding practice). Rename the default Form1.vb to WinUI.vb and replace Form1 with WinUI in code (two occurrences). Change the startup object in project property dialog to WinUI and change the form label to Avitek Order Entry Smart Client.

Add a dataset (OrderEntryDataset.xsd) for data binding to the order entry data grid (see Figure 7). Add this dataset to the design view of WinUI.vb by dragging a dataset control from the Toolbox tab Data. Then accept the choice (AvitekOrderEntryUI.OrderEntryDataset) in the Add Dataset dialog box by clicking OK.

Add a DataGrid to the form by dragging a DataGrid control from the Toolbox tab Windows Forms. Size it and change the name to m_OrderEntryDataGrid (in the property window). Set the CaptionVisible property to false, set the DataSource property to m_OrderEntryDataset, and set the DataMember property to OrderLine. Optionally, you can size the columns and disable editing of first three columns.

Now add the Submit Order! button below the DataGrid. Add a Web reference to the WebLogic-hosted Web service OrderEntryWebService2 by right-clicking on AvitekOrderEntryUI/References in the Solution Explorer. Select Add Web Reference… and start the OrderEntryWebService2 Web service in Workshop. Navigate to Overview (see Figure 8) and then to Complete WSDL (see Figure 9). Now copy the URL from address bar in Figure 9 and paste it into the URL field in VS.Net's Add Web Reference dialog box. Click on the Go button (a description page should be visible, see Figure 10). Change the Web reference name to AvitekWS (from localhost). This creates the namespace for the Web service. Click Add Reference, then add code to import the namespace:

Imports AvitekOrderEntryUI.AvitekWS 

Now add a form load handler by double-clicking from the canvas in the design view (creates Sub WinUI_Load) and adding the initialization code:

Dim catalog As ProductCatalogProduct() 
Dim orderWS As OrderEntryWebService2 
orderWS = New 
	AvitekWS.OrderEntryWebService 
'set real URL here 
'orderWS.Url = "" 
catalog = orderWS.getProductCatalog() 
m_OrderEntryDataset.Clear() 
For Each product As 
	AvitekWS.ProductCatalogProduct In catalog 
	OrderEntryDataset1.OrderLine.AddOrderLine
	Row(product.ID, product.Description, 
	product.UnitPrice, 0) 
Next 
M_OrderEntryDataset.AcceptChanges() 

Add the Submit Order! button handler by double-clicking the button in the design view (creates Sub SubmitButton_Click). Then add the code shown in Listing 2 to handle the submit request. Now it's time to test your application.

Kicking the Tires
Let's see what it's like calling a .Net Web service from WebLogic. The first step in calling the .Net Web service is to build the PricingService in .Net. PricingService is a binary distributed Enterprise JavaBean (EJB) in BEA's evaluation guide. For this implementation you will discontinue using it and consume a .Net Web service instead.

To add a new Web service project in VS.Net named AvitekPricingService:

  • Select File -> New -> Project
  • Select Visual C# Projects
  • Select ASP.Net Web Service
  • Name the project AvitekPricingService
  • Fix default Service1 by renaming it PricingService (PricingService.asmx and all references in code).

Add the code shown in Listing 3 to implement GetDiscountRate.

Now you need to modify the BEA Avitek project to consume the .Net Web service. Start by opening OrderEntryServiceImpl.jcs in Design View and removing the existing pricingControl. Next add a control for the .Net-based Web service by right-clicking on the canvas for OrderEntryService Java Control and selecting Add Control -> Web Service. Fill out the dialog box (see Figure 11) with these:

  • Variable name for this control: dotNetPricingService
  • Select "Create a new Web Service control to use."
  • New JCX name: DotNetPricingService
  • File or URL: http://localhost/AvitekPricingService/PricingService.asmx?WSDL
  • Click Create (see Figure 12)

.Net standard coding practice uses an initial capital letter for method names. Therefore, you need to change the calling code to use a capital G for getDiscountRate:

discountRate = 
	dotNetPricingService.GetDiscountRate(
	custID); 

Web Services Security
You need to specify the WS-Security requirement in the WebLogic project. The evaluation guide ships with a policy file preconfigured for an X509 message-level security. You will use username and password authentication instead. Change the policy file OrderEntryWebService2.wsse to require user name and password tokens instead:

<?xml version="1.0" ?> 
<wsSecurityPolicy xsi:schemaLocation=
	"WSSecurity-policy.xsd" 
	xmlns="http://www.bea.com/2003/
		03/wsse/config"
	xmlns:xsi="http://www.w3.org/2001/
		XMLSchema-instance"> 
	<!-- 
		Incoming SOAP messages must be 
		accompanied by a username and 
		password. 
	--> 
	<wsSecurityIn> 
		<token tokenType="username"/> 
	</wsSecurityIn> 
</wsSecurityPolicy> 

Change ws-security-service -> file property of OrderEntryWebService2 to AvitekWebServicePolicy2.wsse.

To use Microsoft WSE 1.0, exit VS.Net and install WSE 1.0 (see Resources). Modify the project to use WSE by adding a reference to Microsoft.Web.Services 1.0 and adding this app.config file:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
	<!-- Defines WSE version (1.0) for this 
	client application --> 
		<configSections> 
			<section name="microsoft.web.services" 
			type="Microsoft.Web.Services.
			Configuration.WebServicesConfiguration, 
			Microsoft.Web.Services, Version=1.0.0.0, 
			Culture=neutral, 
			PublicKeyToken=31bf3856ad364e35" /> 
		</configSections> 
	</system.net> 
</configuration> 

Regenerate the proxy class by right-clicking on the Web reference AvitekWS and selecting Update Web Reference. This creates two proxy classes: one each for a regular Web service and one for a WSE-enabled one.

Add import statements at the beginning of WinUI.vb:

Imports Microsoft.Web.Services 
Imports Microsoft.Web.Services.Security 

Next change all references to the Web service proxy from OrderEntryWebService2 to OrderEntryWebService2Wse in WinUI_Load and SubmitButton_Click:

Dim orderWS As OrderEntryWebService2Wse 
orderWS = New OrderEntryWebService2Wse 

Add code to attach the username token to the Web service call in WinUI_Load and SubmitButton_Click. You also have to disable the MustUnderstand SOAP header attribute for the path header:

'hard code user credentials for demo 
Dim userToken As UsernameToken 
Dim requestContext As SoapContext 
userToken = New UsernameToken(
	"jane", "janejane", 
	PasswordOption.SendPlainText) 
requestContext = orderWS.RequestSoapContext 
requestContext.Security.Tokens.Add(
	userToken) 
requestContext.Timestamp.Ttl = 60000
requestContext.Path.EncodedMustUnderstand = 
	"false" 

Now let's learn how to use the WS-Security header in the WebLogic project. The authenticated username is contained in the JwsContext. The username can be converted into an Avitek customer record. Add these import statements to the beginning of OrderEntryWebService2.jws:

import com.avitek.commerce.CommerceCustomer; 
import com.bea.control.JwsContext; 

Next, add a reference to the JwsContext at the beginning of the Web services class:

/** 
* @common:context 
*/ 
JwsContext context; 

Now replace this line in method createOrder (OrderEntryWebService2.jws):

int customerID = 1; 

with the bold lines:

public java.lang.String createOrder(
	OrderEntryServiceFolder.OrderInfo order) 
	{ 
	String customerName = 
		context.getCallerPrincipal().getName(); 
		CommerceCustomer customer = 
		orderEntryService.findCustomerByLogin(
		customerName); 
	int customerID = customer.getCustID(); 
	return orderEntryService.createOrder(
		customerID, order); 
} 

You can now enable SSL transport in the project, but this is optional. To do so, add these lines to web.xml (in folder Avitek/AvitekWeb/WEB-INF):

<web-resource-collection> 
	<web-resource-name>
		OrderEntryWebService2.jws
	</web-resource-name> 
	<url-pattern> 
		/webServices/orderEntryInterface/
		OrderEntryWebService2.jws/* 
	</url-pattern> 
	<http-method>GET</http-method> 
	<http-method>POST</http-method> 
</web-resource-collection> 

Add these lines to wlw-config.xml (in folder Avitek/AvitekWeb/WEB-INF):

<service> 
	<class-name>
		webServices.orderEntryInterface.
		OrderEntryWebService2
	</class-name> 
	<protocol>https</protocol> 
</service> 

OrderEntrywebService2 now uses SSL for all of its communications. WebLogic ships with a test SSL certificate, but this won't work with .Net. You must purchase a real SSL certificate or use a time-limited one from a certification authority. For more details see Lesson 1.7, Step B: Securing Web Services With Transport-Level Security in the WebLogic evaluation guide.

The last step is to change the URLs in the .Net Web services proxy classes (Reference.vb) to read https instead of http.

What We've Learned
Calling a WebLogic-hosted Web service from a .Net client is easy. BEA Workshop's schema mapping simplifies any schema adjustments required. In this project, private details of the product catalog were hidden through this mapping. Calling an ASP.Net-hosted Web service from a WebLogic client is equally easy. Each of these tasks takes minutes to complete. Achieving a secure calling environment is more difficult, but as we prove, WebLogic Workshop can interoperate with .Net.

About the Author
Heinrich Gantenbein is a solutions architect at Avanade specializing in .Net security, scalability, and multitier architectures. He is an expert in C#, VB.Net, enterprise services, and Java to .Net interoperability. Prior to Avanade, he was a principal software architect at .Net consulting company IDesign. Heinrich was named a BEA Technical Director in recognition of his work on interoperability and has just completed an advanced VB.Net book. Contact him at heinrichgantenbein@hotmail.com.