Xamarin PCL Refit 3.0.1,看起来不像一个Refit接口
本文关键字:Refit 一个 接口 看起来 PCL Xamarin | 更新日期: 2023-09-27 18:15:23
我最近开始做一个Xamarin Android/iOS项目,其中包含一个PCL类,我想把所有的逻辑都放进去。像我的Refit接口,reactiveuiviewmodels等,但每次当试图执行我的代码时,我得到一个错误,说我的接口不是一个Refit接口。目前我的界面是这样的
public interface IMyApi
{
[Post("/authenticate")]
IObservable<Models.ApiResponses.AuthenticationResponse> SigninRaw([Body] JObject credentials);
[Get("/service")]
IObservable<Models.ApiResponses.MyListResponse> GetServiceListRaw();
[Get("/service/{id}/idstatus")]
IObservable<Models.ApiResponses.IdResponse> GetIdStatusRaw(string Id);
}
据我所知,这看起来不错,这也工作,当我试图从一个特定的平台,如iOS项目加载这个。但是当试图从PCL做它失败了!我已经在我的两个平台特定项目Android中安装了Refit包。iOS和我在PCL中引用了一个dll,我错过了什么?
如果需要更多的信息或你有任何问题,请不要犹豫,问我。话不多说,谢谢你的阅读,希望有人能帮助我,因为我开始失去我的思想在过去的几天。
编辑:增加调用方法。这里我从ViewModel
调用它var client = new HttpClient(NetCache.UserInitiated)
{
BaseAddress = new Uri("https://api.address.com")
};
var api = RestService.For<IMyApi>(client); <= here it crashes
var response = api.SigninRaw(token);
我已经设法追踪到这一点,实际上有几个问题在发挥作用。幸运的是,有一些方法可以绕过它们。
第一个问题是PCL接口首先没有被检测到。Refit在编译时运行一个实用程序(InterfaceStubGenerator),它扫描子文件夹中的接口类,并为每个接口类生成实现代码。这些都被打包到一个名为RestStubs.g.cs的中间文件中,该文件被包含在程序集中。然而,这个实用程序只运行在通过nuget添加了Refit的项目上,并且由于它不包括PCL项目,因此这些项目中的接口永远不会被处理。解决方案是在预构建步骤中手动调用此实用程序,并将生成的文件包含在每个平台项目中。转到PCL项目的属性设置,并将以下内容添加到预构建步骤中:
..'..'..'..'packages'refit.3.0.1'tools'InterfaceStubGenerator.exe ..'..'..'ProjName.Droid'RefitStubs.cs ..'..'..'ProjName
..'..'..'..'packages'refit.3.0.1'tools'InterfaceStubGenerator.exe ..'..'..'ProjName.iOS'RefitStubs.cs ..'..'..'ProjName
这将为您的平台项目生成RefitStubs.cs,因此将每个文件添加到各自的项目中。
如果不是因为另一个问题,通常事情就结束了。您为获得实现而调用的RestService.For<>泛型假定实现类与其对应的接口位于相同的程序集中。显然,PCL项目并非如此。为了解决这个问题,您需要实现您自己版本的RestService类,这可能会满足您的大部分需求:
public static class PclRestService
{
public static T For<T>(string hostUrl)
{
var className = "AutoGenerated" + typeof(T).Name;
var typeName = typeof(T).Namespace + "." + typeof(T).Name.Replace(typeof(T).Name, className);
var assembly = System.Reflection.Assembly.GetExecutingAssembly();
var generatedType = assembly.GetType(typeName);
var requestBuilder = RequestBuilder.ForType<T>();
var client = new HttpClient(new HttpClientHandler()) { BaseAddress = new Uri(hostUrl) };
return (T)Activator.CreateInstance(generatedType, client, requestBuilder);
}
}
然后像这样调用它:
var netService = PclRestService.For<IMyApi>("http://jsonplaceholder.typicode.com");
var result = await netService.GetDataOrSomething();
您可能遇到的最后一个问题是对PreserveAttribute类的多次声明,它在存根文件的顶部声明。只要你不将Refit接口添加到你的平台项目中,这种情况就不会发生,但如果你这样做了,那么你有3个选择:
- 修改InterfaceStubGenerator实用程序以不创建该代码
- 编写一个预处理器,一旦生成代码就将其剥离。
- 去Refit的"Refit"。然后注释掉
"<Exec Command="$(RefitExecCmd)" />
行
Refit tools文件夹包含用于生成存根文件的模板文件,但由于某些奇怪的原因,它被完全忽略并静态链接到应用程序,因此在tools文件夹中编辑它根本不做任何事情。