更新:签名和类型定义
GetChecklistStringParents
IObservable<ChecklistStringParents_Response> GetChecklistStringParents(int company_id, string auth_token, string q = null, int page = 1)
代表页面的顶级响应
public class ChecklistStringParents_Response
{
//the content of the page a list of string parents
public List<Resp_ChecklistStringParent> BODY { get; set; }
public Resp_Meta META { get; set; }
public List<object> ERRORS { get; set; }
}
单个字符串父级的响应类
public class Resp_ChecklistStringParent
{
public int checklist_string_type { get; set; }
public string client_date_created { get; set; }
public string uploaded_date { get; set; }
public string last_modified { get; set; }
public string value { get; set; }
public int id { get; set; }
}
我试图反应(RxNet)访问我已构建的REST API,但是我对这个范例很新,而且有点卡住了。
以下函数逐页请求端点数据。
使用 Observable.DoWhile
和Observable.Defer
以便为每个页面创建一个新的observable,我们会一直创建它们,直到我们收到一个空列表
作为页面回复的主体。
我订阅Observable.DoWhile
返回的observable来更新页面并更新结果计数。这感觉不对,但我还没有看到替代方案。
我的问题是,这是在RxNet中分页结果的最佳方法吗?另外,我真的想得到一个结果流,即每个页面的内容被展平为一个可观察的,我可以从这个函数返回,但我不知道如何实现这个。
private void FetchStringParents(int checklist_id)
{
/*Setup the filter to the endpoint such that string parents returned are those associated with the passed checklist*/
Filter base_filter = new Filter("checklist_id", "eq", checklist_id.ToString());
NestedFilter nested_filter = new NestedFilter("checklists", "any", base_filter);
Filters filt = new Filters();
filt.filters.Add(nested_filter);
string sp_query_json = JsonConvert.SerializeObject(filt);
int result_count = 0;
int page = 1;
var paged_observable = Observable.DoWhile(
//At least once create an observable on the api endpoint
Observable.Defer(() => NetworkService_ChecklistStringParentService.GetInstance.GetChecklistStringParents(6,
this.cached_auth.Auth_Token, sp_query_json, page)),
/*boolean function which determines if we should hit the api again (if we got back a non empty result the last time)*/
() => result_count > 0)
.Subscribe(
st =>
{
//on successful receipt of a page
Debug.WriteLine("Success");
page++;//update page so that the next observable created is created on page++
result_count = st.BODY.Count;//update result_count (we will stop listening on a count of 0)
},
_e =>
{
Debug.WriteLine("Fail");
});
}
更新:解决方案
private IObservable<Resp_ChecklistStringParent> StreamParents(int checklist_id)
{
Filter base_filter = new Filter("checklist_id", "eq", checklist_id.ToString());
NestedFilter nested_filter = new NestedFilter("checklists", "any", base_filter);
Filters filt = new Filters();
filt.filters.Add(nested_filter);
string sp_query_json = JsonConvert.SerializeObject(filt);
return Observable.Create<List<Resp_ChecklistStringParent>>(async (obs, ct) =>
{
int pageIdx = 1;
//for testing page size is set to 1 on server
int pageSize = 1;
while (!ct.IsCancellationRequested)
{
//Pass in cancellation token here?
var page = await NetworkService_ChecklistStringParentService.GetInstance.GetChecklistStringParents(6,
this.cached_auth.Auth_Token, sp_query_json, pageIdx++);
obs.OnNext(page.BODY);
if (page.BODY.Count < pageSize)
{
obs.OnCompleted();
break;
}
}
})
.SelectMany(page => page);
}
答案 0 :(得分:2)
以下示例展示了如何使用IEnumerable<T>
和IObservable<T>
来传输数据。
IEnumerable<T>
样本用于上下文和比较。
我没有使用您的数据类型,因为我认为它与问题无关(希望没问题)。
Linqpad脚本
void Main()
{
var enumerableItems = GetItemsSync();
foreach (var element in enumerableItems)
{
Console.WriteLine(element);
}
Console.WriteLine("Received all synchronous items");
StreamItems().Subscribe(
element => Console.WriteLine(element),
() => Console.WriteLine("Received all asynchronous items"));
}
// Define other methods and classes here
public IObservable<string> StreamItems()
{
return Observable.Create<string[]>(async (obs, ct) =>
{
var pageIdx = 0;
var pageSize = 3;
while (!ct.IsCancellationRequested)
{
//Pass in cancellation token here?
var page = await GetPageAsync(pageIdx++, pageSize);
obs.OnNext(page);
if (page.Length < pageSize)
{
obs.OnCompleted();
break;
}
}
})
.SelectMany(page => page);
}
public IEnumerable<string> GetItemsSync()
{
return GetPagesSync().SelectMany(page => page);
}
public IEnumerable<string[]> GetPagesSync()
{
var i = 0;
var pageSize = 3;
while (true)
{
var page = GetPageSync(i++, pageSize);
yield return page;
if (page.Length < pageSize)
yield break;
}
}
private static string[] _fakeData = new string[]{
"one",
"two",
"three",
"four",
"Five",
"six",
"Se7en",
"Eight"
};
public string[] GetPageSync(int pageIndex, int pageSize)
{
var idx = pageSize * pageIndex;
var bufferSize = Math.Min(pageSize, _fakeData.Length-idx);
var buffer = new string[bufferSize];
Array.Copy(_fakeData, idx, buffer, 0, bufferSize);
return buffer;
}
public Task<string[]> GetPageAsync(int pageIndex, int pageSize)
{
//Just to emulate an Async method (like a web request).
return Task.FromResult(GetPageSync(pageIndex, pageSize));
}