如何更好地构建架构

我有一个 ASP.NET Core 应用程序,它从另一个库调用服务。该服务使用外部 API,这需要sessionId. 我们必须调用 Login API 方法来获取sessionId. 这sessionId能活多久,什么时候可以改变——我们不知道。规则是:sessionId1个请求有效,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. 保存sessionIdweb 应用程序级别并尝试捕获异常,当任何方法返回“无效 sessionId”时,然后调用Login方法,该方法将返回一个新的sessionId. 在这种情况下,我们必须传递sessionId给类的构造函数BillRequest。它可以工作,但我不喜欢将服务责任转移给其他人,因为如何使用 API 是服务的内部责任。

  3. 保存sessionId在服务本身内部并在服务内部调用Login方法,当旧sessionId的被认为无效时,用新的等重写它。但是如何将其保存为内存中的“静态”?我不想将它保存到任何外部位置(文件系统、云等),但我也不能保存到类的变量中,因为可以重新创建类的对象......


Cats萌萌
浏览 165回答 1
1回答

心有法竹

我建议在这里对函数式编程进行一定的心理转变。将sessionID其视为独立值流而不是单个对象。然后可以通过以下(语义等效)方式重新定义您的问题:给定一个类型化的流(string在您的情况下),如何观察其流程并对传入的更改做出反应,而您的源代码无法控制?嗯,有一个由 Enterprise™ 证明的答案:反应式扩展。从技术上讲,这种转变意味着您正在处理IObservable<string>控制器的内部,它可以通过标准的 .NET Core DI 方法注入,或者简单地由构造函数定义。这是非常灵活的,因为rX它为您提供了完全可测试、令人难以置信的强大工具集来处理此类任务;rX也与本机兼容,Task因此也与async/await功能兼容。不错的事实是,从外部世界注入所需的行为并用更合适的行为来装饰现有的 observable 非常容易:因此,您是安全的:一旦第 3 方的服务逻辑发生更改,您几乎可以立即轻松地采用您的代码库。里面会是什么IObservable<string>?好吧,我不能说,因为你没有提供足够的信息。这可能是一个间隔,询问远程服务器当前sessionID是否仍然有效,如果不是 - 运行重新登录程序并通知它的订阅者新值;它可能是一个负责编译时已知过期规则的计时器rX,它可能是您需要的复杂逻辑:足够灵活,不会限制您使用它可以实现的目标,只要您处理(可能是无限的)流.因此,这意味着您不需要任何全局值。只需订阅会话 ID 流并获取最新的 - 当前有效的,完成工作并处理您的订阅。它不贵,不会影响性能;两者都不会破坏并发性。如果您想坚持一种常见的 .NET 方式,请rX使用它Task。awaitPS 交付实施所需的 99% 已经存在;你只需要结合它。
打开App,查看更多内容
随时随地看视频慕课网APP