Справочное пространство имен службы WCF отличается от исходного

У меня проблема с пространствами имен, используемыми моими ссылками на службы. У меня есть несколько служб WCF, скажем, с пространством имен MyCompany.Services.MyProduct (фактические пространства имен длиннее).
В рамках продукта я также предоставляю образец веб-сайта C# .NET. Это веб-приложение использует пространство имен MyCompany.MyProduct.

Во время первоначальной разработки сервис был добавлен как ссылка проекта на веб-сайт и используется напрямую. Я использовал фабричный шаблон, который возвращает экземпляр объекта, реализующий MyCompany.Services.MyProduct.IMyService. Все идет нормально.

Теперь я хочу изменить это, чтобы использовать фактическую ссылку на службу. После добавления ссылки и ввода MyCompany.Services.MyProduct в текстовом поле пространства имен создаются классы в пространстве имен MyCompany.MyProduct.MyCompany.Services.MyProduct. ПЛОХО! Я не хочу менять директивы using в нескольких местах только потому, что использую прокси-класс. Поэтому я попытался добавить к пространству имен global::, но это не принято.

Обратите внимание, что я еще даже не удалил исходные ссылки на сборки, а «повторное использование типов» включено, но, по-видимому, повторное использование не проводилось. Однако я не хочу хранить ссылки на сборки на своем тестовом веб-сайте, чтобы он все равно работал.

Единственное решение, которое я придумал до сих пор, — установить пространство имен по умолчанию для моего веб-приложения на MyCompany (поскольку оно не может быть пустым) и добавить ссылку на службу как Services.MyProduct. Предположим, что клиент хочет использовать мой пример веб-сайта в качестве отправной точки и меняет пространство имен по умолчанию на OtherCompany.Whatever, это, очевидно, нарушит мой обходной путь.

Есть ли хорошее решение этой проблемы?

Подводя итог: я хочу создать прокси-сервер ссылки на службу в исходном пространстве имен без ссылки на сборку.

Примечание. Я видел этот вопрос, но не было решения, приемлемого для моего варианта использования.


Изменить: как предложил Джон Сондерс, я отправил отзыв в Microsoft по этому поводу:
Элемент отзыва @ Microsoft Connect


person Thorarin    schedule 29.07.2009    source источник


Ответы (3)


Я добавил об этом решение в мой блог. На самом деле та же информация, но, возможно, немного менее фрагментированная

Я нашел альтернативу использованию svcutil.exe для выполнения того, что я хочу. Это (imo) упрощает обновление ссылки на службу, чем повторный запуск утилиты.

Вы должны явно указать uri пространства имен в контрактах ServiceContract и DataContracts (комментарии см. ниже).

[ServiceContract(Namespace = "http://company.com/MyCompany.Services.MyProduct")]
public interface IService
{
    [OperationContract]
    CompositeType GetData();
}

[DataContract(Namespace = "http://company.com/MyCompany.Services.MyProduct")]
public class CompositeType
{
    // Whatever
}

Пространство имен может быть любым, но технически это должен быть действительный uri, поэтому я выбрал эту схему. Возможно, вам придется собрать вручную, чтобы все заработало позже, так что сделайте это.

После этого включите параметр Показать все файлы в обозревателе решений. Разверните ссылку на службу, которую вы добавили ранее. Дважды щелкните файл Reference.svcmap.

Там будет элемент <NamespaceMappings />, который вам нужно будет отредактировать. Продолжая мой пример:

<NamespaceMappings>
    <NamespaceMapping
        TargetNamespace="http://company.com/MyCompany.Services.MyProduct"
        ClrNamespace="MyCompany.Services.MyProduct" />
</NamespaceMappings>

Сохраните файл, щелкните правой кнопкой мыши ссылку на службу и выберите Обновить ссылку на службу.

Вы можете добавить столько отображений, сколько вам нужно (на самом деле мне нужно было два). Эффект тот же, что и у подхода svcutil /namespace:, но без необходимости использовать саму утилиту командной строки, что упрощает обновление.

Отличие от svcutil

Недостатком этого подхода является необходимость использования явных сопоставлений пространств имен. Используя svcutil, у вас есть возможность отобразить все, что не отображается явно, как это (решение, на которое ссылался Джон Сондерс):

svcutil /namespace:*,MyCompany.Services.MyProduct ...

Вы можете подумать об использовании:

<NamespaceMappings>
    <NamespaceMapping
        TargetNamespace="*"
        ClrNamespace="MyCompany.Services.MyProduct" />
</NamespaceMappings>

но это не сработает, потому что Visual Studio уже неявно добавляет это сопоставление, указывая на сгенерированное имя пространства имен, от которого мы пытаемся избавиться. Приведенная выше конфигурация заставит Visual Studio жаловаться на повторяющийся ключ.

Объявление явных пространств имен.
Если в вашем коде не указано явное пространство имен, кажется, что .NET сгенерирует uri в форме http://schemas.datacontract.org/2004/07/MyCompany.Services.MyProduct. Вы можете отобразить это точно так же, как явные пространства имен в моем примере, но я не знаю, есть ли какие-либо гарантии для такого поведения. Поэтому использование явного пространства имен может быть лучше.

Примечание: сопоставление двух пространств TargetNamespace с одним и тем же ClrNamespace нарушает генерацию кода

