locked
Custom attribute on WCF Data Contract is missing in proxy class RRS feed

  • Question

  • We have a simple WCF service that has a Data Contract class decorated with a custom attribute.  The DataContract class is one of the parameter of the method defined in the service. The proxy on client application tries to read the method parameters and try to retrieve the attributes but it doesn't show the custom attribute at all.

    WCF Service

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    using System.Security;
    
    [assembly: AllowPartiallyTrustedCallers]
    namespace TestCustomAttributesInWCFService
    {
      // NOTE: If you change the interface name "IService1" here, you must also update the reference to "IService1" in App.config.
      [ServiceContract]
      public interface IService1
      {
        [OperationContract]
        string GetData(int value);
    
        [OperationContract]
        CompositeType GetDataUsingDataContract(CompositeType composite);
    
        // TODO: Add your service operations here
      }
    
      // Use a data contract as illustrated in the sample below to add composite types to service operations
      [Flag("UserDefinedClass")]
      [DataContract]
      public class CompositeType
      {
        bool boolValue = true;
        string stringValue = "Hello ";
    
        [DataMember]
        public bool BoolValue
        {
          get { return boolValue; }
          set { boolValue = value; }
        }
    
        [DataMember]
        public string StringValue
        {
          get { return stringValue; }
          set { stringValue = value; }
        }
      }
    
      public class FlagAttribute : Attribute
      {
        // This constructor specifies the unnamed arguments to the attribute class.
        public FlagAttribute(string name)
        {
          this.name = name;
        }
    
        // This property is readonly (it has no set accessor)
        // so it cannot be used as a named argument to this attribute.
        public string Name
        {
          get
          {
            return name;
          }
        }
    
        public override string ToString()
        {
          string value = "Flag : " + Name;
          return value;
        }
    
        private string name;
      }
    }
    
    

    I am trying to read the attribute on client side to perform so particular task. But the attribute is missing.  

    The Client Code is:

    MyService.Service1Client client = new MyService.Service1Client();
    Type t = typeof(MyService.Service1Client);
    MethodInfo members = t.GetMethod("GetDataUsingDataContract");
    ParameterInfo[] parameters = members.GetParameters();
    foreach (var parameter in parameters)
    {
      Type tt = parameter.ParameterType;
      object[] attributes;
      attributes = tt.GetCustomAttributes(true);
    }
    

    The GetCustomAttributes function returns 4 elements. Not sure what are all these:
    System.SerializableAttribute
    System.CodeDom.Compiler.GeneratedCodeAttribute
    System.Runtime.Serialization.DataContractAttribute
    System.Diagnostics.DebuggerStepThroughAttribute
    but not MyAttribute.

    Why is my custom attribute missing? What am I missing here?? The above code is just a sample code that I am trying to debug. Actually I am generating the proxy at runtime based on the URI (http://.../xyz.svc).

    Wednesday, January 5, 2011 9:33 PM

Answers

  • The attributes you add to the data contract classes are not exposed in the service metadata, so when you generate the proxy at runtime, the information about it doesn't exist. There are a few things you can do to expose that information:

    - Add one WSDL export extension, which understands your attribute, and adds it to the service metadata. There a sample about that at http://msdn.microsoft.com/en-us/library/aa717040.aspx. Your code which imports the service to generate the proxy would need to be aware of that as well (the sample also shows the client changes which need to be made). That's the most complicated option, but if you want to completely isolate the server and the client it's a good choice.

    - Create a "common" data contract library and reuse it on both client and server. If you're using svcutil you can use the /reference (/r) option to reference the common library, so the client will use the same data contract class (with the custom attribute); if you're using add service reference on Visual Studio there's an option (IIRC on the "Advanced" settings) which will let you choose the common library as well.

    • Proposed as answer by Carlos Figueira Friday, January 7, 2011 10:39 PM
    • Marked as answer by Yi-Lun Luo Wednesday, January 12, 2011 9:27 AM
    Wednesday, January 5, 2011 9:45 PM

All replies

  • The attributes you add to the data contract classes are not exposed in the service metadata, so when you generate the proxy at runtime, the information about it doesn't exist. There are a few things you can do to expose that information:

    - Add one WSDL export extension, which understands your attribute, and adds it to the service metadata. There a sample about that at http://msdn.microsoft.com/en-us/library/aa717040.aspx. Your code which imports the service to generate the proxy would need to be aware of that as well (the sample also shows the client changes which need to be made). That's the most complicated option, but if you want to completely isolate the server and the client it's a good choice.

    - Create a "common" data contract library and reuse it on both client and server. If you're using svcutil you can use the /reference (/r) option to reference the common library, so the client will use the same data contract class (with the custom attribute); if you're using add service reference on Visual Studio there's an option (IIRC on the "Advanced" settings) which will let you choose the common library as well.

    • Proposed as answer by Carlos Figueira Friday, January 7, 2011 10:39 PM
    • Marked as answer by Yi-Lun Luo Wednesday, January 12, 2011 9:27 AM
    Wednesday, January 5, 2011 9:45 PM
  • Did you try using POCO object? You can refer the below link for POCO objects. And then try your specific implementation.

    http://www.pluralsight-training.net/community/blogs/aaron/archive/2008/05/13/50934.aspx

    Thanks & Regards,

    Ravi Bhatt.


    I m here to win not to loose.
    Wednesday, January 5, 2011 9:58 PM
  • I have the same problem.

    I needed to send custom attributes for data contact and data members. Using the link in Carlos's answer I was able to add custom attribute for service contract but I could not add custom attribute for operation contract, data contract and data members.

    Then I decided to add new method into service contract. This method returns data with attributes linked with data members. When the client application is started some action links client types with custom attributes from server.

    Tuesday, January 27, 2015 9:10 AM