Christian Weyer shows how to host WSE’s SoapReceiver within EnterpriseServices. This came up while we were watching Keith Ballinger do a code-driven presentation on WSE messaging.
The demo was illustrating using SoapReceiver within a Windows Form application, which highlights that SOAP messages can be received inside any .NET assembly. While this demo makes the point (and suggests some interesting application designs, such as having a user interface app host a service and listen for messages, as John Cavnar-Johnson mentions in the comments), this may not be an appropriate hosting situation, esepcially if you want it to run the application on a server, without user intervention. Don Box has a great series on the major hosting options within .NET (IIS, DCOM/ES and Windows Services) and the advantages and disadvantages of each. Christian’s question was ‘Can I host SoapReceiver within a ServicedComponent?’
Here’s my version of a solution to this problem, with all the steps you need to get to the spinning balls. The server code looks like this:
using System;
using System.EnterpriseServices;
using System.IO;
using System.Net;
using System.Reflection;
using Microsoft.Web.Services2.Addressing;
using Microsoft.Web.Services2.Messaging;
[assembly : AssemblyKeyFile("keys.snk")]
[assembly : ApplicationName("WSE Hosting Example")]
[assembly : ApplicationActivation(ActivationOption.Server)]
[assembly : ApplicationAccessControl(false)]
public class WSESoapService : ServicedComponent, IProcessInitializer
{
#region IProcessInitializer Members
public void Shutdown()
{
Logger.LogMessage("Shutdown");
}
public void Startup(object punkProcessControl)
{
Uri uri = new Uri("soap.tcp://" + Dns.GetHostName() + ":4545/");
EndpointReference epr = new EndpointReference(uri);
// Add our WSE SoapService to the static collection of receivers,
// giving the address we want to listen on and the CLR type that
// will receive this message.
SoapReceivers.Add(epr, typeof (MyService));
Logger.LogMessage("Startup");
}
#endregion
}
// Here's our service that will receive messages
public class MyService : SoapService
{
[SoapMethod("ReceiveMessage")]
public void ReceiveMessage(string message)
{
Logger.LogMessage(message);
}
}
internal class Logger
{
internal static void LogMessage(string message)
{
// Log the messages to a file.
StreamWriter writer = new StreamWriter(@"c:\wsemessages.txt", true);
writer.WriteLine(message + "," + DateTime.Now);
writer.Flush();
writer.Close();
}
}
To compile this code, save it in a file called WSESoapService.cs, then use the following command lines (assuming that you’ve got the Microsoft.Web.Services2.dll in the compilation directory since csc.exe wont look in the GAC for assemblies):
sn –k keys.snk
csc /target:library WSESoapService.cs /r:Microsoft.Web.services2.dll
regsvcs WSESoapService.dll
Then go to the computer manager and start the WSE Hosting Example COM+ application.
The client code looks like this:
using System;
using System.Net;
using Microsoft.Web.Services2.Addressing;
using Microsoft.Web.Services2.Messaging;
public class App
{
public static void Main(string[] args)
{
Uri uri = new Uri("soap.tcp://" + Dns.GetHostName() + ":4545/");
EndpointReference epr = new EndpointReference(uri);
MySoapClient proxy = new MySoapClient(epr);
proxy.SendMessage("Here's a message");
Console.Write("Message Sent! Press any key to continue ...");
Console.Read();
}
}
// Proxy class to call the SoapReceiver Service
internal class MySoapClient : SoapClient
{
public MySoapClient(EndpointReference epr) : base(epr){}
public void SendMessage(string message)
{
base.SendOneWay("ReceiveMessage", message);
}
}
Then save this file as client.cs and compile it from the command-line as follows:
csc /target:exe client.cs /r:microsoft.web.services2.dll