我正在尝试使用 ServiceStack 为 BitBucket API 编写包装器。该 API 有相当复杂的 URL,例如:
bitbucket.org/api/1.0/repositories/{accountname}/{repo_slug}/issues/{issue_id}/
此路线用于从 id 获取问题。该问题是
repo_slug
存储库的一部分,也是 accountname 用户存储库的一部分。这两个参数不是问题的一部分。那么我该如何为此编写一条路线呢?我试过这个:
[Route("/repositories/{Accountname}/{RepositorySlug}/issues/{local_id}")]
public class GetIssue : IReturn<Issue>{
public string AccountName { get; set; }
public string RepositorySlug { get; set; }
// issue object properties from here on
public string status { get; set; }
public string priority { get; set; }
public string title { get; set; }
public User reported_by { get; set; }
public string utc_last_updated { get; set; }
public int comment_count { get; set; }
public Metadata metadata { get; set; }
public string content { get; set; }
public string created_on { get; set; }
public int local_id { get; set; }
public int follower_count { get; set; }
public string utc_created_on { get; set; }
public string resource_uri { get; set; }
public bool is_spam { get; set; }
}
所以基本上我将这两个参数与整个 Issue DTO 结合在一起。这适用于 GET 请求,但当我尝试 PUT 更新后的问题时,我从 bitbucket 收到错误。
然后我继续尝试伪造被称为的路径:
[Route("/repositories/a/a/issues/{Id}")]
public class GetIssue : IReturn<Issue>{
public int Id { get; set; }
}
为了简洁起见,我在这里只是使用 ID,但这里它是整个 DTO。然后,当我发出请求时,我会伪造从路由中获得的网址,如下所示:
public Issue GetIssue(int issueId){
_url = "repositories/" + _accountName + "/" + _repository + "/issues/" + issueId;
return _sharpBucket.Get(new GetIssue{ Id = issueId}, _url);
}
这是上面调用的get方法。
public T Get<T>(IReturn<T> request, string url = null){
return Send(request,
HttpMethods.Get,
overrideUrl: url,
sendRequestBody: false);
}
以及从上面调用的发送:
private T Send<T>(IReturn<T> request, string method, string overrideUrl = null, bool sendRequestBody = true){
var relativeUrl = overrideUrl ?? request.ToUrl(method);
var body = sendRequestBody ? QueryStringSerializer.SerializeToString(request)
: null;
var json = Send(relativeUrl, method, body);
var response = json.FromJson<T>();
return response;
}
public T Send<T>(IReturn<T> request){
var method = request is IPost<T> ?
HttpMethods.Post
: request is IPut<T> ?
HttpMethods.Put
: request is IDelete<T> ?
HttpMethods.Delete :
HttpMethods.Get;
return Send(request, method, sendRequestBody: false);
}
这种作品。有没有更好的办法?我想我一定是错过了什么。我看到了类似的主题here,但它没有提供解决方案。
更新:
这似乎在 v3 版本中存在错误。坚持我的“伪造”网址方法。罪魁祸首似乎是 UrlExtensions 类的 GetQueryProperties 方法:http://www.diffchecker.com/u1nyqpcw
wiki 上的路由文档提供了有关 ServiceStack 中路由的信息。此外,您在这里尝试执行的方法与ServiceStack 的 Stripe Gateway 相同,它使用属性 DTO 和通用 StripeGateway 客户端 来提供类型化 API 客户端。
您的路线存在一些问题,应以
/
开头,并且组件需要用斜杠分隔,因此:
[Route("repositories/{Accountname}/{RepositorySlug }issues/{local_id}")]
应该是:
[Route("/repositories/{Accountname}/{RepositorySlug}/issues/{local_id}")]
对于像这样的类型化网关有用的另一个自定义选项是使用
[IgnoreDataMember]
来指定仅应在路由上而不是在 POST 的 DTO 中的属性,例如:
[Route("/path/{UseOnlyOnUrl}")]
public class Request
{
[IgnoreDataMember]
public string UseOnlyOnUrl { get; set; }
public string Data { get; set; }
}
检查路由生成的 url 的快速方法是使用
To{Verb}Url()
扩展方法,例如:
new Request().ToGetUrl().Print();
new Request().ToPostUrl().Print();
new Request().ToPutUrl().Print();
new Request().ToDeleteUrl().Print();
new Request().ToUrl("CustomVerb","json").Print();
您可以使用它们来验证每个请求 DTO 在不同的 HTTP 方法中使用时将生成哪些路径。