Bezdepbonusu7Программирование: статьи и ответы

Вопрос

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

Автор вопроса: ThorarinОтветов: 3

У меня проблема с пространствами имен, используемыми моими ссылками на службы. У меня есть несколько служб 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

namespaceswcf

Ответы

Ответ 1 · рейтинг 23 · Thorarin

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

Я нашел альтернативу использованию 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 нарушает генерацию кода

Ответ 2 · рейтинг 1 · John Saunders

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

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

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

Ответ 3 · Sergiu Cosciug

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

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы