WCF Client generation possible based on ServiceContract alone? - c#

I have a Visual Studio Solution in which a WCF server is contained; the service is defined as an interface using the ServiceContract attribute. The service is finally hostes via an instance of ServiceHost using HttpBinding, which is the intended behaviour.
In the same solution, there is a client; currently the hosted service is consumed by starting the server manually and generating a proxy class using "Add Service Reference", which can be updated as soon as the server is running.
While this works in the sense that the outcome is as desired, I wonder if it is possible to remove the manual start of the server to update the service reference in the client. Is it possible to build the client by just sharing the DataContract attributed interface between server and client without actually running the server and importing the service definition manually in the client? If yes, how can it be done?

Another way is to use svcutil to generate proxy, but even that require WSDL metadata to generate proxy and that is usually available by starting service, you can save it once from the running server and you can use that to generate proxy without starting server later on.
see different options http://www.codeproject.com/Articles/33297/WCF-Proxy-Generation-Options
I personally like hand crafted client as I have better control on code/error handling and I can use shared DTOs from common dll.

Yes, you can use a common data contract, shared between the client(s) and host, to maintain the interface between both sides. That's what I do with this big data sync WS built on BasicHttpBinding.
In a nutshell, I have a host project, with a service contract and the functioning/processing code, referencing a very small project (and DLL) containing only the data contract class definition; just class, constructor, variables and in/out parameters.
That same small project containing the data contract is also referenced by a client-side project that handles all of the interaction between our client programs and the Sync WS. We actually have every web service call (from the simplest Ping() function to the most complicated RetryFileUpload() function) running through that data contract. All the string-based parameters and binary data is passed through the data contract class, then seriailized or deserialized on the receiving end.
Having said that, this approach only works when you have .NET code on both the client and host. We also have Android and iOS clients that are forced to emulate this behavior ... which isn't a big deal, obviously. But this is the approach we took.

Related

What does "Add Service Reference" really do?

Forgive me if the question is incoherent.
I find WCF really complicated. Moreover, different ways to do the same thing make a beginner even more befuddled, like hard-code a host vs config file, or hard-code a client vs add service reference. (Am I feeling right?)
I think it would be helpful to try to go through the process with code in a primitive way. No service reference, no config file.
Maybe I can put it this way: If the service is running on another machine (or my machine pretending another machine), what are the minimum things it has to provide beside an address for some one to consume it?
And how can I consume it with code?
Add Service Reference parses the WSDL of the service to import the service contract, and potentially any referenced domain types, into the client's representation (in this case, C#). It generates a proxy which exposes a C# interface that represents the service contract. The proxy is a namespace and set of classes with methods to call each service method for the particular endpoint.
In short it takes service contract metadata and reifies it to C#.
You can also manually generate the proxy with 'svcutil.exe'
svcutil http://server.com/FooService/FooService.svc /out:FooProxy.cs
Or to include generation of the app.config as well
svcutil http://server.com/FooService /out:FooProxy.cs /config:App.config
Visual Studio "Add Service Reference" does that for you, plus adds the new files to your project.

Consuming the same WCF service from different addresses

