我有一个Singleton(好吧,它可以是一个静态类,无所谓),这是我的WPF应用程序的一些数据的外观.我想通过WCF加载此数据异步.这是我的实现:
public class Storage
{
private static readonly Lazy<Storage> _lazyInstance = new Lazy<Storage>(()=>new Storage());
public static Storage Instance
{
get { return _lazyInstance.Value; }
}
private Storage()
{
Data = new Datastorage(SettingsHelper.LocalDbConnectionString);
InitialLoad().Wait();
}
public Datastorage Data { get; private set; }
private async Task InitialLoad()
{
var tasks = new List<Task>
{
InfoServiceWrapper.GetSomeData()
.ContinueWith(task => Data.StoreItem(task.Result)),
InfoServiceWrapper.GetAnotherData()
.ContinueWith(task => Data.StoreItem(task.Result)),
InfoServiceWrapper.GetSomeMoreData()
.ContinueWith(task => Data.StoreItem(task.Result)),
};
await Task.WhenAll(tasks.ToArray());
}
}
Run Code Online (Sandbox Code Playgroud)
我从我的ViewModel访问这个类,如下所示:
public class MainWindowViewModel:ViewModelBase
{
public SensorDTO RootSensor { get; …Run Code Online (Sandbox Code Playgroud) 我有一个界面,它为我提供了一条特定的路径.在我需要使用的一个实现中async,但我还没有弄清楚如何将异步方法的结果转换为同步方法.这是代码示例:
接口:
public interface IFilePath
{
string GetAsset();
}
Run Code Online (Sandbox Code Playgroud)
有问题的实施:
public class FilePath : IFilePath
{
public string GetAsset()
{
return GetAssetAssync();
}
private async Task<string> GetAssetAssync()
{
StorageFolder assetsFolder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync(@"Assets").AsTask().ConfigureAwait(false);
return assetsFolder.Path;
}
}
Run Code Online (Sandbox Code Playgroud)
仅对于此实现,我需要异步调用.所有其他人都不需要它.所以我不能使用public Task<string> GetAsset()或者我可以以某种方式?
我正在尝试从在 IIS 8.5 上运行的 ASP.NET 应用程序中对另一台服务器进行 HTTP 调用。
首先,我从 Microsoft 的一篇文章Call a Web API From a .NET Client (C#) 中得到了一些提示。我可以很容易地看到他们如何在那里进行 HTTP 调用的模式;仅显示一个缩短的示例:
static async Task<Product> GetProductAsync(string path)
{
HttpResponseMessage response = await client.GetAsync(path);
if (response.IsSuccessStatusCode)
{
// retrieve response payload
... = await response.Content.ReadAsAsync<...>();
}
// do something with data
}
Run Code Online (Sandbox Code Playgroud)
很简单,我想,所以我很快为我的应用程序编写了一个类似的方法(请注意,ReadAsAsync扩展方法似乎需要一个额外的库,所以我选择了一种内置的、更抽象的,但在其他方面可能是类似的方法):
private async Task<MyInfo> RetrieveMyInfoAsync(String url)
{
var response = await HttpClient.GetAsync(url);
response.EnsureSuccessStatusCode();
var responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<MyInfo>(responseBody);
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,调用此方法会导致我的应用程序挂起。调试时,事实证明await …
当可等待任务完成但启动异步方法的线程不可用(例如处理另一个请求)时,在 C# 中会发生什么?然后将使用另一个线程而不是第一个线程,或者执行将等到繁忙线程可用?
预先感谢您的回答。
我很确定这里某处有一个副本,但我找不到它。
很简单,最好这样做:
await MyMethod();
Run Code Online (Sandbox Code Playgroud)
和:
public async Task MyMethod()
{
Thread.Sleep(10000); // Simulates long running operation
}
Run Code Online (Sandbox Code Playgroud)
或涉及 Task.Run 的东西?
public async Task MyMethod()
{
await Task.Run(() => Thread.Sleep(10000)); // Simulates long running operation
}
Run Code Online (Sandbox Code Playgroud)
实际长时间运行的操作是一个不支持异步的阻塞调用。
第一个例子显然有 Visual Studio 抱怨它会同步运行。使该方法异步的原因是因为我希望人们能够轻松地await使他们不会占用他们的线程。
HttpContext.Current在等待调用后在异步中为null。
这是我的代码:
if (!string.IsNullOrEmpty(securityGroupName))
{
// To remove the domain name from the security group name.
string securityGroupDisplayName = securityGroupName.Split('\\')[1];
string serviceSecurityGroupId = await this.graphApiClient.GetGroupIdAsync(securityGroupDisplayName).ConfigureAwait(false);
if (!string.IsNullOrEmpty(serviceSecurityGroupId))
{
Task securityGroupRoleAddTask = this.CheckMembershipAndAddRole(serviceSecurityGroupId, userId, securityGroupName);
Task flightAdminRoleAddTask = this.CheckMembershipAndAddRole(FlightAdminSecurityGroupId, userId, FlightAdminRoleName);
Task.WaitAll(securityGroupRoleAddTask, flightAdminRoleAddTask);
}
else
{
LoggingUtilities.Logger.TraceInformation("Azure AD id does not exist for the security group: {0}.", securityGroupName);
await this.CheckMembershipAndAddRole(FlightAdminSecurityGroupId, userId, FlightAdminRoleName).ConfigureAwait(false);
}
}
else
{
LoggingUtilities.Logger.TraceInformation("Security group name is not valid, checking for flight admin role for the user: {0}.", …Run Code Online (Sandbox Code Playgroud) 刚刚阅读了这篇关于 ConfigureAwait 的文章,它让我思考了一个我已经有一段时间无法平静下来的问题。
考虑下面的代码。每个依赖项都用于await使调用异步。我担心的是,每次我们退出时,await它都会返回到 UI 线程,我不希望这样,直到我真正处于需要更新 UI 以减少线程上下文切换的顶层为止。这让我觉得ConfigureAwait(false)应该在 UI 下方的层中使用,以避免不必要Post的 ( SynchronizationContext) 到 UI 线程。
你怎么认为?这是必要的还是我离开了?或者运行时实际上会为我处理这个问题?
ConfigureAwait(false):public class ViewModel
{
private readonly Service service;
private readonly ICommand updateCommand;
public ViewModel(Service service)
{
this.service = service;
updateCommand = new RelayCommand(UpdateUser);
}
private async void UpdateUser()
{
Cursor.ShowWait();
await service.UpdateUser(SelectedUser);
Cursor.ShowDefault();
}
}
public class Service
{
private readonly Repository repository;
public Service(Repository repository)
{
this.repository = repository; …Run Code Online (Sandbox Code Playgroud) 但是,使用ASP.NET Web Api,如果您的请求是在一个线程上进行的,并且等待某些函数和调用
ConfigureAwait(false),则在返回ApiController函数的最终结果时可能会将您置于不同的线程上.实际上,只是做一个
await可以做到这一点.一旦你的async方法遇到一个await,该方法被阻止但线程返回到线程池.当方法准备好继续时,从线程池中抢夺任何线程并用于恢复该方法.
我刚刚在控制台程序中测试过:
async Task foo()
{
int y = 0;
while (y<5) y++;
}
async Task testAsync()
{
int i = 0;
while (i < 100)
{
Console.WriteLine("Async 1 before: " + i++);
}
await foo();
while (i < 105)
{
i++;
Console.WriteLine("Async 1 after: " + i);
}
}
Run Code Online (Sandbox Code Playgroud)
调用await foo()不会导致线程testAsync运行返回到线程池,testAsync只是从头到尾在同一个线程上逐行运行.我在这里错过了什么?