Внедрение зависимостей в типичном веб приложении.
От: #John Европа https://github.com/ichensky
Дата: 18.05.17 15:14
Оценка:
Здравствуйте.

Типичное легко-расширяемое веб приложение(интернет магазин/форум/блог/каталог/веб сервис по обработке какихх-то данных):
Приложение разделено на две части:
1.FE html+js+css
2.BE asp.net webservices
Хоститься на одном вебсайте-ip адресе, но вебсервисы — под-приложение. FE показывает html страничку и по необходимости дергает методы вебсервисов .
FE — может писаться на ангуляре/кастомного js/__подставить свое.

BE.
Базовый контроллер, содержит информацию о сессии, о пользователе и информацию которая нужна в почти во всех запросах на сервер. От базового контрллера будут унаследованы практически все контроллеры.
Аттрибут `exception` — это "фильтр", который перехватывает все exceptions, логирует и если нужно возвращает клиенту сеарилизованную ошибку в json или HTTP CODE.
   [exception]
    public class baseController : ApiController
    {
        public session session { get; internal set; }
        public domain.servicemodels.user.user user{ get; internal set; }
    }


Пример типичного контроллера.
"фильтр" `auth` говорит, что только аутентифицированные пользователи могут вызывать данный контроллер.
"фильтр" `authorz` — говорит какие роли должны быть у этого пользователя, что бы он мог вызвать контроллер.
аттрибут service — говорит что только HTTP POST запрос может быть выполнен к этому методу; т.к. PUT,DELETE -это недоработки/костыли HTTP протокола, в реальной жизни они ненужны, все запросы к сервисам будут идти только через POST, буд-то мы создаем еще один уровень в сетевой моделе OSI. HTTP GET нужен только для браузеров для скачивания html или js, тоже недостаток HTTP протокола, можно было бы спокойно жить с одним POST, отсылая еще как параметр время жизни данных, которые отдал сервер.
В теле контроллера, идет базовая обработка кода, по необходимости, достаются нужные конфиги, конвертируются входящие параметры в нужные объекты.

  [auth]
   public class carController : baseController
   {
   [authorz(roles.user,roles.admin)]
        [service]
        public rr delete(car car)
        {
            var s = new carservice();
            return s.delete(car, this.user);
        }
   }


Каждый метод контроллера, будет возращать код ошибки/кастомной ошибки с описанием.

 public enum responce_codes
    {
        // Action was handled well, without errors
        success = 0,
        // HTTP parameters(from body|url) not valid
        bad_request = 400,
        unauthorized = 401,
        forbidden=403,
        internal_server_error = 500,
...
    }
    public class error {
        public string name { get; set; }
        public string message { get; set; }
    }
    public class rr : error
    {
        public responce_codes code { get; set; }
        public IEnumerable<error> errors { get; set; }
    }


Типичный сервис с бизнес логикой.
В метод `delete` передаются данные, которые будут проверены: базовая валидация, потом запросы к бд, какая-то логика, конвертация прокси/адаптером классом в объект — Responce для клиента, в котором не будет содержаться лишних данных.
В блоке `using (var context = new xcontext())` -создает соединение с бд, достаются необходимые данные, обрабатываются и закрывается соединение.
`invalid_data_exception` — кастомное исключение, которое будет обрабатываться в `exception` фильтре

public class carservice
{
 public rr delete(servicemodels.car.car car, servicemodels.user.user user)
        {
            var date = DateTime.UtcNow;

            if (user.shop == null || car == null)
            {
                throw new invalid_data_exception();
            }

            using (var context = new xcontext())
            {
                var carsmanager = new carsmanager(context);
                var usersmanager = new usersmanager(context);
                var carproxy = new carproxy();

                var update_car = carsmanager
                    .list_by_shop_not_deleted(user.shop.id)
                    .FirstOrDefault(x=>x.id==car.id);

                if (update_car==null)
                {
                    throw new invalid_data_exception();
                }
      ...

                update_car.deletedate = date;

                carsmanager.update(update_car);

                context.SaveChanges();

                return new rr();
            }
        }
}


Все никакого лишнего кода, все красиво, все работает,
мы всегда знаем что в каждый метод сервиса будут переданы только те данные/конфиги, которые ему нужны для выполнения логики, потом будет проверка входящих данных, а после, если нам надо, а не при каждом request|responce, будет создано соединени с бд/диском, а ты только клепай контроллеры да методы.

Где можно применить Dependency Injection что бы упростить себе жизнь?
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.