I have a single WCF service but, until runtime, I don't know the correct address of the service. It may be :
http://example1.com/MyService.svc
// or
http://example2.com/MyService.svc
The service is used by a class library (DAL). I have two options:
Add a service reference to the
service (Visula Studio 2010) and
change the address at run-time. This
way VS-2010 will create WSDL and
other stuff for me (I'm not sure if this is even possible).
Create the proxy on the fly and set
the base service address. This needs
more work and if I make any change
to service, I need to generate WSDL
myself. Maintenance of this code is
not as easy as option one.
Which option to use? Also if option two is recommended by you, then should I my client wrapper class be singleton or I can create all the connection stuff on each call?
you can point to localhost or any other address in development then in production if the url changes you simply modify the web.config or the app.config where you have configured the WCF end point.
Option 1 - you get all the advantages and none of the pain. Just use something factory-oriented (i.e. Don't do new MyProxy(), but instead stick that code somewhere central like a static CreateMyProxy() method, or consider an IoC/DI container).
How to consume WCF web service through URL at run time?

Extending a WCF service and its auto-generated client service reference

I am relatively new to .Net and C# development and am having an issue decoupling WCF services from an app into a network DLL I am creating. The DLL's goal is to offer a simple way to host and access a service from a server and client application and to add some functionality to the basic service for heartbeat and automatic reconnection without each application having to specify heartbeat methods in their WCF services and witho/ut having the apps manage a timer for automatic reconnection.
The DLL offers a ServiceServer and a ServiceClient class that have these goals:
ServiceServer :
Creates and manages the ServiceHost instance.
Host a service from outside the DLL (passed as a generic).
Add heartbeat operations to the service to be hosted, as well as other operations common to all our client/server apps.
ServiceClient :
Creates and makes the client service reference available to the client application. The service reference (auto-generated) is also passed as a generic from the application.
Add heartbeat methods to the service reference for the client, as well as other operations common to all our client/server apps.
Automatic reconnection using a timer or similar.
So far I have tried to use partial classes, generics and static extension methods without success. The issue is that to make my DLL completely decoupled I obtain and create the service reference and service using generics; I am unable to extend the received generic type using any of these approaches.
I am basically trying to extend the client service reference with additional methods to be able to send heartbeats and such without needing another independent connection and service (which would make the heartbeat ineffective), and without the client application having to know anything about sending heartbeats and automatic reconnection. Likewise, I want to extend the service that the server class receives as a parameter to add operations and the implementation of the server heartbeat code and eventually other common-to-all-apps methods too.
You might want to explore this solution for implemeting hearbeats automatically in a wcf services.
http://weblogs.asp.net/cibrax/archive/2010/05/17/enabling-service-availability-in-wcf-services.aspx
The solution also provides an extension method for the client.
Thanks
Pablo.
No it will not work this way.
When you define the service you first create one or more service contracts (best practice is to use interfaces). Service contract interface has to be marked with ServiceContract attribute and each exposed method used in service has to be marked with OperationContract attribute. Then you create service class which implements these interfaces. Such class can be exposed as WCF service with endpoint for each interface (service contract).
No other approach works. You can't add extension methods, use generic or whatever else to "extend" implemented service. What you can is to inherit existing service class and add additional interface. Obviously this is not no code solution unless you create some very advanced code to generate dynamic data type at runtime (= emitting MSIL at runtime).

Creating web service and client with shared types

I have created two wsdl files with shared types imported from xsd schema file.
After that I have created web services using interface generated by wsdl.exe tool with parameter /serverInterface.
Frist web service, have web method “RegisterData” with put into queue some complex object to be processed, by system “A”. As result of this method is returned Boolean (with tell us that object was registered successful).
Second web service, have web method “UpdateData” to update some data in system “B” based on this same object , with was changed in process on system “A”.
So in system “A” I have to create client for second web service, where I will call method “UpdateData” with this modified complex object us argument.
But when I’m creating this client in Visual Studio (by add web reference or add service reference) I have to create some namespace for client. And then when I’m trying to call “UpdateData” agument have different namespace for this same object received from first web service “RegisterData” method.
I would like to create first web service and second web service client , where I can use this same type object between them.
Thank you very much for help.
I don't believe this is possible with ASMX web services.
WCF does support this, however.
WCF Links:
WCF Developer Center
Beginner's Guide to Windows Communication Foundation
How to: Configure a Service to Reuse Existing Types
Actually, I think I may have misread your question. I though you were trying to share the same types between the client and the server. ASMX cannot do that. However, it appears you are trying to share the same types between two client proxies. You can do that easily using the WSDL.EXE tool.
Consider a schema, DataTypes.xsd, and two WSDL files that import it, ServiceA.wsdl and ServiceB.wsdl. To create the server interfaces, use:
wsdl /serverInterface /n:SharedTypes.Servers /out:Services.cs ServiceA.wsdl ServiceB.wsdl DataTypes.xsd
This will create interfaces which you can implement in order to create your services. These interfaces will both use one set of classes created from DataTypes.xsd. To create the proxy classes, simply use:
wsdl /n:SharedTypes.Proxies /out:Proxies.cs ServiceA.wsdl ServiceB.wsdl DataTypes.xsd
Notice that you do not need the /sharedTypes switch. That has a different purpose. It is for combining types of external services when you need to download the WSDL and any XSD from the service.
I have tried this using an example like yours, ServiceA posting a message into a queue, and a client picking up that message and sending it to ServiceB. It works quite well.
I agree that it is not possible to do this via the VS Web Reference functionality. To meet your requirements you can use the wsdl.exe utility with the /sharetypes switch.
For more information see Web Services Description Language Tool (Wsdl.exe)

wsdl.exe/svcutil.exe - is there a way not to generate the classes for types in the xsds during a Web service or client generation

We have a centrally managed object model for types in the schema in C#.
We want every one across the enterprise use that object model instead of using the one generated each time from wsdl/svcutil during a webservice client or service implementation.
is there a parameter(any other way) to wsdl/svcutil not to generate classes for the schema types during theie execution?
I believe what you are looking for is: svcutil.exe /r your-dtos.dll
/reference: -
Reference types in the specified
assembly. When generating clients, use
this option to specify assemblies that
might contain types representing the
metadata being imported. (Short:
/r)
In my opinion the tight coupling of the WCF proxy, endpoint channel, service operations and dto payloads into the same generated client proxy is a major design flaw.
This is what spurred me to solve in my open web services framework where I decouple the end point and payload which allows:
The same web service client (i.e. Soap11, Soap12, XML, JSON) to be able to call any web service.
It lets me also use the same DataContract dto instance in any of the web service clients
This has many benefits including being able to expose the same web service on a number of different end points without any extra configuration. Thus providing optimized web service endpoints for each consumer of my service. E.g.
XML for interoperability and strongly-type clients,
JSON for Ajax clients,
WSDL's for environments that prefer generated code (i.e. Flex Builder, VS.NET 'Add Service Reference' etc)
At my company we have developed hundreds of web services called by a number of different clients i.e. Ajax, Flash/ActionScript, C++, Silverlight, ASP.NET and being able to call the same web service through different endpoints has saved us countless hours.
I don't know of any specific setting or command line switch to enforce this - what you can do, but that's mostly a matter of training and enforcing by checking, is to share the class library (the assembly, in a DLL) with the developers, and make sure that everyone references that common class library and leaves the default settings in the "Add Service Reference" dialog (on the "Advanced" page) alone:
Here, you define that WCF will reuse any types it can find in any of the referenced assemblies - so if your developers add a regular reference to the common data contracts library, then WCF will use those types instead of re-creating them over and over again.
But again - that's only a "management by example and checking" kind of approach - I don't know of any technical way to enforce this.
If you remove the mex endpoint from the service config file, the client app will not be able to discover and generate the proxy objects.
A way to handle this situation if I understand your question correctly is to do the following:
Create a common set of DLLs that has the service, and datacontracts / shared object model.
Create a service using the contracts in the common dll instead of the contracts visual studio creates when you create a new service.
Remove the MEX endpoint from the server config file (this will essentially break proxy generation).
Have your client use the the common dll and manually create the channels on the client side (via channel factory etc...).
In this approach you do not use wsdl.exe/svcutil.exe at all since you are essentially bypassing the wsdl. You do not add service references either since you are manually managing the connections.
EDIT: Following this approach, the client can still try to generate proxy objects via wsdl.exe/svcutil.exe, but they won't get the correct information from the wsdl. They'll essentially generate a non-functioning / incomplete proxy.

Categories