I've recently got a new laptop and have finally got around to getting a recent build of Indigo installed. I wrote the simplest client and service I could using as little code and config as I could get away with, with as little code being the high-order bit. So given a choice between less code/more config or more code/less config, I always chose the former. Oh, and I didn't want to run any tools like svcutil or host inside IIS for this particular experiment either…
Here is what the service looks like;
// service.cs
using System;
using System.ServiceModel;
namespace Gudge.Samples {
[ServiceContract]
public interface ISimple {
[OperationContract]
string Ping(string text);
}
public class Service : ISimple {
static void Main(string[] args) {
ServiceHost<Service> sh = new ServiceHost<Service>();
sh.Open();
Console.WriteLine("Press enter to close the service");
Console.ReadLine();
}
public string Ping(string text) {
return text;
}
}
}
I have a simple interface, ISimple, to my service annotated with the [ServiceContract] attribute. That interface has a single 'operation', Ping, which accepts a string as input and returns the same string. The operation is marked with [OperationContract]. The Service class implements the service contract, as indicated by the fact that it inherits from ISimple. It also self-hosts which is what the code inside Main() is doing. The ServiceHost class looks in the config file to figure out what it's supposed to expose to the outside world and how it's supposed to expose it.
My config file for the service looks like this;
<!-- service.exe.config -->
<configuration xmlns = "http://schemas.microsoft.com/.NetConfiguration/v2.0" >
<system.serviceModel>
<bindings>
<basicProfileBinding>
<binding configurationName = "SimpleServiceBinding" />
</basicProfileBinding>
</bindings>
<services>
<service serviceType="Gudge.Samples.Service" >
<endpoint
address = "http://localhost:8080/simple"
bindingSectionName = "basicProfileBinding"
bindingConfiguration = "SimpleServiceBinding"
contractType = "Gudge.Samples.ISimple, Service" />
</service>
</services>
</system.serviceModel>
</configuration>
The ServiceHost class figures out which service element to use based on the value of the required serviceType attribute. It looks for an attribute that matches the type name of the type parameter. In my case, it's looking for Gudge.Samples.Service. Having found the appropriate service element, ServiceHost uses the child endpoint element to figure out how to expose my service contract to the outside world.
The address attribute indicates what address my service contract is available on. In this case it's an HTTP address on my local machine using port 8080. This is the address that clients can send messages to.
The bindingSectionName and bindingConfiguration attributes together point into the bindings section of the config file. The bindingSectionName takes us to the basicProfileBinding element and then the bindingConfiguration takes us to the binding element whose configurationName attribute has the same value. I've not done anything to change the behaviour of this binding, as evidenced by the lack of other attributes on the binding element itself. My service gets the default behaviour of the basicProfileBinding (whatever that is). I can share this binding across multiple endpoints if I want to, although in this simple case, I only have one endpoint.
Lastly, the contractType attribute tells ServiceHost which contract to expose. In this case Gudge.Samples.ISimple. If my service exposed multiple contracts, each one would have it's own endpoint.
That's it. I can build and run this service and it will happily sit at the specified address waiting for messages. For which we need a client...
Posted
May 09 2005, 04:09 AM
by
martin-gudgin