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.
Related
I have two service references that I am importing into my asp.net project by importing a WSDL for each. The first reference is a default reference from my web service (Acumatica) and the second is a custom endpoint service I created in the original web service.
The problem is that both of them use the same "base types" in their object classes so when I include both namespaces to use the objects from both of them in my code, I get an error saying there ambiguous references between the base types in the two namespaces. Makes sense. But how can I set this up so that .net knows to re-use the base types between the two namespaces since they are exactly the same?
To show what I'm talking about:
You can see there are types that are exactly the same between the references. Can I configure these references to re-use those types between the two of them to get rid of my ambiguous reference errors?
Unfortunately, there's no way of achieving what you want.
The thing is, the base classes used are not the same (they have different attributes which leads to different XML (de)serialization). To add insult to injury, when we researched this issue, we've found out that WCF client utility which you use to generate client-side code does not support reuse when XMLSerializer is used, so even if Acumatica made the base classes exactly the same, there still wouldn't be any reuse on client.
But why do you need to different endpoints simultaneously? If your own endpoint is only adding functionality to Acumatica's Default, why not consider extending Default? This way you'd need only one endpoint in your code.
Create a class library (e.g. "MySharedContracts") where you place all the types you want to use in the web services. You can reference that same class library in your web service projects and in the ASP.net project that consumes the web services.
Then, in the ASP.net project when importing the WDSL definition, click on "Advanced" to open the "Service References Settings" dialog. In here, enable "Reuse types in references assemblies". You can then either let VS search for fitting types by itself by selecting "Reuse types in all references assemblies" or alternatively specify a set of assemblies that you want to use types from for the web services.
When I use svcutil or some other proxy generator it creates appropriate classes in client. I wonder what is the best way to store this classes to avoid conflicts.
In some other "Common" project and remove generated classes from proxy?
Or just use original classes in service and theese duplicated in proxy?
There are two ways to handle the code for service and data contract classes WCF clients.
Generate everything using svcutil.exe. Don't have any kind of reference from your client project to the service assembly. Just use the classes generated by svcutil.
Reference the assemblies containing the types directly. I sometimes use a separate assembly for my DTO classes, that is references from both the client and the server. When generating the client code with svcutil, use the /reference:<file path> option to tell svcutil to reuse the types from an existing assembly instead of regenerating them.
If you reference the origin assembly, without passing it with /reference to svcutil you'll end up with a mess of conflicts. I guess that's what happened to you.
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.
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.
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.