views:

343

answers:

4

Hi all,

Per default, all data contract entities, involved in realization of service operation (and their known types, are include in service metadata. I am trying to find out, if it is possible in include other classes or data contracts in the metadata. The reason for this is that i have some enums, which can be used to fill in string fields of entities involved in service operation or, when service returns error messages, they have an identifier which I would like to "translate" or give a meaning to it without referencing some assembly form the external service.

Is such thing possible, or have someone other hints how to deal with this?

Thank to all in advance.

Ilustratory exmaple of service declaration would be something like:

[DataContract(Namespace = "http://schemas.example.com/Common/ExampleServices/V20090903")]
public enum SearchTaskField
{

    [EnumMember]
    Id,
    [EnumMember]
    Date,
    ...
}

[DataContract(Namespace="http://schemas.example.com/Common/ExampleServices/V20090903")]
public class SearchCondition 
{

    [DataMember(Name = "ColumnName")]
    public virtual string ColumnName
    {
     get; set; 
    }

    [DataMember(Name = "ColumnValue")]
    public virtual object ColumnValue
    {
     get; set;
    }

    [DataMember(Name = "ObjectType")]
    public virtual string ObjectType
    {
     get; set; 
    }
}

[ServiceContract(Namespace="http://schemas.examle.com/Common/ExamleServices/V20090903")]
public interface IExampleServiceServiceContract
{

    [OperationContract(Name = "Search")]
    SearchOut Search(SearchIn messageIn);
}

[MessageContract]
public class SearchIn
{

    [MessageBodyMember(Name = "Conditions", Order = 1)]
    public virtual IList<Condition> Conditions
    {
     get; set;
    }
}
A: 

Would the EnumMember attribute work for you?

David Andres
Yes, I have EnumMember attribute in my enum data contract definition.
Jozef
+1  A: 

If you add a [DataContract] to your enums, they should be included in your metadata automatically. That's by far the easiest way to do this.

You can also extend the way the metadata is creating and presented - in WCF, you can extend just about everything :-) - but that involves a lot more code. One example is Christian Weyer's "flattening WSDL" service behavior - he taps into the process of creating the metadata by adding an endpoint behavior to his service endpoints.

Similarly, you could write your own endpoint behavior to extend your service - but again: just marking your enum types with [DataContract] should do the trick much more easily.

Marc

UPDATE: I think your enum is not being serialized into the meta data since it doesn't appear to be used - or is that impression wrong?

What happens if you e.g. add a field of that "enum" type to one of your DataContract classes? I would think, if it's really being used, then it will show up in your metadata...

marc_s
The enum is of cource marked as DataContract. But I assume that metadata are assumed by default only classes that are used in the service contract API ... or does it search for all data contract in the assembly and export them all? This behavior can cause issues.Anyway simply including [DataContract] does not work. When I create service reference in other project, the enum is not in generated code for service client.
Jozef
can you show us your enum type as you have it defined? I'm using plenty of enums all over the place and never had any issues....
marc_s
I have updated the question with an example ...
Jozef
Marc, your impression is correct. But the fact that enum is not beeing used anywhere is intended. I am trying to find out if you can force some types to be included there even when they are not used, referenced direcly in API of a service.The simple think I whant to do this for is to provide client with some heler classes ...E.g. by using example:SearchCondition condition = new SearchCondition();condition.ColumnName = SearchTaskField.Id.ToString();instead ofcondition.ColumnName = "Id";
Jozef
+4  A: 

You can decorate your service with the ServiceKnownType attribute. This will cause the specified type to be included in the metadata even if it is not directly used by the service contract (that is not involved in the object graph of one of the other exposed types).

As you have already done, you must mark the enum as a [DataContract] and each enum value as an [EnumMember]. Adding the following line to your ServiceContract interface will expose the enum on the client.

Remember you'll need to update the service reference to see any changes in the generated code.

[ServiceKnownType(typeof(SearchTaskField))]
Jerry Bullard
Not working. The msdn is saying "The known types are types that may be present in an object graph when serialization or deserialization occurs.". Therefore, I assume that if the type is not used in API object graph, is is not included in generated reference client code when adding service reference.Am I correct?
Jozef
I updated my answer to clarify the steps to get this working. I tested this in one of my projects, and I was able to see a new enum type on the client right away.
Jerry Bullard
I saw the update and I am regenerating the reference code. However, it is not working for me. What is you command to svcutil? Or, how are you generating client code?
Jozef
I am doing an Update Service Reference from Visual Studio.
Jerry Bullard
+1  A: 

Service metadata is not intended for the purpose of defining an API. Only the types actually used by the service will be reflected in the metadata. If you want other types to be used by the clients, then you should do the exact same thing you would have done with a class library: put the shared types into a shared assembly.

Of course, this doesn't help clients not running .NET, but by attempting to expose random types, you've already moved away from SOA, so you shouldn't mind much.

John Saunders
Thanks for the reply. So from your reply it seems that what I try to do is not possible and, moreover, it is a bad practice in terms of SOA architecture? Correct? This 'bad practice' is related probably to your comment "... but by attempting to expose random types, you've already moved away from SOA, so you shouldn't mind much". Can you please elaborate more on this? What you mean by'random type'? What should be SOA way if I do not want to do shared library thing because of restriction to .Net clients?
Jozef
The SOA way would be to not attempt to expose types that you think your clients might decide to use. How would a script-based client use your "enums"? Note that WSDL can't quite represent the programming language concept of an enum in any case.
John Saunders
It should a convenience for the client which can make an advantage of it and avoid string guessing. I have seen it in WSDL of one commercial company providing BPM solutions.Anyway, I am still convinced it can helpful, but probably it requires more advanced techniques to incorporate data types into service metadata which are not directly used in service API. I just wonder what are the techniques ...
Jozef
I agree with John that this does not follow SOA best practices. You could refactor your enum and SearchCondition class into strongly-typed search condition classes to satisfy your requirements yet retain an SOA-friendly API.
Jerry Bullard
OK, let admit that it does not follow SOA practice.Now, lets talk how to do it or if it is possible. Should be possible because I saw it :-). Strong type is not easy, because options for column name changes with object type you want to search on. Unless the API is redesigned ... but this is different story.
Jozef
What was your reason for not simply sharing the assembly with the types in it?
John Saunders
The assembly is language specific and makes even worse for not native clients than some additional types in service xml metadata.
Jozef