Общие имена ServiceContracts и String.Format - PullRequest
1 голос
/ 22 июля 2010

Мне известны форматированные имена DataContract, как описано здесь: http://msdn.microsoft.com/en-us/library/ms731045.aspx (Настройка имен контрактов данных для общих типов в нижней части).

Пример:

[DataContract( Name = "SearchCriteriaFor{0}", Namespace = "http://schema.mycompany.com/MyProject/" )]
public class SearchCriteria<T> { ...

Это приведет к тому, что SearchCriteria<Employee> станет <xs:complexType name="SearchCriteriaForEmployee"> в сгенерированном XSD для службы. Это выглядит намного лучше, чем SearchCriteriaOfEmployeeWkD50_Xf (generic + "Of" + types + hash).

Я хочу сделать это и для ServiceContracts. К сожалению, использование синтаксиса {0} не работает (скобки экранируются, а ноль остается буквальным). Я не нашел примеров того, как это сделать, но я надеялся, что, поскольку он работает для DataContract, он будет работать и для ServiceContract. Есть ли способ включить аргументы типа как часть настраиваемого имени сериализации для ServiceContract?

Однако, когда я писал это, мне просто пришло в голову, что включение имени типа может даже не быть необходимым для ServiceContract, даже если реализация именования по умолчанию делает это. Допустимо ли указывать фиксированное имя для универсального ServiceContract? Я попробовал его, и, похоже, он правильно генерирует XSD, но не придется ли мне беспокоиться о будущих конфликтах из-за этого? Это внутренняя система, и я могу гарантировать от любых коллизий имен / пространств имен для любых объектов, которые будут использоваться в качестве аргументов универсального типа.

Например, если у меня есть IDataStore<T>, есть ли проблемы с:

[ServiceContract( Name = "DataStore", Namespace = "http://schema.mycompany.com/MyProject/" )]
public interface IDataStore<T> where T : MyBaseObject
{ IList<T> FindAll(); }

, в результате чего в результате XSD будет отображаться http://schema.mycompany.com/MyProject/DataStore/FindAll вместо http://schema.mycompany.com/MyProject/IDataStoreOf_Employee/FindAll.

Здесь много болтовни, поэтому реальные вопросы выделены жирным шрифтом выше.

1 Ответ

0 голосов
/ 23 июля 2010

Нет, нет способа включить аргументы типа как часть пользовательского имени сериализации. Используя Reflector, вы можете найти код, который создает имя в System.ServiceModel.Description.NamingHelper.GetContractName. Это выглядит так:

internal static XmlQualifiedName GetContractName(Type contractType, string name, string ns)
{
    XmlName name2 = new XmlName(name ?? TypeName(contractType));

Функция TypeName имеет логику для создания имен для универсальных типов и типов массивов, но если вы укажете имя в контракте, оно просто будет точно использовать это имя.

Я бы не рекомендовал использовать фиксированное имя для родового договора, но это может сработать. Поскольку он универсальный, я предполагаю, что у вас есть более одного его экземпляра, и IDataStore<Foo> и IDataStore<Bar> будут иметь одно и то же полное имя, но будут иметь операции разных типов. Пока ничто не видит обе версии контракта одновременно, у вас должно быть все в порядке, но если что-то видит обе версии сразу, это может запутаться.

Можете ли вы создать конкретный подкласс универсального интерфейса для каждого сервиса? Вы можете объявить что-то вроде:

[ServiceContract(Name = "EmployeeDataStore", Namespace = "http://schema.mycompany.com/MyProject/")]
public interface IEmployeeDataStore : IDataStore<Employee> { }

и ваш тип сервиса реализует этот интерфейс вместо IDataStore<Employee>. Затем вы можете установить имя явно для каждого типа.

...