tigrou
tigrou

Reputation: 4516

How to keep some custom attributes when generating a proxy with svcutils?

I use the following command to generate a proxy class for a WCF service :

svcutil.exe" /out:C:\SomePath\.... /n:*,Internal.FooNameSpace 
   http://localhost/MyService.svc

The following class :

[ProtoContract]
[ServiceContract]
public class Foo 
{
    [ProtoMember(1)]
    [DataMember(Order = 0)]
    public string Bar { get; set; }
}

Becomes :

public partial class Foo : object, System.Runtime.Serialization.IExtensibleDataObject
{            
        private string BarField;

        [System.Runtime.Serialization.DataMemberAttribute()]
        public string Bar
        {
            get
            {
                return this.BarField;
            }
            set
            {
                this.BarField = value;
            }
        }        
}

Is there a way to keep some specific attributes on the generated class ? (eg : ProtoMember in this case). I could off course hack the proxy but it create maintenance problems.

Upvotes: 1

Views: 77

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062502

If you're adding that as a service reference, then nope: there's no way to retain that information - it simply isn't in the WCF endpoint.

IIRC, though, the WCF code-gen does actually come up with incremental Order values when you have multiple properties - i.e. the next property would be [System.Runtime.Serialization.DataMemberAttribute(Order = 1)], then 2 etc. So one option is to in a different file (the beauty of partial class), define (in the same namespace, etc) additional info about your type:

[ProtoContract(DataMemberOffset = 1)]
public partial class Foo { }

What this means is: when processing [DataMember], add 1 to every value - that means that you should get the required 1,2,3,4... and everything will be fine, and you haven't had to change the code.

Alternatively, you can be explicit:

[ProtoContract]
[ProtoPartialMember(1, nameof(Foo.Bar))]
[ProtoPartialMember(2, nameof(Foo.AnotherProp))]
public partial class Foo { }

This gives you a lot more flexibility to specify nuance about the properties.

As another alterative, you can configure everything at runtime:

RuntimeTypeModel.Default.Add(typeof(Foo), false)
    .Add(1, nameof(Foo.Bar))
    .Add(2, nameof(Foo.AnotherProp));
    // or AddField to get the ValueMember that you can use to set
    // fine-grained control

Finally, you can just ship the data contract dll, and tell svctil to use the types it already contains. You do this with the /reference:<file path> command-line switch, or there's a similar feature when using the UI tools (that lets you choose from the available dlls).


As a second "finally" (because one is not enough): you could describe the data instead as a .proto schema, and just tell the recipient to do the codegen locally and tell svcutil to exclude it (/excludeType: or /reference:). Note that the in progress rewrite of "protogen" does not currently include [DataContract]/[DataMember] attributes, but I could get that added today if it would be useful.

Upvotes: 1

Related Questions