Aracılığıyla paylaş


Type sharing in WCF service reference

Type sharing is very useful when we want to pass same data between two services.  Without type sharing, we will get seperated types in the proxy for every service we consume.  That means a lot of code to convert data in one type to another before and after calling a service, which could be painful, and unnecessary coupling in code.

For service reference, there are two kind of type sharing:

1, reuse type pre-defined in a class library in proxy code  (do not generate new type in proxy)

2, share type between services (generate new type only once for different services)

The SDK tool svcutil supports the first kind of type sharing.  The WCF feature in the Visual Studio provides same level support for this kind of type sharing.  However, it becomes easier to use, because the generator in VS could automatically extra types in depedent assemblies of the project.  We do need remember to add reference to the assembly containing pre-defined types, but don't have to pass it as a parameter as we use svcutil.  The feature in VS also provides more refined control to the user, so it is possible to share types in a small set of assemblies or disable it.

The type sharing is actually done by the DataContract importer extension, so the type sharing in VS inherits the same limitation of the feature in svcutil.exe.  Basically, if you are only using new DataContract in service contracts, it works well.  But it doesn't support sharing some xml serializable types.  Sharing dataSet is supported, but somewhat limited.  The problem is that the data set type must be defined in exactly same CLR namespace in both server and client before the type sharing can work.  It should not be a problem if we want to share a same data set between client and server, but could be a problem if we only want to share the type between clients.  Of course, since data contract types are generated by extensions, it is possible to improve that by adding new or customized extensions.

One limitation which could not be resolved by adding extension is that the shared type must be defined in a library, but can not be defined in the same project consuming the service.  Considering that the type must be used by the proxy generator, and the proxy is a part of the project.  Reusing type in the same project could somehow cause a recursive logic in the current way how the generator works today. We may have to live with that limitation.

The second style of type sharing is supported by wsdl.exe.  svcutil.exe also allows to have two metadata source URL in its command line, although it works only if there is no conflict in metadata from the two sources.  That works if the wsdl files are hand crafted, but doesn't work well when the metadata is generated automatically, because we often get duplicated schema files from difference sources.  The WCF consumption feature in VS works in a very similar way as svcutil, although it would try to remove duplicated schemas.

(BTW, the type sharing is not supported in beta 1, but CTPs after that)

Comments

  • Anonymous
    November 29, 2007
    Could you please have a look at my problem here? http://forums.asp.net/p/1187759/2031259.aspx Thanks

  • Anonymous
    January 04, 2008
    Sorry, I didn't notice this post eariler. I saw a similar post in the VS 2008 forum, and Johan answered the question. The service reference folder actually contains all metadata downloaded from the server to describe the service.  A code generator then uses those information to generate proxy code, (and configuration).  Type sharing happens in the code generation process, so no matter whether we need generate new code or not, the metadata to describe the dataset will be persisted. The reason is simple: you can change the code generator options, turn on/off type sharing, without downloading information again from the server. (Actually server side might not be avaiable all the time.)  We also plan to use persisted information to track whether the server side has been updated, and check whether the type in the server matching the shared assembly, although some of the feature haven't made into the schedule. Another reason is to persist all the metadata is that ASP.Net web site project wants code generator happens at the runtime (but not within VS.)  Although client projects are different, we want to build a consistant design time feature crossing the two project systems.   In most cases, dataset files are small, comparing to the resouce in the computer today.  Removing those really don't save much space for you.  Except ASP.Net web site projects, they are also design time only file, and will not affect the size of the application.

  • Anonymous
    August 01, 2008
    I got an email from Brock, who had trouble with type sharing, because he has to deal with legacy xml structure, and still wants to share types between client & server. Yes, this is a little bit difficult to resolve, because the XmlSerialization type generator does not support type sharing.  However, we do have a possible workaround here.  You can try to share the whole service contract between the client & server, which means that not only the DataContract will be shared, the definition of the service contract (the interface) is also shared as well. It will work if you are building a WCF service (if you are building an old web service, i guess it won't work.) To do that, define your service contract and data contracts in a shared assembly.  In both of your client and server, you can add reference to this assembly.  You should be able to make the server to work first, after that, you should be able to add that service reference to your client application.  However, the service reference won't be shared by default, and the function is not exposed through UI directly, you have to edit the .svcmap file by hand to enable this function.  (The UI only exposes some common functionality, you do need work with the file when you need share a service contract.) Now, in the solution explorer, you can enable "show all files in the project" for the client project. Inside the service reference folder, you can find the .svcmap file.  Open that file in the editor, the intellisense will help you to work with that file. In the ServiceContractMappings section, add a ServiceContractMapping node, you need fill three attributes.  Name should be the name of the interface (actually, it is the name in the wsdl file, but it is usually the same as the name of the interface.) TypeName should be the full type name of the interface defined in the shared assembly, and the TargetNamespace is the targetNamespace of the wsdl file.  It can be found in the wsdl file (which can be found in the same folder.)  Often, if you didn't define it, it is "http://tempuri.org/".  After editing it, saving the file, and right click the serviceReference node and use the context menu to update the service reference.  The generated code will become empty, but configuration will still be generated. At that point, you will share the service contract between your client and server.  Of course, the code on the client side should consume the shared interface after this point.

  • Anonymous
    August 13, 2008
    I got a feedback for this post.  A customer found that the client class was no longer generated after he set the ServiceContractMapping. It is indeed the current behavior of the code generator.  I didn't aware of this, when I posted the solution. I didn't find an easy way to work around this issue.  The solution maybe is to hand-craft the client class, which is just a wrapper of the clientBase<> class.  It is an additional work, and add cost to maintain it, when the interface is changed.  The good news is that the compiler should find mismatch when it happens.

  • Anonymous
    March 13, 2011
    Someone actually created a small console app that knows how to generate proxies/types from different metadata urls into a single assembly.  It uses the svcutil utility with the /r switch to build up an assembly from all the types that are downloaded. You can read about it here www.drinkcoffeeandcode.com/.../how-to-share-base-types-with-svcutil

  • Anonymous
    April 02, 2014
    I was able to get this kinda working through trial & error.  I can get the proxy to generate, but it still recreates the ICatalogService interface in the client side reference project.  In my "TypeName" field, I tried using the FQTN (fully qualified type name) and it would fail.  Only when I removed the namespace would it generate.  Then I tried putting a ",CatalogService.ServiceDomain" to explicitly tell it where to find my ICatalogService interface.  It would generate the proxy, but still creates it's own ICatalogService.  Does anyone else have examples of this?  Or are we the most advance SOA people on the planet? LOL    <ServiceContractMappings>      <ServiceContractMapping Name="ICatalogService" TargetNamespace="tempuri.org/Imports" TypeName="ICatalogService,CatalogService.ServiceDomain" />    </ServiceContractMappings>