다음을 통해 공유


Reusing Types in Referenced Assemblies with svcutil's /r Switch

Everyone’s entitled to their own personal favorite svcutil switch, but mine is the “/reference” switch, or “/r” for short. It allows you to avoid generating a type again if it’s already present in a referenced assembly. Here’s how it works:

 

Let’s say you have an assembly Foo.dll that already contains a type Foo:

 

[DataContract(Name="Blah", Namespace="https://www.myNamespace.org/")]

public class Foo

{

    [DataMember(Name="theSMember")]

    public string s;

}

 

Now, if you run “svcutil /reference:Foo.dll https://www.awesomeServices.com/FooService?wsdl” , and if FooService happens to reference a type that matches Foo’s data contract in its metadata, like here:

 

<xs:schema xmlns:tns="https://www.myNamespace.org/" elementFormDefault="qualified" targetNamespace="https://www.myNamespace.org/" xmlns:xs="https://www.w3.org/2001/XMLSchema">

  <xs:complexType name="Blah">

    <xs:sequence>

      <xs:element minOccurs="0" name="theSMember" nillable="true" type="xs:string" />

    </xs:sequence>

  </xs:complexType>

  <xs:element name="Blah" nillable="true" type="tns:Blah" />

</xs:schema>

Instead of generating a client-side class definition for this type that you might expect:

 

[System.Diagnostics.DebuggerStepThroughAttribute()]

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]

[System.Runtime.Serialization.DataContractAttribute(Name="Blah", Namespace="https://www.myNamespace.org/")]

public partial class Blah : object, System.Runtime.Serialization.IExtensibleDataObject {

    private System.Runtime.Serialization.ExtensionDataObject extensionDataField;

    private string theSMemberField;

    public System.Runtime.Serialization.ExtensionDataObject ExtensionData {

    get {

    return this.extensionDataField;

    }

    set {

    this.extensionDataField = value;

    }

    }

    [System.Runtime.Serialization.DataMemberAttribute()]

    public string theSMember {

        get {

            return this.theSMemberField;

        }

        set {

            this.theSMemberField = value;

        }

    }

}

Svcutil will just reference the type Foo from the assembly that you provided. So you’re able to avoid having ugly-looking generated data types on your client when you already have access to those types.

 

This can be useful in a number of cases:

· Your client and server share an assembly of common types, so that the very same types can be used on the server and on the client.

· You need to import metadata for two different services that happen to share the same type and don’t want to get two copies of the same type. In this case, you can generate proxy for the first service, compile it, and then reference the assembly when generating proxy for the second service.

· You already have client-side types that are similar to the types that are being imported and you want WCF to use these types directly instead of having to copy over data from the auto-generated class into your own type or vice versa

 

I should note that by default, Visual Studio’s “Add Service Reference” will use all of the referenced assemblies in your project as references for proxy generation purposes as well. Also, mscorlib and System.ServiceModel are always considered referenced assemblies unless you use the flag “noStdLib”. Finally, the /r switch only works for DataContract types. It does not work for XmlSerializer types. So if your types can't be imported as data contracts, /r won't do anything for you.