I am trying to write some code in C# that will call a WCF service on the fly by importing the WSDL, examining it and then making calls to it dynamically.
The service I am calling can change from time to time - so if it does I want my client to know about new methods and new input parameters and output parameters to the calls, without rebuilding my client.
One possible solution to this is to import and compile a service reference on the fly.
Outlined here: Creating an assembly on the fly from a WSDL
I would like to avoid the generation of an assembly and then reflecting over it if possible.
I looked into the code of the dynamic proxy in the link and they use a framework class to do the import. This class is the WsdlImporter. So I had thought great - I can use that and examine the WSDL schema and determine what calls are present and what inputs and outputs are available.
The problem is that the type information is missing in the MessagePartDescription objects that the WsdlImporter creates. Apparently this is missing because it cannot find the types yet - see the response to the question from Brian.
So any advice on how I should proceed? Am I completely on the wrong track here?
This is probably not an answer but I will post it as one to fully describe my opinion.
Dynamic proxy:
IMO this is example of wrong usage of technology. It is elementary behavior of WSDL - if it changes you have to change client or you have to make good WSDL versioning and create new client.
You still have to somehow say your client to get WSDL - does it mean that you will parse WSDL before each call? Doesn't seem like a good idea.
Information about types is really not part of WSDL because by default WSDL is generated as interoperable. CLR types are not operation needed for interoperability. When you create service proxy by Add service reference or Svcutil it will generate code for types defined in WSDL. That code then need to be compiled.
You can try to use NetDataContractSerializer instead of default DataContractSerializer. NetDataContractSerializer adds CLR type information into WSDL but I still expect that new types must be known to your clients - it means deploying new assembly with types and use it by clients. This almost sounds like same approach when simply deploying assembly with new static client proxy.
Dynamic WF client
I also don't see too much usage of this architecture - you still need to change client to reflect new WF steps, don't you?
Changing the WF
Are we talking about Windows Workflow foundation? I can hardly imagine scenario where you create WF, expose it as a service and then change it. When you expose WF as service you are probably defining long running WF. Long running WFs use persistance which is based on serialization (at least in WF 3.5 but I believe it is same in WF 4). When you change WF definition, all persisted WFs are most probably doomed because they will never ever deserialize. This situation is usually solved by parallel deployment of new and old version where old version is only used to finish incomplete WFs. Again it means new clients.
If you look at the problem from a different angle. Do you need to regenerate the proxy each time or do you need a contract that continues to work when things change?
WCF has a mechanism for this IExtensibleDataContracts see: http://msdn.microsoft.com/en-us/library/ms731083%28v=VS.100%29.aspx
Best practices for versioning of contracts can be found here
Related
I am new to WCF service. I am aware about three ways to generate proxies.
Using Service reference
Using SvcUtil
Using ClientBase
But I am confused in which case I should use which type. In my case I have to generate proxies for third party service for which I don't have service code. I don't want to use add service reference because it gives me following issue. Mentioned in this stackoverflow question. So I want to use clientBase. But I think I cannot use it without using service reference. I am pretty much confused when should we choose which kind of proxies.
In my case I have to generate proxies for third party service for which I don't have service code.
I will have multiple apps using this service.
In that case you are better off using SvcUtil because it can generate a single library that all of your projects can use, even if they are .NET libraries. After it is generated you can always go in and tweak it.
Add service reference on the other hand is fine for a single .exe but as you have discovered, is annoying for multiple apps as you need to repeat the process and you end up with multiple definitions of WCF types that is just going to increase maintenance.
Just be sure to leave WCF client config in the app.config of your applications and not your app.config of your class library (as the former may not be read).
If your vendor had followed "WCF the Manual Way… the Right Way" it would have made your life easier.
SOAP purists would argue however that the only thing the vendor provides is a SOAP WSDL XML file from which you are required to generate your types anyway. (sadly, the default behaviour in .NET is back-to-front)
I've started using some web services that have a staggering amount of redundancy when added as web services in Visual Studio 2012. Here are two WSDLs that demonstrate this:
http://webservices.sabre.com/wsdl/sabreXML1.0.00/usg/SessionCreateRQ.wsdl
http://webservices.sabre.com/wsdl/sabreXML1.0.00/usg/SessionCloseRQ.wsdl
These are services to create a new session and to close it, respectively. Each service has its own MessageHeader class, which in turn has a member that's from a MessageData class that's redefined in every generated proxy. There are others like this but I won't name them all.
This makes it difficult when I want to create a helper function that sets up my request and fills in all the common stuff in the envelope such as timestamps, authentication, etc. because Service1.MessageHeader is not the same type as Service2.MessageHeader. I've experimented with duck typing, but as far as I've seen the nested nature of this would prevent that approach.
Looking at the WSDL, these classes are all defined as being from the same namespaces. In other words, in both WSDLs, MessageHeader is defined as:
<xsd:import namespace="http://www.ebxml.org/namespaces/messageHeader" schemaLocation="msg-header-2_0.xsd"/>
...
<part name="header" element="eb:MessageHeader"/>
Is there some way to make VS understand that these are the same thing in both classes and somehow get it to separate them out as common to both? Or is it "a web service is an island"? I'd really rather not have to create separate code for every single type of web service I'll need, as there are far more than just these two. But every one of them uses these same classes.
I've thought about going in and hacking up the proxy classes by hand. But beyond my fear that this would make VS slip some gear because I'd messed up what it was doing behind the scenes that it never expected me to tinker with, I'd lose the whole auto-generation should something change in the WSDL that needed resyncing.
I've tried this both in C# and in Oxygene and run into the same issues. I imagine it'd be the same in other languages under VS. It seems related to how it understands WSDL.
Before anyone asks, I can't change anything about the actual web services. That is another company altogether, and not one that will be interested in redesigning their widely used system based on my whims.
I've found a potential solution to this, and it works in every way I can tell. But I'm open to criticisms or "a better way" (including a better way to do it from the GUI).
I've found that using the following command generates the proper "single unit" type of interface I want with all the types shared:
wsdl.exe /sharetypes /language:CS "http://webservices.sabre.com/wsdl/sabreXML1.0.00/usg/SessionCreateRQ.wsdl" "http://webservices.sabre.com/wsdl/sabreXML1.0.00/usg/SessionCloseRQ.wsdl" /o:"SabreWebServices.cs" /n:SabreWebServices
That creates a C# one. For Oxygene, I use:
wsdl.exe /sharetypes /language:OXYGENE "http://webservices.sabre.com/wsdl/sabreXML1.0.00/usg/SessionCreateRQ.wsdl" "http://webservices.sabre.com/wsdl/sabreXML1.0.00/usg/SessionCloseRQ.wsdl" /o:"SabreWebServices.pas" /n:SabreWebServices
FWIW, I used the wsdl from the "c:\Program Files\Microsoft SDKs\Windows\v8.1A\bin\NETFX 4.5.1 Tools directory on my machine.
I added the resulting wrapper file to my application and it worked perfectly, if a bit differently than the wrappers created through Add Service Reference. I actually prefer the syntax this created a bit more. It also had the benefit of creating only the one file rather than numerous ones and not mucking with app.config. If you want to change the endpoint, you can just set the Url property of whichever service you instantiate.
I arrived at this solution at this post this via this post.
looking at
WCF ChannelFactory vs generating proxy
appears that the best practice in creating a WCF client is to create a proxy (Not autogenerated).
I've been looking online for a while and i didn't find any complete example(Proxy class, web.config)
Could you provide an example or links to resources?
This article is about exactly what you're asking, I believe:
WCF the Manual Way... The Right Way
Having shared that, though, creating your proxies manually is probably not always the best possible use of your time. The article goes into some great reasons for doing so - you'll certainly have more control, your clients may have an easier time, etc. but overall, doing things manually like this will require more of your time, and explaining to users of your service exactly how to use the proxy you provide may be a pain.
There's a reason WCF allows metadata exchange and discovery and VS will auto create proxies for you.
Either way, it's a cool article and a technique well worth learning.
This is how I do it.
Get service contracts and data contracts
If I have access to the service code, I have all the contracts. If not, I can use svcutil or Add Service Reference to generate them.
Make config
I use Add Service Reference just to get the app.config file. I then delete everything else it generates. Edit the app.config as necessary.
Define factory
Say I have a service contract IFooService:
interface IFooServiceChannel : IFooService, IClientChannel { }
That is literally it. No members.
Create factory
fooServiceFactory = new ChannelFactory<IFooServiceChannel>(
"NetTcpBinding_IFooService");
The string "NetTcpBinding_IFooService" is the name attribute of the binding element in app.config.
Create channel
fooService = fooServiceFactory.CreateChannel();
Use it
fooService.DoSomething();
The trickiest part is getting app.config right. You need to learn about bindings and endpoints. It's a bit of a learning curve, but nothing drastic.
Here are the basic steps.
Create your service like normal.
Move the interface that your service implements into an assembly that can be shared with the client.
Create a ChannelFactory where T is your interface. You will have to give the uri of your service to the constructor.
Call factory.CreateChannel(). This will be type T.
Use the channel to make calls.
It is really that simple. No auto generated code, no service references. It gets a little more complicated with async calls and Silverlight, but not too much.
WCF beginner's question: I've been told that changing the WCF contract is costly and requires constant maintenance (recreating the proxy in the client side), and therefore the preferred method is having one very generic point-of-contact method (which decides how to act, say, according to a given enum parameter).
This sounds quite smelly to me, but I haven't been able to find any information about this issue (bad choice of search keywords? probably).
Any advice, or maybe a useful link?
Thanks!
You don't need to generate the proxy again, you can simply ensure the client is built with the correct interface version. If you're very careful and only add methods, not remove or modify, that works just fine too. That's a lot of responsibility to manage, of course.
To use an interface rather than generate a client proxy, check my question from a while ago:
WCF Service Reference generates its own contract interface, won't reuse mine
You are confusing some terms here and I think you might be referring to a known flaw which has been fixed in .Net 3.5 SP1.
Recreating the WCF proxy used to be an expensive operation at runtime. This has been improved in .Net 3.5 to cache the proxy objects transparently MSDN Blog.
If you are referring to the "code maintenance" of the proxy, then all you are referring to is implementing an interface at the client. If you need to maintain the interface then this comes back to basic SOA. If your services provide access and as much information as possible, assuming that your service will be used for purposes you haven't yet considered then you will likely not need to modify the interface after it is created. You should also consider your upgrade paths as well.
Juval Lowy has a good discussion about this problem in his book which is a little dense but has some pretty good information in it.
A piece of advice: WCF has a whole lot of features designed to make your code really simple and elegant. If you are worreid about maintenance, what you may be driven to do is write an interface:
string ServiceMethod(string xml) //returns XML
Don't do this. Take the time to design a good maintainable interface and a good data/message contract. This will let WCF provide all the extras you get for free when hosting your service for interaction.
Generic (as in non-specific, monolithic) interfaces are hard to understand and program to. The reason not to define a single method as the API is that it's impossible for clients to understand what's going on, and when you change the (implicit) API of this interface, your clients will break in horrible ways that you won't detect at compile time.
It's been a while since I touched WCF, but if your clients are internal (same codebase, versioning and deployment schemes), then regenerating the WCF proxies is very easy, and having a "strong" detailed API will make your life so much easier than a generic one.
It depends on what kind of change you mean. Change to the service contract is indeed costly and should not happen. Service contracts are (or should be) at a sufficiently high level of granularity that change is very rare.
More common are changes to the types which are exposed on the service. These changes are more common and therefore you do need to approach your change in such a way as to avoid breaking existing clients if possible.
There are several ways you can do this, such as exposing your types polymorphically using an interface, but the simplest way is to simply ensure that changes to your types on add new data member fields and make the new fields non-mandatory. If you can limit your changes to these then this is has the lowest impact to existing clients and enables new clients to use the new fields.
Hope this helps.
This is true that modifying the service contract (interface) would also required the client to recreate the proxy class at their end using the new published WSDL and may even require the client to change their code as par the new proxy. I don't think you can create such a generic interface that can handle all changes further down the road in the contract. A contract has to be written very carefully so that it doesn't change often and if there is a need to change the contract then it is better to deploy the service with a different version so that your old client can still work with the old version.
Consider the following Visual Studio project structure
ProjectA.csproj
AClass.cs
ProjectB.csproj
References
ProjectA
Web References
AWebService
AWebService.csproj
References
ProjectA
ReturnAClassViaWebService.asmx
The issue occurs when ProjectB adds the web reference to AWebService and automatically generates all the proxy code for accessing AWebService including a new implementation of AClass. Since all of our other code needs to use the AClass defined in ProjectA, we're forced to convert the AWebService.AClass returned from the service into something we can use.
We're currently considering two solutions, neither of which are ideal.
Manually editing the generated Reference.cs to remove new definitions of AClass
Serializing AWebService.AClass to a stream then deserializing to ProjectA.AClass
Does anyone have any better solutions? This seems like something common enough for other developers to have experienced it.
Ideally we would like to have the proxy code generated in ProjectB to reference ProjectA.AClass rather than generating a whole new implementation.
Our environment is VS 2008 using .NET 2.0.
I have had the same problem that you are describing and I have tried both of the options you specify without being entirely happy about either of them.
The reason we both have this issue is at least partly because the shared-library-between-consumer-and-provider-of-a-web-service-solution is in violation of accepted patterns and practices for web service design. On the consumer side, it should be sufficient to know the interface published in the WSDL.
Still, if you are prepared to accept a tight coupling between your web service provider and web service consumer and you know for certain that your current client will never be replaced by a different client (which might not be capable of referencing the shared library), then I understand why the proposed solution seems like a neat way to structure your app. IMPORTANT NOTE: Can we really honestly answer yes to both of these questions? Probably not.
To recap:
The issue appears when you have classes (e.g. a strongly typed dataset) defined in some sort of shared library (used on both client and server).
Some of your shared classes are used in the interface defined by your web service.
When the web reference is added there are proxy classes defined (for your shared classes) within the web reference namespace.
Due to the different namespaces the proxy class and its actual counterpart in the shared library are incompatible.
Here are four solutions that can be tried if you want to go ahead with the shared library setup:
Don't. Use the proxy class on the client side. This is how it is intendend to be done. It works fine unless you simultaneously want to leverage aspects of the shared library that are not exposed by the web service WSDL.
Implement or use a provided copy/duplication feature of the class (e.g. you could try to Merge() one strongly typed dataset into another). A Cast is obviosuly not possible, and the copy option is usually not a very good solution either since it tends to have undesirable side-effects. E.g. When you Merge a dataset into another, all the rows in the target dataset will be labeled as 'changed'. This could be resurrected with AcceptChanges(), but what if a couple of the received rows were actually changed.
Serialize everything - except for elementary data types - into strings (and back again on the consumer side). Loss of type safety is one important weakness of this approach.
Remove the explicit declaration of the shared class in Reference.cs and strip the namespace from the shared class wherever it is mentioned within Reference.cs. This is probably the best option. You get what you really wanted. The shared class is returned by the web service. The only irritating drawback with this solution is that your modifications to the reference.cs file is lost whenever you update your web reference. Trust me: It can be seriously annoying.
Here is a link to a similar discussion:
You can reuse existing referenced types between the client and service by clicking on the 'Advanced' button on the 'Add Service Reference' form. Make sure the 'Reuse types in referenced assemblies' checkbox is checked and when the service client is generated it should reuse all types from project A.
In past versions this has not always worked correctly and I've had to explicitly select the shared type assemblies by selecting the 'Reuse types in specified referenced assemblies' option and then checking the appropriate assemblies in the list box. However, I just tested this with VS 2008 SP1 and it appears to work as expected. Obviously, you need to make sure that the types that are being used by the service and client projects are both from project A.
Hope that this helps.
We encountered a similar problem with one of our projects. Because we had several dependencies, we ended up creating a circular reference because project 1 required objects from project 2, but project 2 could not be build before project 3, which relied on project 1 to be build.
To solve this problem, we extracted all the public standalone classes from both projects and placed them inside a single librarie. In the end we created something like this:
Framework.Objects
Framework.Interface
Framework.Implementation
WebService
The WebService would be linked to all projects in our case, whereas external parties would only be linking to the objects and interface classes to work with. The actuall implementation was coupled at runtime through reflection.
Hope this helps