Ошибка конфигурации конечной точки WCF: атрибут «контракт» недействителен?

У меня есть служба WCF, назовем ее UserService. UserService имеет ссылку на библиотеку классов. Назовем его DoWork.dll. DoWork.dll содержит ссылку службы WCF на другую службу, которую мы назовем CompanyService.

Теперь, когда я впервые попытался вызвать UserService, я получил сообщение об ошибке конечной точки, не настроенной. Почитав в Интернете, я обнаружил, что мне нужно добавить привязки CompanyService и информацию о клиенте в web.config UserService под узлом <system.serviceModel>.

Вот:

<system.serviceModel>
    <bindings>
      <basicHttpBinding>
        <binding name="BasicHttpBinding_IComapnyService" />
      </basicHttpBinding>
    </bindings>
    <client>
      <endpoint name="BasicHttpBinding_ICompanyService"
          address="http://it-dev.company.local:81/Project/Copmpany/CompanyService.svc"
          binding="basicHttpBinding" 
          bindingConfiguration="BasicHttpBinding_IComapnyService"
          contract="CompanyService.ICompanyService"  />
    </client>

У меня проблема в том, что contract="CompanyService.ICompanyService" показывает мне ошибку:

Атрибут «контракт» недействителен — значение «CompanyService.ICompanyService» недопустимо в соответствии с его типом данных «clientContractType» — ошибка ограничения перечисления.

Теперь, если я добавлю ссылку CompanyService непосредственно в проект UserService WCF, ошибка исчезнет (очевидно). Однако я не должен был этого делать. Я попытался полностью определить пространство имен, в котором находится контракт ICompanyService, и это тоже не работает. Я удалил файл .suo и перестроил проект, и это тоже не работает (предложено в другом месте в Интернете). Кроме того, если я наберу contract=, я получу раскрывающийся список, но CompanyService.ICompanyService нигде не будет найден (только когда я ссылаюсь на службу непосредственно в проекте UserService).

Я пытался настроить его с помощью Tools > WCF Service Configuration Editor, и это не помогает.

Я должен отметить, что все, кажется, работает нормально, но мне не нравится тот факт, что intellisense дает мне синее волнистое подчеркивание и это сообщение об ошибке. У меня есть ощущение, что мне нужно что-то еще в web.config, чтобы заставить это работать, поскольку UserService ссылается на DoWork.dll, который, в свою очередь, ссылается на CompanyService, чей контракт я не вижу должным образом.

Любые предложения очень ценятся. Заранее спасибо.


person BBauer42    schedule 16.08.2013    source источник
comment
Недавно я столкнулся с этим и обнаружил, что на самом деле включение полного пространства имен способствовало моим проблемам. Полезно отметить для всех, у кого есть эта проблема.   -  person Ian    schedule 08.10.2013


Ответы (1)


Вы правы - вы не должны этого делать.

Архитектура наличия DLL (DoWork.dll) со «ссылкой на службу» (ComanyService) плоха. Если в DLL жестко не запрограммирована конечная точка клиента (в коде) для вызова CompanyService для вас, то любой, кто использует DLL, должен будет попытаться выяснить, как настроить конечную точку клиента для службы, о которой он не знает. Это то, с чем вы столкнулись.

Причина, по которой это работает, когда вы добавляете ссылку на службу непосредственно из UserService, заключается в том, что когда вы делаете это, вы получаете копию ServiceContract из метаданных CompanyService. Чтобы доказать это, просмотрите сгенерированный файл Reference.cs, выполните поиск CompanyService, и вы обнаружите, что он имеет атрибут [ServiceContract], идентифицирующий его как службу WCF. Кроме того, вы увидите атрибуты [OperationContract] для методов, а также любые [DataContracts], которыми может обмениваться служба. Другими словами, все эти «типы» были импортированы в ваш проект, и при компиляции WCF теперь может находить эти типы при создании экземпляра конечной точки клиента.

Если CompanyService является одной из ваших служб, рассмотрите возможность извлечения определения ServiceContract (интерфейса) в отдельную DLL. Затем вы можете ссылаться на эти типы как на «ссылки на сборки» из службы (CompanyService) и любых клиентских приложений, таких как UserService. По крайней мере, таким образом вам не нужно добавлять ссылку на службу. Но вам все равно придется заполнить раздел .... в своем приложении для службы, о которой вы технически можете не знать подробностей. Не лучший подход.

Лучшим подходом является удаление зависимости службы от DoWork.dll. Вы можете сделать это, просто переместив логику в реализацию UserService.

Или, если вам нужно сохранить независимость DoWork.dll, рассмотрите возможность включения DoWork в службу WCF, которая зависит от CompanyService. Затем из UserService добавьте ссылку на новую службу DoWork. Это больше соответствует принципам SOA и позволит вашим сервисам развиваться независимо.

person Rick Rainey    schedule 16.08.2013
comment
Спасибо за информацию. Может у меня плохая архитектура. CompanyService — это ТОЛЬКО служба WCF, потому что мне нужно, чтобы она работала как синглтон с поведением службы InstanceContextMode.Single. Теперь в моей системе один сервисный метод в CompanyService НИКОГДА не должен вызываться откуда-либо, кроме DoWork.DLL. Итак, мой следующий вопрос: должен ли я жестко закодировать конечную точку в DoWork.DLL или мне следует полностью отказаться от ComapnyService и каким-то образом перенести его логику в DoWork.dll (каким-то образом поддерживая поведение синглтона)? Спасибо. - person BBauer42; 20.08.2013
comment
Нет, не жестко кодируйте конечную точку. Последний вариант, который я вам представил, вероятно, лучше всего подойдет для вашего сценария. Существуют способы (с помощью настроек безопасности) гарантировать, что служба, обертывающая DoWork.DLL, является единственной службой, которая может вызывать CompanyService. Итак, что-то вроде этого. UserService ‹--› NewWrapperService (доворк) ‹--› CompanyService - person Rick Rainey; 21.08.2013