When using WCF to consume a web service from your .NET application, you have a couple of different options:
- Using a contract-only assembly reference, generating a proxy at runtime
- Generate a proxy by running svcutil.exe
- Adding a service reference to your project from Visual Studio
This post is focused on the last of these three options. When adding a service reference, Visual Studio presents you with a dialog box which allows you some level of control over the proxy being generated. One of these options allows you to choose the namespace for the generated classes.
Unfortunately, there is a small but annoying limitation on your ability to choose any namespace you like; Visual Studio will always prefix whatever namespace you enter with the current project's default namespace.
For example, we're writing an web application called MyApplication. The default namespace is MyCompany.MyApplication. The application depends on a service MyService, for which I'm adding a service reference with that same name. The generated proxy class will then be in the namespace MyCompany.MyApplication.MyService. Usually, this is not a big problem, but sometimes this is not what you want, so I went to look for some way to get rid of the bit that Visual Studio adds for me.
My first attempt was to provide Visual Studio with a rooted namespace name: global::MyCompany.MyService. Unfortunately, this is not allowed. When generating a proxy class with svcutil.exe, you have full control over the namespace being used. Visual Studio uses that same mechanism for its code generation, so maybe there was some way to influence which parameters it uses.
Solution
It turns out that Visual Studio does actually allow for some customization beyond what is offered in the dialog box it shows you. After you've added the service reference, enable the Show All Files option in your solution explorer. The service reference will become an expandable node, containing (amongst other things) a Reference.svcmap file. This file contains the settings for your service reference, from which all the other files are generated. We'll be hand editing this XML based file.
Consider this contract definition:
[ServiceContract(Namespace = "http://mycompany.com/MyCompany.MyService")]
public interface IMyService
{
[OperationContract]
CompositeType GetData();
}
[DataContract(Namespace = "http://mycompany.com/MyCompany.MyService")]
public class CompositeType
{
// Whatever
}
Suppose I wanted to generate my proxy into the namespace MyCompany.MyService, I would open up the Reference.svcmap file and find the <NamespaceMappings /> element, replacing it with something like this:
<NamespaceMappings>
<NamespaceMapping
TargetNamespace="http://mycompany.com/MyCompany.MyService"
ClrNamespace="MyCompany.MyService" />
</NamespaceMappings>
After you save the file and update the service reference, the generated code will be inside the desired namespace.
Wait a minute however, what's with these explicit namespaces in my contracts? Well, your contract definitions should really be already containing those, but I imagine that most people don't actually bother with them. If you don't supply any namespace in your contract, .NET will auto generate one in the form http://schemas.datacontract.org/2004/07/MyCompany.MyService. You could map that namespace URI instead of the one I used in the example above, and it'll work. However, I don't really like relying on this behavior, which I why I explicitly provided namespace URIs.
Difference with svcutil
The downside to the above solution, is that you need to use explicit namespace mappings. If you use more than one namespace, you will need to map all of them manually, which can be a bit of a pain. With svcutil, you actually have the option of mapping everything that is not explictly mapped into a default namespace, like this:
svcutil /namespace:*,MyCompany.MyService ...
Since Visual Studio actually uses svcutil to do its job, you might try to be clever and use:
<NamespaceMappings>
<NamespaceMapping
TargetNamespace="*"
ClrNamespace="MyCompany.MyService" />
</NamespaceMappings>
Unfortunately, this will not work. Visual Studio adds this mapping implicitly, to that darned MyCompany.MyApplication.MyService namespace we were trying to get rid of.
Another caveat: mapping two TargetNamespaces to a single ClrNamespace seems to break code generation.
Dude, this solution totally sucks...
I'll readily admit that it is far from ideal, but it saves you from creating batch files for svcutil code generation. To ease the pain of maintaining the Reference.svcmap file a little, it is possible to combine multiple service references into one. That way, you only have to maintain the NamespaceMappings list in one place if you're using multiple services. The key is the MetadataSources element:
<MetadataSources>
<MetadataSource Address="http://localhost/MyService/mex" Protocol="mex" SourceId="1" />
<MetadataSource Address="http://localhost/MyOtherService/mex" Protocol="mex" SourceId="2" />
</MetadataSources>
After updating the service reference, a proxy for services will be generated. Also, if you have data contracts that are shared between these two services, they will actually only be generated once.