Как построить архитектуру лучше - PullRequest
0 голосов
/ 05 января 2019

У меня есть приложение ASP.NET Core, которое вызывает службу из другой библиотеки. Сервис работает с внешним API, который требует sessionId. Мы должны вызвать метод Login API, чтобы получить sessionId. Как долго это sessionId живет и когда его можно изменить - мы не знаем. Правило: sessionId может быть действительным для 1 запроса, для 10 запросов, для 100 запросов, может быть действительным 1 минута, 10 минут, 1 день ... Никто не знает этого.

Служба имеет много методов для вызова похожих API:

public class BillRequest
{
    private readonly HttpClient client;

    public BillRequest()
    {
        client = new HttpClient
        {
            BaseAddress = new Uri("https://myapi.com/api/v2/")
        };
    }

    public async Task<List<Dto1>> CustomerBankAccountListAsync(int start, int count)
    {
        List<KeyValuePair<string, string>> nvc = new List<KeyValuePair<string, string>>
        {
            new KeyValuePair<string, string>("sessionId", CURRENT_SESSION_ID)
        };

        var customerStream = await client.PostAsync("List/CustomerBankAccount.json", new FormUrlEncodedContent(nvc));
        var customerString = await customerStream.Content.ReadAsStringAsync();
        //....
    }

    public async Task<List<Dto2>> Method2(int start, int count)
    {
        List<KeyValuePair<string, string>> nvc = new List<KeyValuePair<string, string>>
        {
            new KeyValuePair<string, string>("sessionId", CURRENT_SESSION_ID)
        };

        var customerStream = await client.PostAsync("List/Method2.json", new FormUrlEncodedContent(nvc));
        var customerString = await customerStream.Content.ReadAsStringAsync();
        //....
    }

    // logic to get SessionId here
    public async Task LoginAsync()
    {

    }

Как реализовать сохранение этого sessionId внутри сервиса?

Существует множество вариантов реализации:

  1. Вызывать метод Login каждый раз перед вызовом метода. Простой в реализации, но плохой подход, потому что у нас много ненужных запросов и мы используем sessionId только один раз

  2. Сохраните sessionId на уровне веб-приложения и попытайтесь перехватить исключение, когда любой метод вернет «недопустимый идентификатор сессии», а затем вызовите метод Login, который вернет новый sessionId. В этом случае мы должны передать sessionId конструктору класса BillRequest. Это работает, но я не люблю переносить ответственность службы на другую, потому что это внутренняя ответственность службы, как работать с API.

  3. Сохранить sessionId внутри самой службы и вызвать метод Login внутри службы, когда старый sessionId считается недействительным, переписать его новым и т. Д. Но как сохранить его как «статический» в памяти? Я не хочу сохранять его в каких-либо внешних местах (файловая система, облако и т. Д.), Но я не могу сохранить его и в переменную класса, поскольку объект класса может быть воссоздан ...

1 Ответ

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

Я бы предложил определенное умственное изменение здесь к функциональному программированию.

Думайте о sessionID как о потоке независимых значений, а не отдельного объекта. Тогда ваша проблема может быть переопределена следующим (семантически эквивалентным) способом: учитывая типизированный поток (string в вашем случае), как наблюдать его поток и реагировать на поступающие изменения , который ваш исходный код не контролирует?

Ну, есть ответ, подтвержденный Enterprise ™: реактивные расширения .

С технической точки зрения такой сдвиг подразумевает, что вы имеете дело с IObservable<string> внутри вашего контроллера, который либо может быть введен с помощью стандартного подхода .NET Core DI, либо просто определен конструктором. Это довольно гибко, поскольку rX предоставляет ваш полностью проверяемый, невероятно мощный набор инструментов для работы с подобными задачами; rX также совместим с родной Task и, следовательно, async/await функцией. Приятным фактом является то, что действительно легко внедрить требуемое поведение из внешнего мира и украсить существующее наблюдаемое более подходящим: итак, вы в безопасности: как только логика обслуживания стороннего поставщика изменяется, вы можете принять свою кодовую базу практически мгновенно и безболезненно.

Что будет внутри этого IObservable<string>? Ну, я не могу сказать, так как вы не дали достаточно информации. Это может быть интервал , запрашивающий у удаленного сервера, действителен ли текущий sessionID, а если нет - запускает процедуру relogin и уведомляет своих подписчиков о новом значении; это может быть таймер , отвечающий за известное правило истечения времени компиляции, это может быть настолько сложная логика, сколько вам нужно: rX достаточно гибок, чтобы не ограничивать вас тем, чего можно достичь с его помощью до тех пор, пока как вы имеете дело с (возможными бесконечными) потоками.

Как следствие, это означает, что вам не нужно глобальное значение. Просто подпишитесь на поток идентификаторов сеансов и получите последний - тот, который в настоящее время действителен, сделайте работу и утилизируйте вашу подписку. Это не дорого и не будет ухудшать производительность; ни один не испортит конкуренцию. Оберните rX в Task и await, если хотите придерживаться обычного способа .NET.

P.S. 99% того, что вам потребуется для реализации, уже есть; вам просто нужно объединить это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...