Как реализовать действие контроллера, вызывающее другое действие в другом контроллере? - PullRequest
0 голосов
/ 22 января 2019

Я создаю веб-API с использованием ядра ASP.NET и не понимаю, как подойти к публикации в таблице аудита / журнала.

Существуют две таблицы, таблица событий и таблица журнала событий.Если пользователь создает новое событие, он добавляет запись в таблицу событий и в журнал событий.Если пользователь редактирует имя / описание события, он также создает новую запись в таблице журнала событий.Обратите внимание, что таблица журнала событий в основном идентична по структуре таблице событий.

Таблица событий

+------------------+
|   Event Table    |
+------------------+
| Id               |
| EventName        |
| EventDescription |
| CreatorId        |
+------------------+

Таблица журнала событий

+------------------+
| Event Log Table  |
+------------------+
| Id               |
| EventId          |
| EventName        |
| EventDescription |
| EditorId         |
| TimeEdited       |
+------------------+

В настоящее время в моем веб-API есть два отдельных контроллера для каждой из двух таблиц, например Контроллер событий и контроллер журнала событий .

Что в данный момент происходит: Когда есть событие для записи / размещения события, оно создает экземпляр контроллера журнала событий и вызывает метод post для создания журнала событий, передаваянедавно созданный / обновленный объект журнала событий.

Вот какой-то упрощенный код ...

В EventController.cs ..

public IActionResult PostEvent([FromBody] Event event)
{
    _context.Event.Add(event);
    _context.Event.SaveChanges();

    EventLogController logController = new EventLogController(context);
    logController.PostEventLog(event);

    return Ok();
}

В EventLogController.cs ...

public IActionResult PostEventLog([FromBody] Event event)
{
    var eventLog = _mapper.Map<EventLog>(event);
    eventLog.TimeEdited = DateTime.Now;

    _context.EventLog.Add(eventLog);
    _context.EventLog.SaveChanges();

    return Ok();
}

Пока это работает нормально, на данный момент, Я весьма обеспокоен тем, является ли это лучшей практикой (Этокажется плохим создание нового контроллера только для вызова одного метода).Может быть полезно отметить, что я не хочу отправлять два отдельных вызова API каждому контроллеру.Я хотел бы, чтобы журнал событий создавался как следствие добавления / обновления записи.

На мой взгляд, я мог бы использовать некоторые другие подходы ...

  1. Создать репозиторий / сервис?для добавления EventLog в базу данных и внедрения его в EventController.Хотя это позволяет мне избежать создания контроллера, я слышал, что создание репозитория является ненужной абстракцией в ядре asp.net.

  2. Добавьте запись журнала событий в действие PostEvent в EventControllerбез создания контроллера или хранилища / службы.Однако это означает, что метод действия позаботится о двух запросах.

  3. Продолжайте использовать текущий подход, но просто добавьте контроллер EventLog вместо создания нового экземпляра.

Что касается вещей, которые я не думаю, что могу сделать ...

Я не думаю, что смогу создать триггер в самой базе данных с момента созданиязапись о событии не содержит достаточно информации для создания журнала событий (поскольку база данных не знает о редакторе).

Я также не думаю, что могу использовать RedirectToAction, поскольку это почтовый запрос, требующий чего-тодля отправки в теле.

Итак, мой вопрос: каков будет правильный способ создания записи журнала / аудита при каждом создании / обновлении связанного объекта?

Ответы [ 2 ]

0 голосов
/ 02 февраля 2019

Отдельный класс будет вашим другом здесь. Конечно, если реализация очень проста, а приложение невелико, то нет ничего плохого в том, чтобы создать простейшее решение. В любом случае, вызов другого контроллера свяжет ваш код.

Я привел простой пример того, что я обычно предпочитаю подобные случаи.

EventService.cs

public class EventService
{
        private IEventLogger logger;

        public EventService(IEventLogger logger)
        {
            this.logger = logger;
        }

        internal void AddNew(Event @event)
        {

            // Here is your code to persist event.
            // For example, context.SaveChanges(@event)
            // or whatever you want. 

            // When event is saved, I have called object that
            // implements IEventLogger interface. It is just a simple
            // interface to introduce Log(Event @event) -method.
            // 
            // When this service is created, you can pass logger
            // implementation. You can also use different way to pass
            // right implementation if constructor isn't work for you.
            if(logger != null) { 
                this.logger.Log(@event);
            }
        }
}

EventController

# In your controller you can use service like this.
# Of course, service is not needed to create inside the action
# but I just wanted to make a simple example.

public IActionResult PostEvent([FromBody] Event @event)
{
    IEventLogger logger = new EventLogger();
    EventService eventService = new EventService(logger);

    eventService.AddNew(@event); 

    return Ok();
} 

Зачем пользоваться услугой?

Это не должен быть контроллер, который знает детали реализации. Как было сказано ранее, контроллер просто контролирует.

Здесь я представил службу, которая отвечает за обработку постоянных событий. Вы можете инициализировать услугу с помощью context. Я придерживаюсь простого примера и не представляю больше абстракции, но вы, вероятно, поняли идею.

Когда вызывается метод AddNew (событие), служба узнает о ваших бизнес-правилах. В вашем случае я вижу, что «ведение журнала» является одним из правил, которые вам нужны. Вы хотите вести журнал изменений, поэтому при использовании сервиса у вас всегда есть доступный регистратор.

IEventLogger - простой интерфейс. Когда вы реализуете его, вы можете использовать тот же контекст внутри него, а затем обрабатывать ведение журнала внутри реализации.

if(logger != null) не является обязательным, но обычно хорошим способом иметь возможность не использовать ведение журнала, если в этом нет необходимости.

При необходимости вы всегда можете отделить EventLogController, который может возвращать зарегистрированные данные для использования из API. Ваш EventLogController имеет метод PostEventLog. Теперь, если хотите, вы можете использовать тот же регистратор внутри действия контроллера, чтобы сохранить событие журнала.

0 голосов
/ 22 января 2019

Я бы предпочел создание отдельного класса, что вы на самом деле упоминаете в своем «другом подходе 1».Тогда вы можете позвонить из нескольких мест.

Как правило, как вы знаете, возможно много подходов.Правило большого пальца всегда должно быть: «Контролер должен только контролировать, он не должен выполнять работу сам».Это означает, что диспетчер должен знать только, что позвонить, чтобы сделать работу.Если вы следуете этому принципу, вы помещаете свой фактический код в отдельный класс, а затем можете при необходимости вызывать его из нескольких мест одного или нескольких контроллеров.

...