为了账号安全,请及时绑定邮箱和手机立即绑定

如何更好地构建架构

如何更好地构建架构

C#
Cats萌萌 2022-07-10 10:13:05
我有一个 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内部服务?有很多选项可以实现:Login每次调用方法之前调用方法。易于实现,但方法不好,因为那时我们有很多不必要的请求并且sessionId只使用一次保存sessionIdweb 应用程序级别并尝试捕获异常,当任何方法返回“无效 sessionId”时,然后调用Login方法,该方法将返回一个新的sessionId. 在这种情况下,我们必须传递sessionId给类的构造函数BillRequest。它可以工作,但我不喜欢将服务责任转移给其他人,因为如何使用 API 是服务的内部责任。保存sessionId在服务本身内部并在服务内部调用Login方法,当旧sessionId的被认为无效时,用新的等重写它。但是如何将其保存为内存中的“静态”?我不想将它保存到任何外部位置(文件系统、云等),但我也不能保存到类的变量中,因为可以重新创建类的对象......
查看完整描述

1 回答

?
心有法竹

TA贡献1866条经验 获得超5个赞

我建议在这里对函数式编程进行一定的心理转变。

sessionID其视为独立值而不是单个对象。然后可以通过以下(语义等效)方式重新定义您的问题:给定一个类型化的流(string在您的情况下),如何观察其流程并对传入的更改做出反应,而您的源代码无法控制?

嗯,有一个由 Enterprise™ 证明的答案:反应式扩展

从技术上讲,这种转变意味着您正在处理IObservable<string>控制器的内部,它可以通过标准的 .NET Core DI 方法注入,或者简单地由构造函数定义。这是非常灵活的,因为rX它为您提供了完全可测试、令人难以置信的强大工具集来处理此类任务;rX也与本机兼容,Task因此也与async/await功能兼容。不错的事实是,从外部世界注入所需的行为并用更合适的行为来装饰现有的 observable 非常容易:因此,您是安全的:一旦第 3 方的服务逻辑发生更改,您几乎可以立即轻松地采用您的代码库。

里面会是什么IObservable<string>?好吧,我不能说,因为你没有提供足够的信息。这可能是一个间隔,询问远程服务器当前sessionID是否仍然有效,如果不是 - 运行重新登录程序并通知它的订阅者新值;它可能是一个负责编译时已知过期规则的计时器rX,它可能是您需要的复杂逻辑:足够灵活,不会限制您使用它可以实现的目标,只要您处理(可能是无限的)流.

因此,这意味着您不需要任何全局值。只需订阅会话 ID 流并获取最新的 - 当前有效的,完成工作并处理您的订阅。它贵,不会影响性能;两者都不会破坏并发性。如果您想坚持一种常见的 .NET 方式,请rX使用它Taskawait

PS 交付实施所需的 99% 已经存在;你只需要结合它。


查看完整回答
反对 回复 2022-07-10
  • 1 回答
  • 0 关注
  • 109 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信