Pergunta sobre wcf, svcutil.exe – use svcutil para mapear vários namespaces para gerar proxies de serviço wcf

12

Eu quero usar svcutil para mapear vários namespace wsdl para namespace clr ao gerar proxies de serviço. Eu uso versões fortes de namespaces e, portanto, os namespaces clr gerados são estranhos e podem significar muitas alterações no código do lado do cliente se a versão do namespace wsdl / xsd mudar. Um exemplo de código seria melhor para mostrar o que eu quero.

// 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 - sem mapeamento de namespace

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

O proxy gerado parece

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{}
}

As classes do cliente estão fora de qualquer namespace. Qualquer alteração no namespace xsd implicaria alterar todas as instruções usando no meu código de cliente, e todas as construções serão quebradas.

2. svcutil - com mapeamento de espaço de nomes curinga

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

O proxy gerado parece

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

Observe que svcutil alterou automaticamente uma das classes Address para Address1. Eu não gosto disso. Todas as classes do cliente também estão dentro do mesmo namespace.

O que eu quero

Algo assim:

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

Dessa forma, eu posso agrupar logicamente o namespace clr e qualquer alteração no namespace wsdl / xsd é tratada apenas na geração de proxy, sem afetar o restante do código do lado do cliente.

Agora isso não é possível. O svcutil permite mapear apenas um ou todos os namespaces, não uma lista de mapeamentos.

Eu posso fazer um mapeamento como mostrado abaixo, mas não múltiplo

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

Mas existe alguma solução? Svcutil não é mágica, está escrito em .Net e gerando programaticamente os proxies. Alguém escreveu uma alternativa para svcutil ou me aponta para as direções para que eu possa escrever uma.

Eu não tentei desde que eu preciso usar o svcutil para gerar proxy de dll. Mas eu acho que, dado que "adicionar referência de serviço" tem a opção de inserir apenas um namespace, ele seria o mesmo que o mapeamento de namespace com curinga. softveda
O que acontece se você acabou de usar "Add Service Reference"? John Saunders

Sua resposta

2   a resposta
1

ra um namespace CLR, então:

SvcUtil "your wsdl file.xml" /n:*,RequiredClrNamespace
20

de namespace adicionais - não por ponto-e-vírgula separando-os. Então, o seu exemplo deve ser

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

Embora, eu esteja tendo problemas atualmente, onde os tipos gerados a partir de arquivos .xsd não são afetados por esses namespaces. Apenas os tipos gerados pelos arquivos .wsdl são. A documentação implica que ambos deveriam ser.

@Lester: Eu não insisti muito nisso na época. Acabamos evitando a necessidade de xsds, incorporando esses tipos nos wsdls que eu acho. (Já faz 3 anos, lembre-se.) Talvez o VS2010 tenha melhorado essa situação? O acima foi feito com o VS2008. Dave Cameron
Alguma sorte em conseguir que o mapeamento de espaço de nomes também afete os tipos xsd? Adi Lester
@DaveCameron Outro par de anos se passa, e eu ainda estou acertando esse mesmo problema no VS2013 :-( Ian Nelson
Estou enfrentando esse problema somente ao usar o switch / serializador: XmlSerializer. Para DataContractSerializer, os tipos estão incluídos corretamente nos namespaces especificados. De acordo com issoresponda XmlSerializer não suporta este recurso. Alexander

Perguntas relacionadas