在c# UWP应用中放置API调用的位置

本文关键字:API 调用 位置 UWP 应用 | 更新日期: 2023-09-27 18:17:04

我开始理解面向对象编程(过去总是更偏向于过程化)和MVVM。

我对本地应用程序的结构(模型类等)有点信心,但我不确定连接到外部api和检索JSON结果(我知道如何连接,但我正在谈论项目结构等)。我读过有关facade和服务的文章,但似乎不同的人构建事物的方式不同。我敢肯定没有一个通用的规则,但是有一个"最佳实践"吗?

就在我的脑海里,似乎有一个API类是有意义的。从数据模型到连接到API的所有东西都可以放在那里。不过,我似乎看到人们通过他们的视图模型建立了联系。

我只是在寻找一些输入。谢谢你的指导

在c# UWP应用中放置API调用的位置

您可以想象,有很多方法可以做到这一点。任何设计都可能有它的优点和缺点,你可能会通过经验来找出这些缺点。

一个简单的方法是使用一个"service"类,它是代码对外部服务的外观。它的接口可能非常简单:

interface MyService
{
    void SomeOperation(int someValue);
    string AnotherOperation(double anotherValue);
}

实现此服务的类本质上是对外部服务的传递。它将负责封装访问服务的技术堆栈,例如HTTP REST客户端。

理想情况下,这完全封装了使用服务的技术方面(如HTTP, JSON等),只暴露了逻辑方面(命名良好的方法,接受并返回域对象而不是JSON字符串等)。这样,即使你换掉了技术,你仍然可以保留相同的语义业务含义,并且只需要改变接口后面的一个实现。

至于在哪里使用服务类,这通常是一个意见问题,实际上取决于最终哪种方式更有意义,在代码中更容易支持。一种思想流派是让模型在内部使用服务类,并且所有东西都与模型交互,另一种思想流派是在某个地方使用更多的过程代码,从而平等地使用服务和模型。就我个人而言,我发现前者在MVVM中更有意义,后者在MVC中更有意义。但你的里程可能会有所不同。

如果可能的话,我建议尝试直接在模型中使用服务,因为任何过程代码都需要存在于某个地方,而在MVVM模式中,您可能会发现自己在错误的地方"插入"了服务。如何处理模型中服务的依赖注入之类的事情完全是另一个主题,如果你也想这样做的话。

没有明确的正确答案。这取决于你的应用是如何构建的,以及你想要做什么。对于我们的生产UWP应用程序,几乎所有API调用都是业务对象下载调用,因此我们为每个调用设置一个类,每个类实现一个公共接口,如下所示:

interface IDownloadMethod<T> : where T : IPersistable {
   string WebServiceBaseURL { get; set; }
   IEnumerable<T> Download();
   Action<IEnumerable> RepositoryMethod { get; }
}

…其中IPersistable是表示这些调用返回的数据的接口。

我们创建了一个实现IDownloadMethod<T>的抽象基类,具有所有常见功能:

public class AbstractDownloadMethod<T> : IDownloadMethod<T> where T : IPersistable {
   // default implementations of all needed methods
   // the most important one:
   IEnumerable<T> Download() {
      // implementation 
   }
}

然后每个下载方法变成一个非常简单的类:

internal class DownloadSomeBusinessObject : AbstractDownloadMethod<SomeBusinessObject>
{
   public DownloadSomeBusinessObject (Action<IEnumerable> handler, string webServiceBaseURL, LoginCredential credential) 
      : base(handler, webServiceBaseURL, credential)
   {
      ActionURL = @"someBusinessObject/";
   }
}

我们有一个这样的API调用的长列表,所以我们有一个Controller类迭代所有它们并调用它们的Download()方法,然后将结果保存到存储库:

// you need to populate methodsList first with all the methods you want to call, then...
foreach (IDownloadMethod<IPersistable> method in methodsList)
{
   Task<IEnumerable<IPersistable>> task = Task.Run(() => method.Download());
   TaskAwaiter<IEnumerable<IPersistable>> awaiter = task.GetAwaiter();
   while (!awaiter.IsCompleted)
   { // busy waiting is terrible.. we know
   }
   IList<IPersistable> genericList = awaiter.GetResult().ToList();
   if (method.RepositoryMethod != null)
   {
      method.RepositoryMethod(genericList);
   }
}