use svcutil to map multiple namespaces for generating wcf service proxies - wcf

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.

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.

Just in case you want to map all schema namespaces to one CLR namespace then :
SvcUtil "your wsdl file.xml" /n:*,RequiredClrNamespace

Related

ServiceReference not found when return a DataContract from a OperationContract?

It is a simple class, I reference it in silverlight project in the same solution. if the operation method returns an integer, it works fine, but if I make it return a DataContract, it just says the servicereference cannot find
In web project
public class UserResult
{
....
}
[ServiceContract(Namespace = "")]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class ServiceUser
{
[OperationContract]
public UserResult UserSignIn(string userid, string password)
{
...
} /// doesn't work
public int UserSignIn(string userid, string password)
{
...
} // works
In SilverLight
ServiceReferenceUser.ServiceUserClient srUser =
new ServiceReferenceUser.ServiceUserClient();
Perhaps the UserResult class references some other DataContract. If so, that DataContract needs to be specified as a known type.

Expose WCF service for derived class with same name in C#

I want to expose as WCF service two set of classes that have the same name. However, when I add the service reference, it only returns one set of the class.
[ServiceContract(Name = "Service1")]
[XmlSerializerFormat]
public interface IService1
{
[OperationContract]
[ServiceKnownType(typeof(S1.Retangle))]
[ServiceKnownType(typeof(S1.Square))]
[ServiceKnownType(typeof(S2.Retangle))]
[ServiceKnownType(typeof(S2.Square))]
string GetShape(Shape shape);
}
//All types are only example
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute()]
public abstract class Shape
{
public int Width { get; set; }
public int Height { get; set; }
public string TypeName { get; set; }
}
namespace S1
{
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute()]
public class Retangle : Shape
{ }
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute()]
public class Square : Shape
{ }
}
namespace S2
{
//[DataContract]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "Namespace=http://tempuri.org/S2")] //can be changed
public class Retangle : Shape
{ }
//[DataContract]
[System.SerializableAttribute()]
[System.Xml.Serialization.XmlTypeAttribute(Namespace = "Namespace=http://tempuri.org/S2")] //can be changed
public class Square : Shape
{ }
}
Any idea would be very much appreciated.
WCF will generate your objects in its own namespace for use client side but your not forced to use these - you can equally well use your own original objects in the namespaces they were defined by either:
1. Compiling them in a dll and linking to that for both client and sever.
2. If you dont want overhead of shared dll just compile them directly into both server and client.
In the generated proxy code you just need to replace the WCF namespace tags with your own org namespaces so they resolve to your objects and the client side WCF generated ones are ignored.

How to avoid Custom type name clash generated in WCF Client