person Thorarin    schedule 29.07.2009
comment
Спасибо за это подробное объяснение. Мне нужно было контролировать сопоставление пространств имен для сгенерированных объектов, чтобы сопоставлять их с частичными классами (в файлах, связанных между сервером и клиентом Silverlight). Таким образом, у меня есть сгенерированные сервисом объекты со всеми обрезками, а также общие методы и свойства класса на сервере и клиенте. - person Jersey Dude; 22.03.2010
comment
Столкнувшись с этой ошибкой, я обнаружил, что это был ответ, прежде чем я добрался до этого поста на SO, но я должен сказать, что это абсолютно нелепо делать это. WCF должен делать это автоматически, нет ни одного веского обоснования для требования, чтобы каждый отдельный пользователь службы вручную редактировал свои клиентские файлы только для того, чтобы общаться со службой. Как бы я ни любил .NET, подобные вещи делают меня таким злым на Microsoft. - person Chris Marisic; 04.08.2010
comment
@Chris: я бы не считал это ошибкой. Вы можете нормально общаться со службой без какого-либо ручного редактирования. Редактирование предназначено только для того, чтобы вещи соответствовали некоторым личным предпочтениям. Хотя все это довольно неудобно. - person Thorarin; 05.08.2010
comment
Что значит не ошибка? Без этого проект не сможет даже обновить свою служебную ссылку. - person Chris Marisic; 05.08.2010
comment
@Thorarin Ненавижу возвращать это через 5 лет. Этот обходной путь работает просто отлично. Однако есть одна вещь, которая меня беспокоит. В автоматически сгенерированном коде он по-прежнему генерирует старое пространство имен, не содержащее кодов. Сталкивались ли вы с этой проблемой к тому времени, когда писали обходной путь? - person LxL; 22.08.2014

Ваш вариант использования был неправильным.

Вы никогда не должны были включать сервис в качестве ссылки в первую очередь.

Я считаю, что svcutil.exe примет переключатель, указывающий полное используемое пространство имен.

person John Saunders    schedule 29.07.2009
comment
Это допустимый вариант использования, но, по-видимому, он не поддерживается графическим интерфейсом. Я сам смотрел на svcutil.exe переключатели с тех пор, как опубликовал это, и похоже, что это сработает. Я все еще хотел бы избежать необходимости делать это так, если бы я мог. Я также столкнулся со второй проблемой, для которой я использовал глупый обходной путь... Я обновлю здесь, когда попробую некоторые варианты. - person Thorarin; 29.07.2009
comment
Я полностью не согласен. Услуга есть услуга. Тот факт, что он собирается в сборку, не является оправданием для ссылки на сборку. Даже в целях модульного тестирования на эту сборку вообще не следует ссылаться. Вы должны действовать так, как если бы служба была написана на Java или каком-либо другом языке, отличном от .NET, и в этом случае вы никогда бы не подумали о ссылке на сборку. - person John Saunders; 29.07.2009
comment
О, вы имели в виду эту часть... но моя проблема с пространством имен возникает, когда я ссылаюсь на нее как на службу. Например, сгенерированное пространство имен нарушает правила кодирования на основе IDesign, которые мы используем. Для модульного тестирования мы используем ChannelFactory, которому на самом деле нужна ссылка на сборку, но который позволяет вам легко разместить его как службу для теста. - person Thorarin; 29.07.2009
comment
Что не так со ссылкой на 100% сборку ServiceContract и DataContract (конечно, без реализации). Какая разница, особенно если вы владеете обеими сторонами связи. Я бы не сказал, что это категорически плохо, особенно когда вы много рефакторите в начале проекта, это может быть благом для производительности. В этих случаях я вообще не создаю ссылку на службу. - person Anderson Imes; 29.07.2009
comment
Если это только контракты, у меня нет проблем с этим, особенно если это только контракты без поведения. У меня проблема в том, что он, кажется, ссылается на всю службу, включая поведение. - person John Saunders; 29.07.2009
comment
@Thorarin: применяются ли эти рекомендации по кодированию к сгенерированному коду? И у меня нет проблем со ссылками на контракты, которые находятся в отдельной сборке, и нет проблем с использованием ChannelFactory в клиенте. Было бы неплохо, если бы Add Service Reference разрешал произвольное пространство имен. Кажется, он разрешит только одно относительно корневого пространства имен проекта. Я смог добавить Random.Namespace, но он стал RootNamespace.Random.Namespace. Это было бы хорошим предложением для connect.microsoft.com/visualstudio. - person John Saunders; 29.07.2009
comment
Павел кто? Я не знаю, кто это. - person John Saunders; 29.07.2009
comment
Он: stackoverflow.com/users/111335/pavel-minaev :) Он где-то написал, что работает над VS2010. (и это написано в его профиле) - person Thorarin; 30.07.2009
comment
Мне нравится твой подход, Джон Сондерс. Есть +1! - person Andriy Drozdyuk; 12.10.2012

В VS2010 и более поздних версиях есть способ настроить собственные пространства имен. В обозревателе решений выберите «Показать все файлы», затем откройте «Веб-ссылки» в дереве решений, выберите службу, выберите узел Reference.map, отобразите свойства и задайте свойство «Пространство имен настраиваемого инструмента».

К сожалению, у меня недостаточно репутации, чтобы показать скриншот.

person Sergiu Cosciug    schedule 29.10.2013
comment
Я не знал об этом параметре, но когда я меняю его, а затем обновляю ссылку на службу, он вообще не меняет используемое пространство имен. Я что-то упускаю? - person Thorarin; 22.11.2013