I am aware of formatted DataContract names, as described here: http://msdn.microsoft.com/en-us/library/ms731045.aspx (Customizing Data Contract Names for Generic Types near the bottom).
Example:
[DataContract( Name = "SearchCriteriaFor{0}", Namespace = "http://schema.mycompany.com/MyProject/" )]
public class SearchCriteria<T> { ...
This would cause SearchCriteria<Employee>
to become <xs:complexType name="SearchCriteriaForEmployee">
in the generated XSD for the service. This looks a lot nicer than SearchCriteriaOfEmployeeWkD50_Xf
(generic+"Of"+types+hash).
I want to do this for ServiceContracts as well. Unfortunately using the {0}
syntax doesn't work (the braces get escaped and the zero remains literal). I haven't found any examples of how to do this, but I hoped that since it works for DataContract that it would also work for ServiceContract. Is there any way to include the type arguments as part of a custom serialization name for a ServiceContract?
However, as writing this it just occurred to me that including the type name may not even be necessary for ServiceContract at all, even though the default naming implementation does so. Is it acceptable to specify a fixed name for a generic ServiceContract? I tried it and it appears to generate the XSD correctly, but would I have to worry about any future conflicts due to this? This is an internal system and I can guarantee against any name/namespace collisions for any objects that would be used as generic type arguments.
For instance if I have a IDataStore<T>
, is there any problem with:
[ServiceContract( Name = "DataStore", Namespace = "http://schema.mycompany.com/MyProject/" )]
public interface IDataStore<T> where T : MyBaseObject
{ IList<T> FindAll(); }
which would cause the resulting XSD开发者_C百科 to show http://schema.mycompany.com/MyProject/DataStore/FindAll
instead of http://schema.mycompany.com/MyProject/IDataStoreOf_Employee/FindAll
.
Lots of rambling here, so the real questions are in bold above.
No, there is no way to include the type arguments as part of a custom serialization name. Using Reflector, you can find the code that creates the name in System.ServiceModel.Description.NamingHelper.GetContractName. It looks like this:
internal static XmlQualifiedName GetContractName(Type contractType, string name, string ns)
{
XmlName name2 = new XmlName(name ?? TypeName(contractType));
The TypeName
function has logic to create names for generic types and array types, but if you supply a Name in the contract it will just use that name exactly.
I would not recommend using a fixed name for a generic contract, but it might work. Since it's generic, I assume you have more than one instantiation of it, and IDataStore<Foo>
and IDataStore<Bar>
would have the same fully qualified name but would have operations of different types. As long as nothing sees both versions of the contract at once you should be okay, but if anything does see both at once it may get confused.
Can you create a concrete subclass of the generic interface for each service? You could declare something like:
[ServiceContract(Name = "EmployeeDataStore", Namespace = "http://schema.mycompany.com/MyProject/")]
public interface IEmployeeDataStore : IDataStore<Employee> { }
and have your service type implement that interface instead of just IDataStore<Employee>
. Then, you could set the name explicitly for each type.
精彩评论