I have a client app consuming a WCF service that is accepting and returning some complex type parameters. these complex types are held in a separate assembly that both the client app and the WCF service are referencing..
the problem is that when I add the service reference in the client app, the generated reference class builds its own versions of the complex parameter types and hence I cant pass in the types from the assembly that the original types are defined.
not sure if that is at all understandable..
question is.. am I going to have to write some sort of reflective deep copy routine to effectively build up the service reference generated classes from the original types?
or is there a better option
any help as ever very happily received
nat
When you are adding a service reference to code, select Advanced and you'll see an option Reuse types in referenced assemblies. If you ensure that is checked, and the reference is added to the project, WCF won't generate the proxy types and use the referenced types instead.
If you've already added the service reference, reference your shared types first, and then right-click the Service Reference, and select Configure Service Reference to get it to regenerate the client code using your referenced types.
Nope, you can do it: see my question here:
WCF Service Reference generates its own contract interface, won't reuse mine
You can have a shared assembly with interfaces, types, and both the service and client(s) can reference it :)
The 'reuse referenced types..' option does cover complex types, but the answer above also covers reusing the interface type, which IMO is far better option and not covered by that VS option.
Unless I've misunderstood, by checking "Reuse types in referenced assemblies" in the Advanced settings within Add Service Reference, any data contracts which match those in a referenced assembly will be reused and not regenerated.
Related
I have two WCF services I am adding reference to in my application. Both these services have an object called X, which is the same object.
The problem is after adding the references in my application, I am getting two different objects, with the same exact structure, but with different namespace.
This prevents me from casting between them and forces me to create two different objects, one for each service.
Please notice I don’t want to use dll’s.
Please notice I don’t want to use dll’s.
You'll have to. When you generate a WCF proxy, you have the option to reuse types from referenced assemblies. This have to be assemblies containing the types also used by the service. See also How to: Configure a Service to Reuse Existing Types.
Of course as #Franck pointed out in a comment, it's possible to intervene in the serialization process. You can also use a tool like AutoMapper.
More interesting is your actual problem: why don't you want to use a DLL reference? Did you try that but do you for example wish to deploy a single-file application, then merge the assembly in your executable.
I'm designing a new solution that will consist of three projects:
"Server" - a WCF service
"Client" - a winforms app that will call the WCF service
"ServiceContract" - a class lib containing some base classes plus the WCF service contract (interface). This will obviously be referenced by the Server, and also by the Client (I'm using a ChannelFactory rather than have VS generate a service reference). The service contract looks something like this:-
[ServiceContract]
[ServiceKnownType("GetCommandTypes", typeof(CommandTypesProvider))]
public interface INuService
{
[OperationContract]
bool ExecuteCommand(CommandBase command);
}
It's a very basic operation - the client creates a "command" object and sends it to the server to be executed. There will be many different commands, all inheriting from CommandBase (this base class resides in the "ServiceContract" project). As I'm using the base class in the WCF operation signature, I have to specify the known types which I'm doing dynamically using the ServiceKnownType attribute. This references a helper class (CommandTypesProvider) that returns all types deriving from CommandBase.
I've created a simple proof of concept with a couple of derived command classes that reside in the "ServiceContract" project. The helper class therefore only has to reflect types in the executing assembly. This all works fine.
Now in my "real" solution these command classes will be in different projects. These projects will reference the ServiceContract project, rather than vice-versa, which makes it difficult (or impossible?) for the helper to reflect the "command" assemblies. So my question is, how can I provide the known types?
Options I've thought about:-
The "Server" and "Client" projects will reference both the "ServiceContract" project and the various "command" projects. My helper could reflect through AppDomain.CurrentDomain.GetAssemblies(), but this fails because the "command" assemblies are not all loaded (I could force this by referencing a type in each, but that doesn't feel right - I want it to be a dynamic, pluggable architecture, and not have to modify code whenever I add a new command project).
Specify the known types in config. Again it would be nice if the app was dynamic, rather than have to update the config each time I add a command class.
Is there any way to access the underlying DataContractSerializer on both the client and server, and pass it the known types? I guess I'll still have the same issue of not being able to reflect the assemblies unless they've been loaded.
Refactor things to enable the ServiceContract project to reference the various command projects. I can then reflect them using 'Assembly.GetReferencedAssemblies()'. I guess the various command classes are part of the service contract, so perhaps this is the way to go? Edit: looks like this has the same problem of only finding loaded assemblies.
Any ideas greatly appreciated! Is it something that can be achieved or do I need to rethink my architecture?!
Thanks in advance.
One thing to consider is using the DataContractResolver.
Few resources:
WCF Extensibility – Data Contract Resolver by Carlos
Building Extensible WCF Service Interfaces With DataContractResolver by Kelly
Configuring Known Types Dynamically - Introducing the DataContractResolver by Youssef
Thanks for the replies regarding the Data Contract Resolver guys. I probably would have gone down this route normally but as I was using Windsor I was able to come up with a solution using this instead.
For anyone interested, I added a Windsor installer (IWindsorInstaller) to each of my "command" projects, which are run using Windsor's container.Install(FromAssembly.InDirectory.... These installs are responsible for registering any dependencies needed within that project, plus they also register all the command classes which my known types helper can resolve from the container.
I have created two projects in the same solution. The first project has a class, lets call it "class A". The second project is a WCF service library. That WCF service is referencing a
project from that same solution so it can use type "A" defined in the first solution.
Now, the problem is that when I reference that wcf service from the first project (normal C# project), in the object browser I see wcf service methods that have to return type "A", are returning just an "object" type! If I define a custom class as part of WCF project, it is recognized as return type.
How can I make project 1 (that defined type "A") use the WCF project and recognize his own types?
You will probably have to mark your DataContracts with [KnownType].
And it is a (very) good idea to isolate those shared types in a separate assembly (Project).
If you are the only consumer of your services and is a .net application then it might be worth using the NetDataContractSerailizer this way you can pass shared type information and you don't need to mark your objects with [KnownType]
see here for better explanation http://www.pluralsight-training.net/community/blogs/aaron/archive/2006/04/21/22284.aspx
hth
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
In my client, I'm trying to declare an entity type from the service....
MyService.MyClass myClass = new MyService.MyClass();
....
MyClass isn't available.
The assembly MyClass is within is referenced by MyService. What am I missing?
Generally, to preserve the service boundary, you work with mex-generated proxy classes at the client; these are structure only, so don't have any methods etc (just properties), and may even have different names (and almost certainly a different namespace).
However; if this .NET to .NET, you can get WCF (via either svcutil or the IDE) to re-use types in existing assemblies. Via the IDE it does this automatically (by default - you can disable it) if you have a reference to a dll containing matching types. At the command line, you use /r IIRC.
From the client's perspective, the service is just the interface, the client doesn't have access to the guts of the server. The types you might need should be exposed as part of a contract externally (like in a seperate assembly).
You probably want to Add Service Reference. Note that the generated class will have a slightly differnt name/namespace to your server implementation.