Как бороться с исключениями при использовании DTOs
У меня есть структура решения, в которой контракты (данные/услуги и т. д.) находятся в другом проекте от бизнес-объектов, и я использую Automapper для сопоставления между Из третьего проекта реализации сервиса.
WCFProject.Service.BusinessLayer
WCFProject.Service.Contracts
WCFProject.Service.Impl
Мой ServiceImpl имеет ссылку на оба этих других проекта, и здесь выполняется автоматическое сопоставление из DataContract в BusinessEntity, а затем вызывается правильный метод для объекта BusinessEntity
Теперь я хочу добавить несколько FaultContracts
, а затем использовать их в моем бизнес-логика, чтобы выбрасывать правильные исключения. Но если я добавлю их в проект контрактов (что идеально, поскольку я хочу сохранить все мои контракты вместе), то мне нужна ссылка от BusinessLayer на контракты, чтобы использовать их в BusinessLayer. Я хотел сохранить их независимыми, если это возможно, и просто иметь дело с DTO между этими двумя слоями. Является ли это действительным агитационным инструментом с моей стороны, что я хочу сохранить два проекта независимыми? Вы тоже составляете карту исключений? Или есть лучший способ справиться с этим? этот.
3 ответа:
В вопросе вы указываете:
Я хочу добавить несколько Faultcontract и затем использовать их в своей бизнес-логике, чтобы создавать правильные исключения.Как вы правильно определили-это вводит связь между открытым API вашего сервиса (service, data and fault contracts) и вашей бизнес-логикой. В идеале ваша бизнес-логика должна быть агностична к тому, что ее вызывает служба, и поэтому ссылка на сборку контрактов вызывает беспокойство.
В сборке контрактов должна быть изложена общедоступная информация клиентов о вашем сервисе:
namespace Contracts { [ServiceContract] interface IMyService { [OperationContract] [FaultContract(typeof(MyFaultContract))] [FaultContract(typeof(AnotherFaultContract))] void MyOperation(); } [DataContract] public class MyFaultContract { [DataMember] public string Problem { get; set; } } [DataContract] public class AnotherFaultContract { [DataMember] public string Description { get; set; } } }
Как и многие проблемы в разработке программного обеспечения, ваша проблема может быть решена с помощью косвенного подхода. Несмотря на то, что вы указываете в вопросе-вы нехотите связать бизнес-логику с контрактной сборкой. Преимущества отказа от этого очевидны - это позволяет государственным контрактам и "внутренней" бизнес-логике развиваться. независимо.
Ниже приведен пример, в котором реализация сервиса используется для сопряжения контрактов с бизнес-логикой. Исключения в бизнес-уровне сопоставляются с контрактами сбоя, которые возвращаются клиенту:
namespace Service { class MyService: IMyService { public void MyOperation() { try { var businessLogic = new BusinessLogic(); businessLogic.DoOperation(); } catch (KeyNotFoundException) { throw new FaultException<MyFaultContract>(new MyFaultContract { Problem = "A key issue occurred in the service" }); } catch (Exception) { throw new FaultException<AnotherFaultContract>(new AnotherFaultContract { Description = "Something BAD happened in the service" }); } } } }
В качестве отступления, стоит тщательно подумать о контрактах неисправности, которые вы выставляете в вашем клиенте и какую информацию вы требуете от клиента, когда что-то идет не так на стороне сервера. Предоставление слишком большого количества информации об исключениях на вашем компьютере служба может представлять угрозу безопасности.
Ваш бизнес-слой не должен обладать знанием вышеперечисленных слоев. Поэтому он ничего не знает о том, что у вас есть слой wcf сверху. Выбрасывание ошибки-это что-то из вашего слоя wcf, поймайте там свое исключение и определите, что вы хотите сделать. Бизнес-исключение может быть сопоставлено с ошибкой wcf, но если у вас есть соединение исключения nullpointer, вы просто хотите дать общую ошибку, что что-то не так.
Можно найти пример ошибок передачи/отображения в поведении службы здесь: WCF-обработка исключений
Если вы испытываете трудности с созданием слоя DTO, то, вероятно, вы хотите защитить внешний мир от внутренней работы вашего домена.
Точно так же вы должны защищать внешний мир от всех исключений, которые возможны внутри вашего домена.ИМХО, вы должны сделать работу по перехвату исключений вашего домена, решая, что вы хотите (или не хотите) выставлять, и они сопоставляют это с правильной ошибкой в формате исключения DTO. Например, вы можете не хотите выставлять трассировки стека за пределы вашего домена.
Как правило, я стараюсь выставлять только исключения, с которыми клиент может что-то сделать. Если база данных не работает, то что клиент собирается с этим делать? Так что, возможно, клиенту не нужен этотSqlException
, а нужен500 Internal Server Error
.