Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WCF service reference namespace differs from original

I'm having a problem regarding namespaces used by my service references. I have a number of WCF services, say with the namespace MyCompany.Services.MyProduct (the actual namespaces are longer).
As part of the product, I'm also providing a sample C# .NET website. This web application uses the namespace MyCompany.MyProduct.

During initial development, the service was added as a project reference to the website and uses directly. I used a factory pattern that returns an object instance that implements MyCompany.Services.MyProduct.IMyService. So far, so good.

Now I want to change this to use an actual service reference. After adding the reference and typing MyCompany.Services.MyProduct in the namespace textbox, it generates classes in the namespace MyCompany.MyProduct.MyCompany.Services.MyProduct. BAD! I don't want to have to change using directives in several places just because I'm using a proxy class. So I tried prepending the namespace with global::, but that is not accepted.

Note that I hadn't even deleted the original assembly references yet, and "reuse types" is enabled, but no reusing was done, apparently. However, I don't want to keep the assembly references around in my sample website for it to work anyway.

The only solution I've come up with so far is setting the default namespace for my web application to MyCompany (because it cannot be empty), and adding the service reference as Services.MyProduct. Suppose that a customer wants to use my sample website as a starting point, and they change the default namespace to OtherCompany.Whatever, this will obviously break my workaround.

Is there a good solution to this problem?

To summarize: I want to generate a service reference proxy in the original namespace, without referencing the assembly.

Note: I have seen this question, but there was no solution provided that is acceptable for my use case.


Edit: As John Saunders suggested, I've submitted some feedback to Microsoft about this:
Feedback item @ Microsoft Connect

like image 240
Thorarin Avatar asked Jul 29 '09 13:07

Thorarin


People also ask

How do I change my WCF service reference?

To update a service reference In Solution Explorer, right-click the service reference and then click Update Service Reference.

How can I take WCF service without adding references?

Right click on the Solution Explorer of "WCFDemo" and go to Add > New Project. In the "New Project" dialog box, under Project types, expand Visual C#, and then click on WCF. Select "WCF Service Application" and in the Name box, type "WCFService". Click "OK".

How do I add a service reference in net core project?

NET Core or . NET Standard project, this option is available when you right-click on the Dependencies node of the project in Solution Explorer and choose Manage Connected Services.) On the Connected Services page, select Add Service Reference. The Add service reference page opens.


2 Answers

I've added a write-up of this solution to my blog. The same information really, but perhaps a little less fragmented

I've found an alternative to using svcutil.exe to accomplish what I want. It (imo) makes updating the service reference easier than rerunning the utility.

You should explicitly specify a namespace uri on your ServiceContract and DataContracts (see further below for comment).

[ServiceContract(Namespace = "http://company.com/MyCompany.Services.MyProduct")]
public interface IService
{
    [OperationContract]
    CompositeType GetData();
}

[DataContract(Namespace = "http://company.com/MyCompany.Services.MyProduct")]
public class CompositeType
{
    // Whatever
}

The namespace could be anything, but technically it needs to be a valid uri, so I chose this scheme. You might have to build manually for things to work later, so do that.

Once this is done, enable the Show All Files option in the Solution Explorer. Expand the service reference you added previously. Double click the Reference.svcmap file.

There will be a <NamespaceMappings /> element, which you will need to edit. Continuing my example:

<NamespaceMappings>
    <NamespaceMapping
        TargetNamespace="http://company.com/MyCompany.Services.MyProduct"
        ClrNamespace="MyCompany.Services.MyProduct" />
</NamespaceMappings>

Save the file, right click the service reference and select Update Service Reference.

You can add as many mappings as you need (I actually needed two). The effect is the same as the svcutil /namespace: approach, but without having to use the command line util itself, making for easier updating.

Difference with svcutil

The downside to this approach is that you need to use explicit namespace mappings. Using svcutil, you have the option to map everything not explicitly mapped like this (the solution John Saunders was referring to):

svcutil /namespace:*,MyCompany.Services.MyProduct ...

You might think to use:

<NamespaceMappings>
    <NamespaceMapping
        TargetNamespace="*"
        ClrNamespace="MyCompany.Services.MyProduct" />
</NamespaceMappings>

but this will not work, because Visual Studio already implicitly adds this mapping, pointing to the generated namespace name we're trying to get rid of. The above configuration will cause Visual Studio to complain about a duplicate key.

Ad explicit namespaces:
When no explit namespace is specified in your code, it seems that .NET will generate a uri of the form http://schemas.datacontract.org/2004/07/MyCompany.Services.MyProduct. You could map that just as well as the explicit namespaces in my example, but I don't know if there is any guarantee for this behavior. Therefore, going with an explicit namespace might be better.

NB: mapping two TargetNamespaces to the same ClrNamespace seems to break code generation

like image 169
Thorarin Avatar answered Sep 19 '22 12:09

Thorarin


Your use case was wrong.

You should never have included the service as a reference in the first place.

I believe svcutil.exe will accept a switch specifying the full namespace to use.

like image 29
John Saunders Avatar answered Sep 19 '22 12:09

John Saunders