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