Creating WCF servics is really very easy with Visual Studio. All the basic code is generated for you when you add a service to an existing web project or start a new WCF Service Application project. Modifying the "contract" is pretty straightforward too: you just modify the interface for your service, and then the actual implementation. WCF will do everything for you, generate the WSDL, etc. All your clients need to do is download/refresh the WSDL and they are able to use your service. Easy, right?
But when you look at the WSDL that gets generated for your service, you will notice that there are a lot of references to an XML namespace
http://tempuri.org. Lets just say if you publish such a service or develope a solution for yor client who will then publish the service with this namespace to their customers - it is just very unprofessional.
Changing the namespace, however, can be more trickier than you thought.
The following article will show you how to deal with namespace changes in WCF. This will work in both WCF 3 / 3.5 and WCF 4. There are some minor changes, for example, with the configuration, but the same things apply.
Quick reference
For those who are impatient to see how this is done, here is a quick reference of the changes we will apply to a simple WCF service to change the namespace. There are four places to change:
- Apply the
Namespace property to the
ServiceContractAttribute on the service contract interface
- Apply the
Namespace property to the
ServiceBehaviorAttribute on the class that implements the service
- Apply the
Namespace property to the
DataContractAttribute on every class that is involved with the service (parameters, return values)
- Change the namespace for the binding, either on the binding class or in the .config file
And now in detail.
The contract namespace
The first step of course is changing the contract namespace. This is pretty easy, and probably something everyone tries first. It is however, not enough. But lets get started anyway.
Assume I have just generated a new WCF service application. I renamed the default
Service1 name to
RebuildallService, so I have an interface called
IRebuildallService and a class called
RebuildallService. The .svc file is called
RebuildallService.svc. A little too many service words, but I will leave it that way for now
The service contract looks like this:
[ServiceContract]
public interface IRebuildallService
{
The
ServiceContractAttribute accepts a property called
Namespace, and you might have guessed we are going to use that. This will change the namespace on the contract.
So the code now looks lke this:
[ServiceContract ( Namespace = "http://schemas.umbraworks.net/rebuildall" )]
public interface IRebuildallService
{
If I compile and check the WSDL, I will get certain parts with the
tempuri.org namespace and others parts with my new namespace. In practice, the
wsdl:definitions XML elements will be in the new namespace, but all data and other parts of the WSDL will stil exist in
tempuri.org.
A note on namespaces: namespaces ARE NOT URLS!. They might look like one, like in my examples, but there is no such subdomain as schemas actually in existence. Namespaces follow the URI format, but are not actual addresses. They can be used to identify schemas, because usually a company owns a domain name. Thus using that as the schema namespace creates something unique. And that is exactly what namespaces should be: unique.
The service namespace
So, what else do we need to change? The next step is of course the service implementation itself. Currently, it looks like this:
public class RebuildallService : IRebuildallService
{
What we want to do is apply the
ServiceBehaviorAttribute, which also has a
Namespace property.
[ServiceBehavior(Namespace = "http://schemas.umbraworks.net/rebuildall")]
public class RebuildallService : IRebuildallService
{
Looking at the WSDL after this change you will notice that a big part is now in the desired namespace and there are two things left in the
tempuri.org namespace: the data types we use and the
wsdl:binding element.
The data types
Lets change the namespace for the data types, since it is a rather straightforward change. Currently the example service (the default implementation that Visual Studio provides) contains the following definition for a data type:
[DataContract]
public class CompositeType
{
You might have guessed, we will add the
Namespace attribute to the
DataContractAttribute.
[DataContract(Namespace = "http://schemas.umbraworks.net/rebuildall")]
public class CompositeType
{
This will change our data types to exist in our new namespace.
If your data is more complex and you have several classes, be sure to apply the
Namespace property along with the
DataContract attribute to every one of them. Do this also for your
enums, otherwise they will exist in the
tempuri.org namespace!
The binding
The final element is changing the binding namespace. If you use code-only WCF, you would specify this in the constructor of the
Binding class, but since most of the time you will use config files to specify the binding, I will show how to proceed in this latter case.
In WCF4 you have default bindings, so your web.config file will be pretty empty. In WCF3/3.5 the config file will contain the binding by default, so there you can change it more easily.
Anyhow, what you need to do is add the
bindingNamespace element to the
endpoint element of the
service element. Like so:
<services>
<service name="WcfNamespaces.RebuildallService">
<endpoint address="RebuildallService.svc" bindingNamespace="http://schemas.umbraworks.net/rebuildall"
binding="basicHttpBinding" contract="WcfNamespaces.IRebuildallService" />
</service>
</services>
For WCF4, I would need to add this entire section into my config file. For WCF3/3.5 only the new attribute needs to be added. The
WcfNamespaces, in case you wonder, is the .NET namespace my test project was in.
And with this final change, the WSDL will not be in our own custom namespace, and
http://tempuri.org is gone for good
Some thoughts about namespaces
In the example above, I placed all services, descriptions, bindings and data types in the same namespace. This is of course not needed, you can specify different namespaces for everything, and WCF will handle this. The WSDL will be more fragmented: WCF generates a separate document for different namespaced entities. But there is nothing technically preventing you from doing this.