tags:

views:

2361

answers:

2

I want to use svcutil to map multiple wsdl namespace to clr namespace when generating service proxies. I use strong versioning of namespaces and hence the generated clr namespaces are awkward and may mean many client side code changes if the wsdl/xsd namespace version changes. A code example would be better to show what I want.

// Service code
namespace TestService.StoreService
{
    [DataContract(Namespace = "http://mydomain.com/xsd/Model/Store/2009/07/01")]
    public class Address
    {
        [DataMember(IsRequired = true, Order = 0)]
        public string street { get; set; }
    }

    [ServiceContract(Namespace = "http://mydomain.com/wsdl/StoreService-v1.0")]
    public interface IStoreService
    {
        [OperationContract]
        List<Customer> GetAllCustomersForStore(int storeId);

        [OperationContract]
        Address GetStoreAddress(int storeId);
    }

    public class StoreService : IStoreService
    {
        public List<Customer> GetAllCustomersForStore(int storeId)
        {
            throw new NotImplementedException();
        }

        public Address GetStoreAddress(int storeId)
        {
            throw new NotImplementedException();
        }
    }
}

namespace TestService.CustomerService
{
    [DataContract(Namespace = "http://mydomain.com/xsd/Model/Customer/2009/07/01")]
    public class Address
    {
        [DataMember(IsRequired = true, Order = 0)]
        public string city { get; set; }
    }

    [ServiceContract(Namespace = "http://mydomain.com/wsdl/CustomerService-v1.0")]
    public interface ICustomerService
    {
        [OperationContract]
        Customer GetCustomer(int customerId);

        [OperationContract]
        Address GetStoreAddress(int customerId);
    }

    public class CustomerService : ICustomerService
    {
        public Customer GetCustomer(int customerId)
        {
            throw new NotImplementedException();
        }

        public Address GetStoreAddress(int customerId)
        {
            throw new NotImplementedException();
        }
    }
}

namespace TestService.Shared
{
    [DataContract(Namespace = "http://mydomain.com/xsd/Model/Shared/2009/07/01")]
    public class Customer
    {
        [DataMember(IsRequired = true, Order = 0)]
        public int CustomerId { get; set; }
        [DataMember(IsRequired = true, Order = 1)]
        public string FirstName { get; set; }
    }
}

1. svcutil - without namespace mapping

svcutil.exe /t:metadata 
    TestSvcUtil\bin\debug\TestService.CustomerService.dll     
    TestSvcUtil\bin\debug\TestService.StoreService.dll

svcutil.exe /t:code *.wsdl *.xsd /o:TestClient\WebServiceProxy.cs

The generated proxy looks like

namespace mydomain.com.xsd.Model.Shared._2009._07._011
{
    public partial class Customer{}
}
namespace mydomain.com.xsd.Model.Customer._2009._07._011
{
    public partial class Address{}
}
namespace mydomain.com.xsd.Model.Store._2009._07._011
{
    public partial class Address{}
}

The client classes are out of any namespaces. Any change to xsd namespace would imply changing all using statements in my client code all build will break.

2. svcutil - with wildcard namespace mapping

svcutil.exe /t:metadata 
    TestSvcUtil\bin\debug\TestService.CustomerService.dll 
    TestSvcUtil\bin\debug\TestService.StoreService.dll

svcutil.exe /t:code *.wsdl *.xsd /n:*,MyDomain.ServiceProxy 
    /o:TestClient\WebServicesProxy2.cs

The generated proxy looks like

namespace MyDomain.ServiceProxy
{
    public partial class Customer{}
    public partial class Address{}
    public partial class Address1{}
    public partial class CustomerServiceClient{}
    public partial class StoreServiceClient{}
}

Notice that svcutil has automatically changed one of the Address class to Address1. I don't like this. All client classes are also inside the same namespace.

What I want

Something like this:

svcutil.exe 
    /t:code *.wsdl *.xsd 
    /n:"http://mydomain.com/xsd/Model/Shared/2009/07/01, MyDomain.Model.Shared;http://mydomain.com/xsd/Model/Customer/2009/07/01, MyDomain.Model.Customer;http://mydomain.com/wsdl/CustomerService-v1.0, MyDomain.CustomerServiceProxy;http://mydomain.com/xsd/Model/Store/2009/07/01, MyDomain.Model.Store;http://mydomain.com/wsdl/StoreService-v1.0, MyDomain.StoreServiceProxy" 
    /o:TestClient\WebServiceProxy3.cs

This way I can logically group the clr namespace and any change to wsdl/xsd namespace is handled in the proxy generation only without affecting the rest of the client side code.

Now this is not possible. The svcutil allows to map only one or all namespaces, not a list of mappings.

I can do one mapping as shown below but not multiple

svcutil.exe 
    /t:code *.wsdl *.xsd 
    /n:"http://mydomain.com/xsd/Model/Store/2009/07/01, MyDomain.Model.Address" 
    /o:TestClient\WebServiceProxy4.cs

But is there any solution. Svcutil is not magic, it is written in .Net and programatically generating the proxies. Has anyone written an alternate to svcutil or point me to directions so that I can write one.

A: 

Do you have this sort of versioning working in any other environment, or have you seen it work?

Am I understanding correctly that you want to be able to change namespaces on the server and have the client not change? That's contrary to my understanding of versioning.

John Saunders
You are correct to certain extent. Yes I have strategy for strong versioning but my team writes both the service and the primary client for this service. The client proxies are built automatically from service dlls on each build. A datacontract version change implies adding/deleteing or changing type of datamembers. This would normally be caught when the client is compiled. So I want to strike a balance and not make client change in many files if say a single datacontract class changes.
Pratik
But if you're rebuilding the client proxies anyway, why go through all of this?
John Saunders
Because a new web client will be a secondary client for this web service very soon. I want to retain the strong versioning policy to break that client if the versioning changes. My main question is how was svcutil written I hope Microsoft opensource it or add capability to do multiple namespace mapping.
Pratik
+3  A: 

Hi Pratik

You can do multiple namespace mappings by providing additional namespace parameters -- not by semi-colon seperating them. So your example should instead be

svcutil.exe /t:code *.wsdl *.xsd 
/n:http://mydomain.com/xsd/Model/Shared/2009/07/01,MyDomain.Model.Shared 
/n:http://mydomain.com/xsd/Model/Customer/2009/07/01,MyDomain.Model.Customer
/n:http://mydomain.com/wsdl/CustomerService-v1.0,MyDomain.CustomerServiceProxy 
/n:http://mydomain.com/xsd/Model/Store/2009/07/01,MyDomain.Model.Store 
/n:http://mydomain.com/wsdl/StoreService-v1.0,MyDomain.StoreServiceProxy
/o:TestClient\WebServiceProxy3.cs

Although, I am currently having trouble where the types generated from .xsd files are not affected by these namespaces. Only the types generated from the .wsdl files are. The documentation implies that both should be.

Dave Cameron