Building webservices with Spring.Net

Building and consuming anything but a trivial web service with Visual Studio can be quite an error prone task. The service itself is difficult to test outside of the web environment, the proxy class generated by Visual Studio will, most of the time, be in a conflicted state in your code repository as multiple developers add and change methods. It’s also quite cumbersome if you want to map those proxy classes back to your own classes. The list goes on and while Windows Communication Foundation does solve some of these issues I’d like to introduce you to the service infrastructure of Spring.Net which can help you to expose your services and is available on .net 2.0.

Let’s first look at the server side. Instead of decorating your service with webservice and webmethod attributes you can write a plain old c# object (poco) which can be tested like any other class and be hosted in multiple environments, exposing the service via remoting is just a configuration change. Nothing even prevents you from making a fat client, just keep the service itself behind an interface.

public class ProductService
: IProductService
{
	private List<ProductDto> products;
 
	public ProductService()
	{
		products = new List<ProductDto>();
		products.Add(new ProductDto("Pizza Margherita",9.75));
		products.Add(new ProductDto("Pizza Pepperoni Lovers",10.95));
		products.Add(new ProductDto("Pizza Cheesam ",10.95));
	}
 
	#region IProductService Members
 
	public RetrieveProductsResponse RetrieveProducts(RetrieveProductsRequest request)
	{
		return new RetrieveProductsResponse(products);
	}
 
	public SearchProductsResponse SearchProducts(SearchProductsRequest request)
	{
		List<ProductDto> productMatches = new List<ProductDto>();
		foreach (ProductDto product in products)
		{
			if (product.Name.ToUpper().Contains(request.Name.ToUpper()))
			{
				productMatches.Add(product);
			}
		}
		return new SearchProductsResponse(productMatches);
	}
 
	#endregion
}

As you can see, nothing fancy here. The ProductDto, requests, responses and the service interface are all located in an assembly which will be shared between the client and the server.

Whenever you build a service layer around your application, the best way to look upon it is like a GUI. You expose the behaviour of your domain, just not with web or winforms.

Since the service is just a poco, putting it into your spring configuration is just like you would add any other class. You can perform DI, AOP, … upon it like you’d normally do.

<object name="ProductService" type="Service.ProductService, Service"/>

To make it available as a webservice you use the Webservice exporter which can be found in the Spring.Web assembly as illustrated below.

<object id="ProductWebService" type="Spring.Web.Services.WebServiceExporter, Spring.Web">
  <property name="TargetName" value="ProductService"/>
  <property name="Namespace" value="http://www.bennymichielsen.be/services"/>
  <property name="Description" value="Defines operations upon products"/>
  <property name="MemberAttributes">
    <dictionary>
      <entry key="RetrieveProducts">
        <object type="System.Web.Services.WebMethodAttribute, System.Web.Services">
          <property name="Description" value="Retrieves all products"/>
          <property name="MessageName" value="RetrieveProducts"/>
        </object>
      </entry>
      <entry key="SearchProducts">
        <object type="System.Web.Services.WebMethodAttribute, System.Web.Services">
          <property name="Description" value="Searches for products which have a name like the one supplied."/>
          <property name="MessageName" value="SearchProducts"/>
        </object>
      </entry>
    </dictionary>
  </property>
</object>

Using the Webservice exporter you can export any object in your configuration as a webservice, just point it to the appropriate object definition using the TargetName property. I’ve populated some more properties just to show how you can use this class. It is however necessary to have an interface(s) on your service, but since this is a best practice anyhow I don’t see this as a shortcoming.

On the client side a similar approach can be used to consume the webservice using the WebserviceProxy factory in the Spring.Services assembly. Using this class your code can depend upon the service interface instead of the proxy class itself. If you want to use the proxy class, this is still supported. In this case Spring will create a proxy which will implement the service interface and map to the Visual Studio proxy. Note that the original service does not have to implement this interface, the methods supplied in the interface are mapped using a kind of duck typing. This is very useful if you don’t control the service but are consuming it and don’t want to tightly couple your code.

If you do control both sides, it is much easier to let the proxy be generated at runtime.

<object name="ProductService" type="Spring.Web.Services.WebServiceProxyFactory, Spring.Services">
  <property name="ServiceUri" value="http://localhost:1871/ProductWebService.asmx"/>
  <property name="ServiceInterface" value="ServiceContract.Interface.IProductService, ServiceContract"/>
</object>

This allows you to use the service interface, the concrete implementation is of no concern. What’s also very useful is that you can reuse all the classes which are already in the service contract assembly, thus preventing your solution from being polluted with any additional code.

For more information please take a look at the documentation.

SpringWebservicesSample.zip (1.22 mb)

7 thoughts on “Building webservices with Spring.Net

  1. First thanks for posting this example it has been very helpful.

    There is one bit of oddity that maybe you can clear up though. While goofing around with your example I noticed that any change to method signatures or even adding a new method to the service causes problems even if the changes build correctly.

    For example let’s say we change the SearchProductsResponse method to accept a string as the parameter. All reference are updated as well and we also restart the web server to be thorough.

    Without fail we get:
    “The XML element ‘SearchProductsResponse’ from namespace ‘http://Just/testing’ references a method and a type. Change the method’s message name using WebMethodAttribute or change the type’s root element using the XmlRootAttribute.”

    Our research indicates this comes from a generated WSDL that is out of sync with the service changes. Kinda odd when there is no wsdl hanging around. Do you have any insight on what could be going on here?

    Thanks

  2. Odd indeed, I was able to reproduce this immediately on my virtual machine. Very strange because I’ve developed several applications over the past years using this approach and never ran into this.

    While I’ve been able to reproduce the exception I haven’t found a solution yet. I’ve update my VM to SP1, set the host for 3.5, introduced classes, moved them around, deleted temp asp.net stuff, etc etc . The problem remains.

    What is even more bizarre is that if you add a parameter to one of the methods in the sample there’s no problem. Remove that parameter, no problem. Introduce a new method, no problem. Change that method, no problem. Remove the new method, no problem.

    In the end, somehow, I did get the service to work when changing the parameter on one of the original methods but I was unable to trace my steps back. I’m going to create a topic on the Spring forum and will post the link here.

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>