14

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.

vfilby
  • 9,938
  • 9
  • 49
  • 62
softveda
  • 10,858
  • 6
  • 42
  • 50
  • What happens if you just use "Add Service Reference"? – John Saunders Jul 09 '09 at 18:21
  • I haven't tried since I need to use the svcutil to generate proxy from dll. But I guess given that "add service reference" has option to input only one namespace it would be the same as wildcard namespace mapping. – softveda Jul 09 '09 at 23:56

2 Answers2

23

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
  • 2,110
  • 2
  • 19
  • 23
  • 3
    Any luck getting the namespace mapping to affect the xsd types as well? – Adi Lester Feb 12 '12 at 14:39
  • @Lester: I didn't pursue it much further at the time. We ended up avoiding the need for xsds by embedding those types in the wsdls I think. (It has been 3 years, mind you.) Maybe VS2010 improved on this situation? The above was done with VS2008. – Dave Cameron Feb 13 '12 at 20:28
  • 1
    @DaveCameron Another couple of years pass, and I am still hitting this same issue in VS2013 :-( – Ian Nelson Oct 15 '14 at 14:46
  • 1
    I'm facing this issue only when using the switch /serializer:XmlSerializer. For DataContractSerializer the types are corectly included in the specified namespaces. According to this [answer](http://www.yqcomputer.com/5_30364473a8db76ba_1.htm#p2) XmlSerializer does not support this feature. – Alexander May 19 '16 at 18:22
5

Just in case you want to map all schema namespaces to one CLR namespace then :

SvcUtil "your wsdl file.xml" /n:*,RequiredClrNamespace
Hakan Fıstık
  • 16,800
  • 14
  • 110
  • 131