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 }
|