Вот система, которая работает для нас:
Обычно вы должны использовать объект передачи данных, который отражает ожидаемые данные на стороне клиента. Бизнес-уровень должен определять эти DTO вместе с их интерфейсами репозитория. Уровень данных должен реализовывать интерфейсы репозитория, преобразовывая ваши объекты уровня данных в DTO. Уровень WCF должен быть просто внешней оболочкой для ваших различных методов интерфейса репозитория.
Таким образом, это выглядит примерно так:
UI ---\
| BLL -- DAL
WCF---/
[ DTO ]
[Repositories]
[Entities]
По моему мнению, уровень WCF является частью уровня пользовательского интерфейса, поэтому я чувствовал бы себя хорошо, если бы они оба знали объекты, определенные на бизнес-уровне. Однако вы можете сделать еще один шаг вперед и сделать так, чтобы слой WCF отвечал за преобразование ваших бизнес-объектов в DTO:
UI -- WCF -- BLL -- DAL
[ DTOs ]
[ Repositories ]
[ Business Objects ]
[Entities]
Таким образом, каждый слой знает не более одного слоя с каждой стороны от него. DTO могут быть аннотированы для сериализации или чего-то еще, потому что они действительно предназначены только для этой цели. Только уровень доступа к данным знает о ваших сущностях данных.
В ответе на ваш комментарий:
Если ваши сущности определены на уровне доступа к данным, то они действительно не DTO. Они моделируют ваш слой данных, который не обязательно переводится непосредственно в нужные вам объекты в пользовательском интерфейсе.
Причина, по которой я предлагаю определять интерфейсы для ваших репозиториев, заключается в том, что вы можете использовать внедрение зависимостей, чтобы ослабить связь между вашим уровнем WCF и вашим бизнес-уровнем. Это также поможет сделать ваш уровень WCF модульно-тестируемым, потому что вы можете создавать фальшивые или фиктивные реализации репозитория, которые имитируют определенную ситуацию.
В первой модели, которую я рекомендовал, ваши методы WCF будут выглядеть почти точно так же, как ваши методы репозитория, поэтому обычный WCF будет просто "оборачивать" метод репозитория:
public IEnumerable<Task> GetActiveTasks() {
return _taskRepository.GetActiveTasksForUser(_sessionManager.CurrentUser);
}