c# - 我们可以从构造函数中调用异步方法吗?
问题描述
我需要从 mvc 应用程序调用第三方异步方法。此异步方法的名称是 ForceClient.QueryAsync。它来自一个开源项目:https ://github.com/developerforce/Force.com-Toolkit-for-NET/ 。
下面工作正常,当进程处于 mvc 的 View 阶段时,model.Opportunity 包含预期的信息:
public async Task<ActionResult> MyController(string Id) {
. . . .
MyModel model = new MyModel();
var client = new ForceClient(instanceUrl, accessToken, apiVersion);
var qry = await client.QueryAsync<MyModel.SFOpportunity>(
"SELECT Name, StageName FROM Opportunity where Id='" + Id + "'");
model.Opportunity = qry.Records.FirstOrDefault();
. . . .
return View(viewName, myModel);
}
但下面不起作用。当流程处于 View 阶段时,model.Opportunity 为 null。我做了一些调试,发现流程是这样的:
1) 第一步
2) 第二步
3) 在视图阶段。此时 model.Opportunity 为空,我需要填充它。
4) 第三步。
public async Task<ActionResult> MyController(string Id) {
. . . .
MyModel myModel = await Task.Run(() =>
{
var result = new MyModel(Id);
return result;
}); // =====> Step 1
. . . .
return View(viewName, myInfoView);
}
public class MyModel
{
public SFOpportunity Opportunity { get; set; }
public MyModel(string id)
{
setOpportunityAsync(id);
}
private async void setOpportunityAsync(string id)
{
. . .
var client = new ForceClient(instanceUrl, accessToken, apiVersion);
var qry = await client.QueryAsync<MyModel.SFOpportunity>(
"SELECT Name, StageName FROM Opportunity where Id='" + id + "'"); // ======> Step2
Opportunity = qry.Records.FirstOrDefault(); // =====> step3
}
所以,我的问题是我需要做什么才能让它按以下顺序执行步骤:1)Step1
2) 第二步
3) 第三步
4) 在视图阶段。此时应该填充 model.Opportunity。
解决方案
for 的构造函数MyModel
不会(也不能)等待setOpportunityAsync
,因为构造函数本身不是(也不能是)异步的。否则,您将能够等待对构造函数本身的调用,但您不能。因此,在调用构造函数后,异步方法可能不会立即完成执行。它将完成……无论何时完成。
这是一个较小的测试类来说明行为:
public class HasConstructorWithAsyncCall
{
public HasConstructorWithAsyncCall()
{
MarkConstructorFinishedAsync();
}
public bool ConstructorHasFinished { get; private set; }
async void MarkConstructorFinishedAsync()
{
await Task.Delay(500);
ConstructorHasFinished = true;
}
}
ConstructorHasFinished
实例构建后立即的值是多少?这是一个单元测试:
[TestMethod]
public void TestWhenConstructorFinishes()
{
var subject = new HasConstructorWithAsyncCall();
Assert.IsFalse(subject.ConstructorHasFinished);
Thread.Sleep(600);
Assert.IsTrue(subject.ConstructorHasFinished);
}
测试通过。构造函数在MarkConstructorFinishedAsync
尚未完成时返回,因此ConstructorHasFinished
为 false。半秒后它完成,值为真。
你不能标记一个构造函数async
,所以你不能await
在构造函数中做任何事情。
一般来说,我们不会将任何像数据检索这样的长时间运行的东西放在构造函数中,包括我们会异步调用的任何东西。如果我们这样做,那么我们必须要么同步调用它,要么知道构造函数的完成并不意味着它是完全“构造的”。
推荐阅读
- java - 在上下文路径部署应用程序失败
- database - 如何生成一个表格,其中包含一个汇总表,指示分为不同年份的两个时期的两个指标的平均值?
- r - 通过乘以常数增加回归中(控制)变量的效果
- git - 如何解决与受保护分支的合并冲突?
- c - 函数调用之外的指针取消引用不会编译,但内部可以
- string - tk.messagebox.showerror() 出现错误情况
- matlab - MATLAB:获取向量结构的最小 x 值
- visual-studio - .tfignore 路径没有被忽略
- pandas - 为大日期框架改进 Pandas PeriodIndex
- r - 在 R 中使用 ML 模型进行决策变量优化