WCF Service Reference generates its own contract interface, won't reuse mine - c#

My first question so hope it is suitable:
Shared interface assembly - I have a 'shared' assembly which has an interface, let's call it IDocRepository. It's marked with [ServiceContract] and there are several [OperationContract]-marked methods.
WCF implementation assemblies - I have two WCF service projects, each referencing the shared assembly, each implementing that interface as a WCF service.
Consumer assembly - Finally, I have a 'client' project, also referencing the shared assembly, with a reference to each of the two WCF services.
However, the service references generated in the consumer assembly derive from an auto-generated version of the interface:
public partial class ExampleClient : System.ServiceModel.ClientBase<SomeNamespace.ExampleSvcRef.IDocRepository>, SomeNamespace.ExampleSvcRef.IDocRepository {
What I expected
I would have hoped that both references would instead automatically inherit the interface I defined, that the consumer/client assembly is also referencing. Kind of like the re-use of classes that it provides for parameter and return types, but for the service interface.
Why
So that I can create an instance of either service reference proxy and cast it to my interface type.
So I could modify the generated code by hand each time, but there should be better way...?
(edit: I do have 'Reuse types in referenced assemblies' and 'Reuse types in all referenced assemblies' options selected for both service references)

"Reuse types in referenced assemblies" only allows you to reuse Data Contracts, not Service Contracts. If you want to share Service Contracts, you don't need to use "Add Service Reference" at all. You can just use ChannelFactory directly.
// Supply the binding and address in code
Binding binding = new BasicHttpBinding();
EndpointAddress address = new EndpointAddress("http://tempuri.org/address");
IServiceContract channel = ChannelFactory<IServiceContract>.CreateChannel(binding, address);
// Or read them from the config file
ChannelFactory<IServiceContract> channelFactory = new ChannelFactory<IServiceContract>();
IServiceContract channel = channelFactory.CreateChannel();
The channel object will also implement ICommunicationObject, so you can cast it if you need to call methods like Open() or Close().

Visual Studio does not support reusing you existing interface when generating the proxy classes for you. Reuse types will not reuse the contract interface as Quartermeister pointed out.
We have solved it with inheritance. Quite similar to the partial class idea above suggested by Jester Software.
This is how we solved it:
In the project of your client just create a service reference as you would have done. Then add a class that serves as the replacement for the client:
internal class MyServiceProxy : MyServiceClient, MyLogicNamespace.IMyService
{}
This class inherits from the generated MyServiceClient but states that that client does implement the original interface.
(I suggest you put them in a folder named "ServiceProxies")
If the MyServiceClient class contains any methods that do not match with the original interface then you can add them in that proxy and do the conversion in code.
After this, just use the MyServiceProxy where you would have used MyServiceClient.

When you create the service reference, there is a box you can tick to make it reuse the shared definitions. Make sure the client project is already referencing the shared assembly, add the service reference again, and check all the options carefully.
If it still doesn't work, check the binding you use. I have a vague recollection that basic HTTP binding won't support re-using of types?

There is another good option, if you want to continue to use the proxy generator for it's limited-but-somewhat-useful functionality... Use a partial class:
namespace <same namespace as generated proxy>
{
public partial class MyClient : <namespace of "real" service contract>.IServiceContract
{
}
}
Ensure that the proxy is generating code the same way your Service Contract is defining it, ie, if it's using 'List', use that option in Configure Service References as well. In other words, make sure your generated Service Interface is exactly equal to your real Service Interface and the above code should work, and to update the reference you use right-click instead of writing code.

Related

Instanciate proxy of WCF service referring to the same instanciating class

I have a class implementing some audit methods (AuditcClass.cs). I have also implemented a WCF service that uses the AuditcClass.dll methods.
Now I need to be able also to reference the WCF service from within the AuditcClass. However I cannot simply use the generated proxies to reference it, since there are several conflicts with namespaces.
As first approach, I encapsulated the proxy within another namespace, solving many conflicts, but still introducing new ones with other general classes (as example, Exceptions namespace).
Is there an approach by which I could reference the web service within the class, even if the service uses the same class' methods and enums?
I was able to solve my issue by using the parameter /reference:<file path> of the svcutil tool: References types in the specified assembly. When generating clients, use this option to specify assemblies that might contain types that represent the metadata being imported.
This allowed me to exclude from the generated proxy the shared dlls avoiding reference conflicts.

Override ToString method in WCF service

This is my service generated class:
public partial class MyClass : object,
System.Runtime.Serialization.IExtensibleDataObject,
System.ComponentModel.INotifyPropertyChanged
{ }
I'm using my own service. In MyClass I have overridden ToString() but I don't have it in my client. I want either to generate it or as MyClass is partial am I able to override ToString myself?
I know that I can write in generated .cs file. What is the best way to do it and at all should I do it?
If you are defining both the client and the service, you don't need to use the WSDL-generate classes. Move the shared objects into a separate assembly, and reference it from both client and server projects. When you create the service reference, there's an "advanced" option (which I think is on by default) that reuses any known classes from the WSDL instead of generating new ones.
Even better, if you move the service contract into your shared library, you don't even need to create the service reference, you can just call the ChannelFactory directly and eliminate the entire auto-generated proxy class.
I have a demonstration on how to do both of these things on my blog: http://blog.kutulu.org/2012/03/proxy-free-wcf-ditching-proxy.html
If you absolutely need to use the WSDL from the service (e.g. you don't have control over the service side and it could change on you), then you can extend the partial classes that VS creates (as you suggested). Most auto-generate classes you get from VS these days are partial classes specifically to make this kind of extension possible. The downside, of course, is that nothing guarantees client and server's additional partial class methods are the same. I'd definitely consider this a last-resort option.
If you share the dll where overriden method exixts between client and server project, you can use the method. By default, WCF generates each class with only properties declared in the service interface. No method is generated.
You can just create a seperate dll file and put what you want to share between service and client into this dll; and add this dll as a reference to both client and service projects. By default, when you generate the proxy, it will not auto generate the shared classes.

Exposing Member Functions in a Custom Class through WCF

I have some member functions in three custom classes already created in my service. My objective is to use these custom classes on the client side to access the the member functions in the service. How do I expose these classes with all the member methods in them to the client?
I created these three classes in my service and marked them as "DataContract", and the member functions as "OperationContract". I created an Interface that defines these custom classes as OperationContracts returning an object of each of the classes through implementing them on a separate class.
Unfortunately, I couldn't achieve my objective because two of the classes have a constructor that takes some parameters, whereas the class with no constructor was accessible on the client side but I couldn't see the member methods in the class.
I need your hints on what to do.
That won't be easy to do. One way would be to share the DataContract-decorated types between the WCF server and its clients, i.e. add a reference to your service assembly in the client project and bind the service reference to that assembly reference.
However, that breaks contract implementation independence, as the exact same service assembly will need to exist on both the client and the server, and be kept synchronized every time it changes.
See here for more details.
By default and by design, WCF will only share contracts between client and server, e.g. your services ([ServiceContract]), their methods ([OperationContract]) and the data structures they operate on ([DataContract]).
WCF is a message passing system, so all the client and the server share in terms of the data being passed around is a XML serialized message format. When you add a service reference, the client-side proxy will generate a class for each [DataContract] that will look identical in XML serialized format - only the data is being moved back and forth - no behavior (no methods).
Basically, if you want to expose functionality, you need to have a service method decorated with a [OperationContract] attribute. Methods on your data classes will never be visible to the client - and that's by design.
If you control both ends of the communication and both are .NET based, you can "trick" your way around this limitation:
put all your service and data contracts into a separate class library assembly
use a reference to that common, shared assembly to create your service
before you do an Add Service Reference, add a reference to that common assembly on your client
In that case, the WCF runtime will reuse existing types from that common assembly, instead of re-creating them from the service description. And since that assembly contains the shared code that the server also uses, your classes also have their methods present.
It works ok in a .NET only scenario, but it's really kind of a dirty trick behind the proper service separation facade.

What does it do when you add a service reference in Visual Studio, through the GUI?

I'm currently trying to call a WCF service dynamically See here, therefore, I'm trying to understand what happens behind, when I add a service reference by the GUI of Visual Studio... What's generated..? An object is created and an implicit reference is created...
Are the references contained in a specific container, a sort of pool?
When you add a service reference, VS generates a proxy class for the service. This class implements the interface defined by your service endpoint as its ServiceContract, so it appears to consuming code as if it were the actual object performing the operations, but it contains and uses the communication channel defined by the endpoint and bindings to call the exposed service methods.
If you do not have classes that conform to the signatures of the DataContracts required by the service, VS will generate those classes as well, but if you have already referenced classes that are marked identically to the DataContract (usually because you've referenced the project containing the DataContracts in the project with the client-side code) it will simply use those. Svcutil (the command-line tool) can be given a reference list of locations for these DataContracts as well.

WCF Service that returns a custom class generates errors in Reference.cs

I have a WCF Service project in Visual Studio 2008 that contains about 12 methods, some of which return primitive types like bool or string. I also have a Visual Studio Unit Test Project that references the published WCF Service. The Test Project compiles successfully when all the return types are primitive.
If I add a new method to the service that returns a custom class, publish it and update the service reference in the Test Project, it doesn't compile. The errors are: -
The type 'PublisherFaultException' already contains a definition for 'Reason'.
The type 'PublisherFaultException' already contains a definition for 'PropertyChanged'.
Type 'Publisher.Test.LibraryReference.PublisherFaultException' already defines a member called 'RaisePropertyChanged' with the same parameter types.
all in the auto-generated reference.cs file.
The contract for the method of the WCF Service is: -
Page GetItem(string path);
and the Page class has the DataContract attribute and it's public properties have the DataMember attribute.
I'm reluctant to modify the Reference.cs file as I'll need to do this every time the Service is updated.
Anyone know why this is happening?
Stuart.
When you Add Service Reference, you get a 'reuse types in assembly' option - this is likely to be the key to sorting out the duplication.
Or do you have some Test References that are causing the duplication?
Also, have a look in the References section of the project tree and see if there is anything unexpected in there (do you have references to 2 assemblies that both contain Service References in the same namespace?).
Using auto-generated proxy class it is always pain.
To handle situation like this I using separate assembly with data contract classes and service interface.
Contract dll will have:
public interface IService
{
[OperationContract]
List GetContentList();
}
[DataContract]
public class ContentItem
{
[DataMember] public string Name;
[DataMember] public object Data;
}
The client will have reference to the Contract.dll.
Proxy will be created manually:
class ServiceProxy : ClientBase<IService>, IService
{
public List GetContentList()
{
return Channel.GetContentList();
}
}
The server dll will have reference to the same Contract dll.
So we will be able to avoid any errors with auto generated proxy.
Also the manually created proxy will be simpler, more manageable.
When adding the Service Reference, try clicking Advanced, and select "Generate asynchronous operations".
I think what was happening was that there were some asynchronous methods in the web service, with names ending in "Async", which would conflict with the methods generated in the References.cs.
e.g. imagine the web service contains 2 methods: (1)SayHello and (2)SayHelloAsync.
Generating using the default task-based method produces:
SayHello and SayHelloAsync for (1)
SayHelloAsync and SayHelloAsyncAsync for (2).
The conflict occurred because there were 2 generated methods called SayHelloAsync.
At least I think that's what was going on. Anyway setting "Generate asynchronous operations" worked for me.

Categories