# ConversationClient.asmx.cs Sample

This topic inludes the source code for the ConversationClient.asmx.cs Sample.

## Sample Location

This sample is located in the following directory in your WebLogic Workshop installation:

BEA_HOME/weblogic81/samples/workshop/SamplesApp/WebServices/interop/dotNET/

## Sample Source Code

`001 using System; 002 using System.ComponentModel; 003 using System.Diagnostics; 004 using System.Web.Services; 005 using System.IO; 006 007 namespace test 008 { 009 /// <summary> 010 /// This is an example of a .NET web service that is a client of 011 /// a WebLogic Workshop web service. The target web service, 012 /// samples/async/Conversation.jws, is conversational and optionally 013 /// uses callbacks. This client is fully capable of paticipating in 014 /// conversations with Conversation.jws and can also receive callbacks. 015 /// </summary> 016 017 /* 018 * This Namespace declaration is required to cause the callback 019 * handler (onResultReady) to be in the proper namespace. Ideally, 020 * we could set the namespace on a per-method basis, but .NET doesn't 021 * appear to allow that. 022 */ 023 [WebService(Namespace="http://www.openuri.org/")] 024 public class ConversationClient : System.Web.Services.WebService 025 { 026 027 public ConversationClient() 028 { 029 //CODEGEN: This call is required by the ASP.NET Web Services Designer 030 InitializeComponent(); 031 } 032 033 #region Component Designer generated code 034 035 //Required by the Web Services Designer 036 private IContainer components = null; 037 038 /// <summary> 039 /// Required method for Designer support - do not modify 040 /// the contents of this method with the code editor. 041 /// </summary> 042 private void InitializeComponent() 043 { 044 } 045 046 /// <summary> 047 /// Clean up any resources being used. 048 /// </summary> 049 protected override void Dispose( bool disposing ) 050 { 051 if(disposing && components != null) 052 { 053 components.Dispose(); 054 } 055 base.Dispose(disposing); 056 } 057 058 #endregion 059 060 /* 061 * start invokes the Conversation web service's startRequest 062 * operation. 063 * 064 * Since the Conversation web service is conversational, 065 * we must also prepare a SOAP header containing a conversation ID. 066 * 067 * Since the Conversation web service can optionally communicate 068 * the result of it's work via a callback, we must prepare a 069 * second SOAP header containing the "callbackLocation", which is 070 * the URL of the recipient to which callbacks should be sent. 071 */ 072 [WebMethod(EnableSession=true)] 073 public void start(Boolean useCallbacks, Boolean useIPAddress) 074 { 075 /* 076 * The Conversation proxy was created using .NET's wsdl.exe 077 * application and the Conversation.jws's WSDL file. The WSDL 078 * file for any WebLogic Workshop web service may be obtained 079 * by hitting the web service's URL with "?WSDL" appended to 080 * the end. For example: 081 * 082 * http://somehost:7001/samples/async/Conversation.jws?WSDL 083 * 084 * wsdl.exe produces a C# proxy class. Place the resulting 085 * Conversation.cs file in your .NET project, then use Visual 086 * Studio's Project->Add Existing Item menu action to "import" 087 * the class into the project. 088 */ 089 Conversation conv; 090 String conversationID; 091 String callbackLocation; 092 int asmxIndex; 093 094 /* 095 * Construct the callback location from various pieces of 096 * server and HttpRequest info. 097 */ 098 Uri requestUrl = Context.Request.Url; 099 100 if( useIPAddress ) 101 { 102 /* 103 * if useIPAddress is true, construct the callbackLocation 104 * with the IP address of this host. 105 */ 106 callbackLocation = requestUrl.Scheme + "://" + 107 System.Net.Dns.GetHostByName(Context.Server.MachineName).AddressList[0] + 108 ":" + requestUrl.Port + requestUrl.AbsolutePath; 109 } 110 else 111 { 112 /* 113 * if useIPAddress is false, construct the callbackLocation 114 * with the hostname of this host. 115 */ 116 callbackLocation = requestUrl.Scheme + "://" + 117 Context.Server.MachineName + 118 ":" + requestUrl.Port + requestUrl.AbsolutePath; 119 } 120 121 // Remove everything after ".asmx" 122 asmxIndex = callbackLocation.IndexOf(".asmx") + 5; 123 callbackLocation = callbackLocation.Remove(asmxIndex, 124 callbackLocation.Length - asmxIndex); 125 126 /* 127 * Make up a conversation ID for this conversation. It must 128 * be guaranteed unique across all converations on the target 129 * web service's server. 130 * 131 * Here we use a string composed of the current process ID 132 * and the current date and time. That's not completely 133 * reliable since this client could possibly start two 134 * conversations within the space of a second (the resolution 135 * of DateTime.ToString()). 136 */ 137 conversationID = Process.GetCurrentProcess().Id + " - " + 138 DateTime.Now.ToString(); 139 140 /* 141 * Create an instance of the proxy for the Conversation 142 * web service. 143 */ 144 conv = new Conversation(); 145 146 /* 147 * Construct a conversation start header and set conversation ID 148 * and callback location. 149 */ 150 conv.StartHeaderValue = new StartHeader(); 151 conv.StartHeaderValue.conversationID = conversationID; 152 conv.StartHeaderValue.callbackLocation = callbackLocation; 153 154 /* 155 * Persist the conversationID in session state so that it can 156 * be used in other methods that take part in the conversation. 157 * 158 * This is not safe since one session could start multiple 159 * conversations, but there is no other apparent way to persist 160 * this information. Member variables of WebService classes 161 * are not persisted across method invocations. 162 */ 163 Session["ConversationID"] = conversationID; 164 165 /* 166 * Invoke the startRequest method of the web service. The 167 * single boolean parameter determines whether the Conversation 168 * web service will use callbacks to communicate the result 169 * back to this client. 170 * 171 * If the argument is true, an onResultReady callback will 172 * be sent when the result is ready. This client must implement 173 * a method with that name that expects the message shape defined 174 * by the target web service (returns void and accepts a single 175 * string argument). See the onResultReady method below. 176 * 177 * If the argument to startRequest is false, callbacks will not 178 * be used and this client must use the getRequestStatus method 179 * to poll the Conversation web service for the result. 180 */ 181 conv.startRequest(useCallbacks); 182 } 183 184 /* 185 * getStatus invokes Conversation's getRequestStatus method. 186 * getRequestStatus is a polling method that is an alternative 187 * for web services that cannot recieve callbacks. 188 * 189 * Note that a conversation must be started with startRequest before 190 * this method may be invoked. If not, or if this method is invoked 191 * outside of a conversation for any reason, it will get back a SOAP 192 * fault indicating that the conversation does not exist. 193 */ 194 [WebMethod(EnableSession=true)] 195 public String getStatus() 196 { 197 String result; 198 199 /* 200 * Create an instance of the proxy for the Conversation 201 * web service. We could probably persist the proxy instance 202 * in session state, but chose not to. 203 */ 204 Conversation conv = new Conversation(); 205 206 /* 207 * Construct a conversation continue header and set the 208 * conversation ID to the one we cached on session state in 209 * the start method. 210 */ 211 conv.ContinueHeaderValue = new ContinueHeader(); 212 conv.ContinueHeaderValue.conversationID = (String)Session["ConversationID"]; 213 214 /* 215 * Invoke the getRequestStatus method of the web service. 216 */ 217 result = conv.getRequestStatus(); 218 return result; 219 } 220 221 /* 222 * finish invokes Conversation's terminateRequest method, which 223 * terminates the current conversation. 224 * 225 * Note that a conversation must be started with startRequest before 226 * this method may be invoked. If not, or if this method is invoked 227 * outside of a conversation for any reason, it will get back a SOAP 228 * fault indicating that the conversation does not exist. 229 */ 230 [WebMethod(EnableSession=true)] 231 public void finish() 232 { 233 /* 234 * Create an instance of the proxy for the Conversation 235 * web service. We could probably persist the proxy instance 236 * in session state, but chose not to. 237 */ 238 Conversation conv = new Conversation(); 239 240 /* 241 * Construct a conversation continue header and set the 242 * conversation ID to the one we cached on session state in 243 * the start method. Both "continue" and "finish" methods 244 * use the same SOAP header format. 245 */ 246 conv.ContinueHeaderValue = new ContinueHeader(); 247 conv.ContinueHeaderValue.conversationID = (String)Session["ConversationID"]; 248 249 /* 250 * Invoke the terminateRequest method of the web service. 251 */ 252 conv.terminateRequest(); 253 } 254 255 /* 256 * onResultReady is a callback handler for the onResultReady 257 * callback that Conversation.jws can optionally use to return 258 * its results. 259 * 260 * .NET does not support callbacks directly, but a callback is just 261 * a method invocation message. So if you construct a WebMethod with 262 * the same signature as the callback and set the XML namespace 263 * properly, it serves as a callback handler. 264 * 265 * The namespace of this entire WebService is set to match that 266 * required by the callback ("http://www.openuri.org/") using the 267 * [WebService(Namespace=...)] attribute at the top of this file. 268 * Ideally we could set the namespace on a per-method basis, but 269 * .NET doesn't appear to allow that. 270 */ 271 [WebMethod] 272 public void onResultReady(String result) 273 { 274 /* 275 * When the callback is invoked, log a message to the 276 * hardcoded file c:\temp\ConversationClient.log. 277 * 278 * Note: if c:\temp does not exist on this server, an 279 * Exception will be raised. Since it is not handled here, 280 * it will be returned as a SOAP fault to the Conversation 281 * web service. 282 */ 283 TextWriter output; 284 output = File.AppendText("c:\\temp\\ConversationClient.log"); 285 String msg = "[" + DateTime.Now.ToString() + "] callback received"; 286 output.WriteLine(msg); 287 output.Flush(); 288 output.Close(); 289 } 290 } 291 }`