A custom type (e.g. Engine) is defined in two different namespaces on WCF server side, which is exposed to WCF client as Engine, Engine1. How to set up so that the exposed types have the same name, Engine in this case.
Below is my example code:
namespace WcfServiceLibrary1
{
[ServiceContract]
interface ICar
{
[OperationContract]
void RepairMotorCycle(MotorCycle motorCycle);
[OperationContract]
void RepairTwoDoorCar(TwoDoorCar Car);
}
public class Car:ICar
{
public void RepairMotorCycle(MotorCycle motorCycle)
{
throw new NotImplementedException();
}
public void RepairTwoDoorCar(TwoDoorCar Car)
{
throw new NotImplementedException();
}
}
}
namespace WcfServiceLibrary1.MC
{
public class MotorCycle
{
public Engine Engine { get; set; }
}
public class Engine { }
}
namespace WcfServiceLibrary1.C
{
public class TwoDoorCar
{
public Engine Engine { get; set; }
}
public class Engine { }
}
Below is the WCF client for Engine:
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="Engine", Namespace="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1.MC")]
[System.SerializableAttribute()]
public partial class Engine : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
}
[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "4.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="Engine", Namespace="http://schemas.datacontract.org/2004/07/WcfServiceLibrary1.C")]
[System.SerializableAttribute()]
public partial class Engine1 : object, System.Runtime.Serialization.IExtensibleDataObject, System.ComponentModel.INotifyPropertyChanged {
}
Please note that both MotoCycle and TwoDoorCar contain a large number of custom type that have the same name but different function. Thus, it is tedious to change the name on client side (e.g. change Engine1 to Engine for all occurences). Also it is tedious to solve it by using class inheritance. It is ok to define two custom types that have the same name, which might need less work.
Any idea would be very much appreciated!
Edit
*Possible Solution*
Put it into separate interface, as below
[ServiceContract]
interface ICar1
{
[OperationContract]
void RepairMotorCycle(MotorCycle motorCycle);
}
[ServiceContract]
interface ICar2
{
[OperationContract]
void RepairTwoDoorCar(TwoDoorCar Car);
}
This will put the same custom type in different namespace on client side.
If your Engines represent an identical concept, you could define one Engine in a dedicated namespace and reference it from WcfServiceLibrary1.MCand WcfServiceLibrary1.C.
Your example however suggests that you should rather gather your vehicles into a single namespace and make use of inheritance.
namespace WcfServiceLibrary.Vehicles
{
public class Engine
{
}
public abstract class Vehicle
{
public Engine { get; set; }
}
public class Car : Vehicle
{
}
pulic class Motorcycle : Vehicle
{
}
}
Moving your Engine to a common namespace could look like this:
namespace WcfServiceLibrary.Common
{
public class Engine
{
}
}
Your "Motorcycle" library
using WcfServiceLibrary.Common
namespace WcfServiceLibrary.MC
{
public class Motorcycle
{
public Engine Engine { get; set; }
}
}
... and your "Car" library
using WcfServiceLibrary.Common
namespace WcfServiceLibrary.C
{
public class Car
{
public Engine Engine { get; set; }
}
}
You won't have to change your Engine property.
First of all, try and share your code libraries between the server and client. This link will tell you how to do it for Silverlight, if you are not using Silverlight then check this SO search link for a variety of posts and answers on the subject.
Secondly, if you cannot share the libraries then editing the generated client class files will work (just delete the definition of Engine1 and fix up any references to it to point to the Engine), although you will lose the changes if you regenerate the proxy.

Wcf inhereted models

[DataContract]
Base
{
[DataMember]
public int Id {get;set;}
}
[DataContract]
A : Base
{
[DataMember]
public string Value {get;set;}
}
[ServiceContract]
interface IService
{
[OperationContract]
void SetValue (Base base);
}
is there a way to use the service like the following style:
new Service ().SetValue (new A ());
You tagged this WCF so I assume you want to use it.
You need to connect to the endpoint using the ChannelFactory and then open the channel.
This will not work:
new Service ().SetValue (new A ());
You need to do smth. like this:
using (var scf = new ChannelFactory< IService >(<Binding>,<EndpointAddress>)
{
IService proxy = scf.CreateChannel();
proxy.SetValue(new (A));
}
This will return you a proxy object that implements the IService interface. You can call the SetValue on this object.
As well as changing the way you're calling the service as indicated by #Flo, you'll also need to make a small change to prepare the Data Contract Serializer to deal with the inheritance hierarchy.
The easiest way of doing this is decorating Base with the KnownTypeAttribute. Like this,
[DataContract]
[KnownType(typeof(A))]
Base
{
[DataMember]
public int Id {get;set;}
}
[DataContract]
A : Base
{
[DataMember]
public string Value {get;set;}
}

Type not exposed by WCF Service

I have a small test web service to emulate something odd I'm noticing in a real world app. As the demo shows the same behaviour as the app I will use the demo for brevity.
In short My service interface file looks as follows (as you can see it is the default WCF service created by VS2008 but I have added a new public method (GetOtherType()) and two new classes at the bottom (SomeOtherType and SomeComplexType). SomeOtherType manages a generic List of type SomeComplexType
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace WCFServiceTest
{
[ServiceContract]
public interface IService1
{
[OperationContract]
string GetData(int value);
[OperationContract]
CompositeType GetDataUsingDataContract(CompositeType composite);
[OperationContract]
SomeOtherType GetOtherType();
}
[DataContract]
public class CompositeType
{
bool boolValue = true;
string stringValue = "Hello ";
[DataMember]
public bool BoolValue
{
get { return boolValue; }
set { boolValue = value; }
}
[DataMember]
public string StringValue
{
get { return stringValue; }
set { stringValue = value; }
}
}
[DataContract]
public class SomeOtherType
{
public List<SomeComplexType> Items { get; set; }
}
[DataContract]
public class SomeComplexType
{
}
}
My Service is implemented as follows
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
namespace WCFServiceTest
{
public class Service1 : IService1
{
#region IService1 Members
public string GetData(int value)
{
throw new NotImplementedException();
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
throw new NotImplementedException();
}
#endregion
#region IService1 Members
public SomeOtherType GetOtherType()
{
throw new NotImplementedException();
}
#endregion
}
}
The problem I have is that if I include a service reference to this service in an ASP.NET Web Application, I cannot see SomeComplexType via intellisense. The error relates to the type or namespace cannot be found. However, SomeOtherType can be found (I'm assuming as the type is a return type from one of the public methods).
Am I right in thinking I can't expose a type from a WCF Service if that type is not featured in the method signature of one of my public methods (either return type or argument)? If so, how would I be able to iterate over the Items inside an instance of SomeOtherType on the client?
Many Thanks and I hope this is clear.
Simon
The problem I have is that if I
include a service reference to this
service in an ASP.NET Web Application,
I cannot see SomeComplexType via
intellisense. The error relates to the
type or namespace cannot be found.
However, SomeOtherType can be found
(I'm assuming as the type is a return
type from one of the public methods).
Am I right in thinking I can't expose
a type from a WCF Service if that type
is not featured in the method
signature of one of my public methods
(either return type or argument)? If
so, how would I be able to iterate
over the Items inside an instance of
SomeOtherType on the client?
You are absolutely right - your SomeComplexType is never used in any of the service methods, and it's also never tagged as a [DataMember] in any of the types that are indeed used as parameters in your service methods. Therefore, from the point of view of WCF, it's not needed, and won't show up in the WSDL/XSD for the service.
As Graham already pointed out - you are using the SomeComplexType in one place:
[DataContract]
public class SomeOtherType
{
public List<SomeComplexType> Items { get; set; }
}
but since the Items element is not tagged as a [DataMember], it (and therefore the type it uses) will not be included in the WSDL/XSD of your service. Since the Items are not marked as DataMember, they won't be in your serialized WCF message either, so you won't ever need to iterate over this collection :-)
So most likely, what you really want, is just add the [DataMember] attribute to your Items property; then it'll be included in the WSDL/XSD, and so will the SomeComplexType.
Looks like you need the [DataMember] attribute on your SomeOtherType.Items property, i.e.
[DataMember]
public List<SomeComplexType> Items { get; set; }
I'm not at all an expert on this topic, so just as a shot in the blue: Empty DataContracts are discarded by WCF? Try exposing anything in ComplexDataType (some int is enough) and see if that changes anything.
Also, I believe you can verify the availability of the type using the built-in wcftestclient (you need to turn metadata exchange on for this).
We can use Known type in Service in order to get exposed of the class and its members when it is not used in the operation contract signature directly or indirectly.
For such types where you just want it to be available on the client side even if its not used, below attribute class is handy to make it available on client side.
[KnownType(typeof(SomeComplexType))]