我正在进行一个. NET核心项目,需要在其中实现一个清洁架构模式。任务是:
1.向第三方API服务发出HTTP请求
1.将响应内容作为流读取
1.将流内容保存到文件存储
为了解决这个问题,我在基础结构层创建了两个类:
- ApiService.cs
public async Task GetDataAsync(string url, Func<Stream, Task> func)
{
using (HttpResponseMessage httpResponseMessage = await httpClient.GetAsync(url))
{
if (httpResponseMessage.IsSuccessStatusCode)
{
using (Stream stream = await httpResponseMessage.Content.ReadAsStreamAsync())
{
await func(stream);
}
}
}
}
- FileStorageService.cs
public async Task CreateFileAsync(string path, Stream content)
{
using (FileStream fileStream = new(path, FileMode.Create))
{
await content.CopyToAsync(fileStream);
}
}
Core Layer中还有第三种方法,将上述两种方法结合起来进行处理:
public async Task DownloadData(string url, string path)
{
await apiService.GetDataAsync(url, async stream =>
{
await fileStorageService.CreateFileAsync(path, stream);
});
}
尽管上面的代码可以工作,但文件存储服务明显直接依赖于API服务。我的期望是以一种方式将文件和API服务完全分离,使两者不需要了解对方。我希望将来能够选择实现管道模式(如果需要),并能够以某种方式定义上面的代码:
string url = "<some_url>";
Stream result = await apiService.GetDataAsync(url);
string path ="<some_path>";
await fileStorageService.CreateFileAsync(path, result);
我试图用API Service Method中的Stream返回类型替换Func〈〉参数,但在正确处理HttpResponseMessage和Stream中的语句时遇到了挑战。
如果你对如何解决上述问题有一些建议,我将非常感激,以便:
1.明确地将API服务与文件服务分开,以便一个服务不知道另一个服务
1.正确处置HttpResponseMessage和来自apiService.GetDataAsync方法的Stream中的Using语句,而不使用Func〈〉(如果可能)
先谢了。
2条答案
按热度按时间ctehm74n1#
我不确定你是否考虑过类路径,但我更喜欢的处理方式是有一个
StorageFile
和StorageFolder
框架,模仿UWP/Metro/etc从一开始就有的东西。事实上,在dotnet/runtime Github repo中有一个非常古老但仍然悬而未决的问题。这个想法很简单,就是拥有抽象基类-
StorageFile
、StorageFolder
及其父类StorageObject
-为您要使用的每个存储平台(从本地文件系统到Azure blob,再到其他任何东西)实现这些抽象基类。以下是基本定义:
例如,
LocalStorageFile
的基本(不完整)实现如下所示:然后你会这样消费它:
最重要的是,代码的其余部分都引用基类-
StorageFile
等,并且通过处理Stream
-另一个高度抽象和可扩展的类-除了Dispose
之外,你不需要做任何特殊的事情。当然,如果你有一些高度专门化的东西,你也可以子类化Stream
,并从OpenReadAsync
和OpenWriteAsync
返回你想要的任何东西。xpszyzbs2#
经过评论中的讨论,我认为问题在于
apiService
正在处理流,然后fileStorageService
抛出一个已处理对象异常。此问题的一个可能的解决方案是删除
apiService
中的using
语句并返回流。然后,您可以按以下方式使用它: