I have several message contracts that use an external library to standardize a particular functionality between several services. Their code looks somewhat like this...
using System.ServiceModel;
using Query.Search;
[MessageContract(WrapperName = "MyMessageContract")]
public partial class MyMessageContract
{
[MessageBodyMember(Name = "Search")]
public SearchTerms Search { get; set; }
}
The SearchTerms class is in the Query.Search DLL and looks like so...
public class SearchTerms : List<SearchTerm> { }
... with the SearchTerm class also in the same DLL. It works just fine in the service and knows that I'm addressing the Query.Search classes, but when I generate the proxies, these classes are reassigned to the wrong namespace and make it very difficult to build a service adapter in the UI. I'm using svcutil with the following arguments...
/t:code /mc /n:*,MyProject.UI.Proxies /ct:System.Collections.Generic.List`1 /l:cs
/o:WSProxies.cs /config:output.config http://localhost:49207/Service1.svc?wsdl
http://localhost:49207/Service2.svc?wsdl http://localhost:49207/Service3.svc?wsdl
Now, I understand that the namespace argument as it's defined here is basically assigning all my proxy namespaces to MyProject.UI.Proxies and if I remove it, the namespaces for my Query.Search class are set correctly. However, this means that all the other proxies now fall under the default "MyService.DataContracts" namespace in which they're defined. So I tried using...
/n:MyService.DataContracts,MyProject.UI.Proxies
... but had no luck as the output reverts to "MyService.DataContracts" after it's generated. What I'd like to be able to do is for my proxies to have the UI namespace of "MyProject.UI.Proxies" while maintaining the namespace for the SearchTerms class as "Query.Search" without manually modifying the output file so a new run of svcutil doesn't wipe out the manual changes. Is this possible and am I just using the /namespace argument wrong, or will I have to manually modify the output file every time I generate proxies?
EDIT: After a fruitless day of trying to get this working, I simply created a workaround, creating a set of similar classes in the services and translating them to the Query.Search ones. Would still be interested to know if what I wanted can be done but form what I've gathered, using these classes in a message contract sort of dooms it to be listed under the same namespace as the MC.
You should tell svcutil to reuse your classes instead of fighting with proxy namespaces.
This is achievable using /reference parameter.
It also will be good idea to move all such classes to separate assembly. Otherwise you will have direct reference between WCF server and client what is not good architecturally.
Check this link for sample:
http://blogs.msdn.com/b/youssefm/archive/2009/10/09/reusing-types-in-referenced-assemblies-with-svcutil-s-r-switch.aspx
You also can do the same task in Visual Studio. See my answer here:
How to use a custom type object at the client
Update:
I did some investigation. You are right SVCUtil does not generate proxy classes if you references assembly that contains all interfaces and data contracts.
That behavior is different from Visual Studio. Visual Studio seems to not use SVCUtil work with WCF directly.
This is command line I tried:
C:\Windows\system32>svcutil /directory:D:\prog\myfolder /r:"D:\prog\SampleWcf\Server\bin\Debug\Contract.dll" http://localhost:8080/Service/mex
One difference from your code is that I used metadata instead of wsdl.
You have two options:
Generate proxies in Visual Studio.
Work with Service without profies using ChannelFactory
BasicHttpBinding myBinding = new BasicHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress("http://localhost/MathService/Ep1");
ChannelFactory myChannelFactory = new ChannelFactory(myBinding, myEndpoint);
IMath wcfClient1 = myChannelFactory.CreateChannel();
http://msdn.microsoft.com/en-us/library/ms734681.aspx
Related
I'm writing a simple command line .NET application that retrieves data from a SOAP endpoint. I'm using WCF and Visual Studio 2017.
The SOAP service has about about 20 endpoints, each with its own WSDL. So far I was able to add a single working endpoint by adding a Service Reference in VS 2017. When I go to the Service Reference dialog, and add the WSDL for the endpoint, VS helpfully generates a Reference.cs with implementation for an Interface, Client, Collection, and Record. So far so good. As long as we're only dealing with a single endpoint.
The problem is that, now all of this auto-generated code is blown out, I need to write some semi-generic code to iterate through and call each of these endpoints. Clearly there's got to be some way to call client.process(requestMessage) without explicitly handling 20+ types.
The problem is that none of these generated classes have any sort of common base class or interface. For example, VS generates client, collection, and record classes for SuperDuperService:
superDuperInterfaceClient
responseMessageSuperDuperCollection
responseMessageSuperDuperCollectionSuperDuperRecord
The signatures for the above types are:
public partial class superDuperInterfaceClient : System.ServiceModel.ClientBase<the_project.SuperDuperService.superDuperInterface>, the_project.SuperDuperService.superDuperInterface {
public partial class superDuperCollection : object, System.ComponentModel.INotifyPropertyChanged {
public partial class responseMessageSuperDuperCollectionSuperDuperRecord : object, System.ComponentModel.INotifyPropertyChanged {
So... what gives? I'm sure I'm missing something completely obvious, but haven't been able to find anything that addresses what you'd think would be pretty straightforward. Apologies in advance most of my exposure to the .NET and C# world has been pretty ad hoc. Thanks!
I'm having my Web Application which hosts Webservices (svc) which are used in a Silverlight Webapplication. After a while I added some new stuff to my Service and now I tried to refresh my proxy classes in the Silverlight Application Project.
Unfortunately, Visual Studio now generates new class names.
Before I had this:
public SilverlightApplication.ServiceReferenceDoc.Document Document
but now I get a different class name (number one behind the name)
SilverlightApplication.ServiceReferenceDoc.Document1 Document
Which is really bad because my Silverlight Projects have a lot webservices and these have a lot of code which uses these proxy classes.
So far I found out it generates the proxy class 2 times.
Some ideas why this renaming is happening? I already tried VS2015, VS2013 and also I deleted the complete reference and add it again, but it's the same.
We had mixed EF classes with own classes. That caused the generation of two classes with the same name.
I have WSDL and XSD as starting point. (WSDL is generated from XSD using WCSF Blue tool). From the WSDL, using a tool, the service code is generated. The project name is “Autogenerated_Service_Project”. Inside this project it will have [ServiceContract] and [DataContract] classes. It has a data contract named “EmployeeDataContract”. In the GetEmployee() service operation, this datacontract is returned to the client.
I have a business layer project named “Business_Project”. It has a method that returns “Employee” entity object.
At present, I am referring the “Business_Project” inside “Autogenerated_Service_Project”.
Business_Project.MyClass b = new Business_Project.MyClass();
EmployeeDataContract d = b.GetAssociate();
return EmployeeDataContract;
The challenge comes when there happens a change in WSDl. When the WSDL is the changed the “Autogenerated_Service_Project” will be recreated and the code mentioned above will be lost.
What is the solution to overcome this code lose?
Note: The “Autogenerated_Service_Project” is the top most project. Ideally, it cannot be referred by any other projects.
You may change the way calling Business layer(may your solution needs additional layer)
But in simple way, you can generate the proxy once, when changes happen to WSDL
handle the changes manually,Or use the tool only for new services.
If the services on WSDL are finely grained, the solution may be applicable.
This can be resolved by using Partial Classes in a different file. The code given in the question can be moved to this new partial class file. This file will persist even if the auto generated file is re-created.
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.
My service uses a type Foo defined in another DLL, and my client also uses that DLL to get that type. Rather than generating a proxy class for that type, I'd like the proxy code to just refer to the real type. I can accomplish this manually by generating the proxy with WSDL.EXE on the running service, manually editing out the partial class Foo definition from it, and adding a Using statement. I'd like to do it without hand-editing if possible.
It seems like maybe the answer is to use SVCUTIL.EXE instead of WSDL.EXE. There are two intriguing options: /R and /ET. I tried putting /ET:Foo and /ET:My.FQN.Util.Foo, and /ET:www.my.com.the.servicenamespace.Foo, and also adding the DLL filename to the option. But nothing changes in the ServiceWithFoos.cs proxy class that gets created. The partial class definition for Foo is still there.
Am I on the right track? What am I doing wrong?
Add [DataContract(Namespace = "http://anything.here")] to your Foo type, then use svcutil with the /r option taking the path of the library containing Foo. This way svcutil should see the same contract namespace and map Foo correctly.