ServiceStack中的复杂路由

时间:2014-07-27 22:46:22

标签: c# .net api servicestack

我正在尝试使用ServiceStack为BitBucket api编写包装器。 api有相当复杂的网址,例如:

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; }
}

所以基本上我将这两个参数与整个问题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

1 个答案:

答案 0 :(得分:1)

Routing docs on the wiki提供有关ServiceStack中路由的信息。此外,您尝试在此处执行的方法与ServiceStack's Stripe Gateway使用属性DTO和generic StripeGateway client提供类型化API客户端的方法相同。

您的路线存在一些问题,应该以{{1​​}}开头,并且组件需要用斜杠分隔:

/

应改为:

[Route("repositories/{Accountname}/{RepositorySlug }issues/{local_id}")]

对此类型网关有用的另一个自定义选项是使用[Route("/repositories/{Accountname}/{RepositorySlug}/issues/{local_id}")] 来指定仅应在路径上而不在POST的DTO中的属性,例如:

[IgnoreDataMember]

检查路由生成的URL的快速方法是使用[Route("/path/{UseOnlyOnUrl}")] public class Request { [IgnoreDataMember] public string UseOnlyOnUrl { get; set; } public string Data { get; set; } } 扩展方法,例如:

To{Verb}Url()

您可以使用这些来验证每个Request DTO在不同的HTTP方法中使用时将生成哪些路径。