如何在 ASP.NET application_start 中调用一些异步代码
How to call some async code in an ASP.NET application_start
在我们的 application_startup 中,如果不存在任何数据,我们会在数据库中植入一些假数据。
为此,我们使用 Async
方法来存储数据。伟大的。唯一的问题是,我们不确定如何在 application_startup
中执行此操作,因为那不是异步方法。
我花了太多时间试图理解@StevenCleary 的教程,但我总是遇到僵局。我完全 grok what he consistently says:
As a general rule, you should use "async all the way down"; that is, don't block on async code
但我只是不知道我该怎么做,在这种情况下:(
让我们想象这是我正在尝试使用的代码...
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStore = new DocumentStore();
await documentStore.InitializeAsync(someFakeData);
...
// Registers this database as a singleton.
Container.Register(documentStore);
}
以及后来的一些代码使用了这个 documentStore
。它是通过构造注入注入的...
public SomeController(IDocumentStore documentStore)
{
_documentStore = documentStore;
}
public ViewModel GetFoos()
{
using (var session = _documentStore.OpenSession())
{
... db code goes in here ...
}
}
澄清
我不是试图在这里做一些异步代码。我实际上是在尝试调用这个异步方法,同步。当然,我失去了 async blah blah de blah 的好处.. 但我对此很满意。这是启动,我很乐意阻止启动。
在这种情况下,您正在异步初始化共享资源。因此,我建议您要么保存 Task
本身,要么引入异步包装类型。
使用Task
:
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStore = new DocumentStore();
var documentStoreTask = documentStore.InitializeAsync(someFakeData);
...
// Registers this database task as a singleton.
Container.Register(documentStoreTask);
}
不过,这可能太尴尬了,具体取决于 Container
。在那种情况下,你可以引入一个异步包装器类型:
public sealed class DocumentStoreWrapper
{
private readonly Task<DocumentStore> _documentStore;
public DocumentStoreWrapper(Data data)
{
_documentStore = CreateDocumentStoreAsync(data);
}
private static async Task<DocumentStore> CreateDocumentStoreAsync(Data data)
{
var result = new DocumentStore();
await documentStore.InitializeAsync(data);
...
return result;
}
public Task<DocumentStore> DocumentStoreTask { get { return _documentStore; } }
}
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStoreWrapper = new DocumentStoreWrapper(someFakeData);
...
// Registers this database wrapper as a singleton.
Container.Register(documentStoreWrapper);
}
或者,您可以使用 AsyncLazy<T>
,其功能大致相同,但使用后台线程来执行初始化代码。
public static class AsyncHelper
{
private static readonly TaskFactory MyTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return MyTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
public static void RunSync(Func<Task> func)
{
MyTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
}
然后用作
AsyncHelper.RunSync(ProcessAsync);
private async Task ProcessAsync(){ ....
您可以在 none 异步方法中使用 Task.Run(() => YourAsyncMethod());
,例如:
protected void Application_Start()
{
Task.Run(() => MyAsyncMethod(true));
}
这是一个老话题,但它出现在我的搜索中,也许其他人也会。
对于 OP 所请求的内容(即从同步方法内部以同步方式 运行 异步方法,并阻塞直到它完成),是否有某种原因使用 Task.WaitAll 不是解决这个问题的简单而充分的方法吗?
protected void Application_Start()
{
Task.WaitAll(MyAsyncMethod(true));
}
在我们的 application_startup 中,如果不存在任何数据,我们会在数据库中植入一些假数据。
为此,我们使用 Async
方法来存储数据。伟大的。唯一的问题是,我们不确定如何在 application_startup
中执行此操作,因为那不是异步方法。
我花了太多时间试图理解@StevenCleary 的教程,但我总是遇到僵局。我完全 grok what he consistently says:
As a general rule, you should use "async all the way down"; that is, don't block on async code
但我只是不知道我该怎么做,在这种情况下:(
让我们想象这是我正在尝试使用的代码...
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStore = new DocumentStore();
await documentStore.InitializeAsync(someFakeData);
...
// Registers this database as a singleton.
Container.Register(documentStore);
}
以及后来的一些代码使用了这个 documentStore
。它是通过构造注入注入的...
public SomeController(IDocumentStore documentStore)
{
_documentStore = documentStore;
}
public ViewModel GetFoos()
{
using (var session = _documentStore.OpenSession())
{
... db code goes in here ...
}
}
澄清
我不是试图在这里做一些异步代码。我实际上是在尝试调用这个异步方法,同步。当然,我失去了 async blah blah de blah 的好处.. 但我对此很满意。这是启动,我很乐意阻止启动。
在这种情况下,您正在异步初始化共享资源。因此,我建议您要么保存 Task
本身,要么引入异步包装类型。
使用Task
:
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStore = new DocumentStore();
var documentStoreTask = documentStore.InitializeAsync(someFakeData);
...
// Registers this database task as a singleton.
Container.Register(documentStoreTask);
}
不过,这可能太尴尬了,具体取决于 Container
。在那种情况下,你可以引入一个异步包装器类型:
public sealed class DocumentStoreWrapper
{
private readonly Task<DocumentStore> _documentStore;
public DocumentStoreWrapper(Data data)
{
_documentStore = CreateDocumentStoreAsync(data);
}
private static async Task<DocumentStore> CreateDocumentStoreAsync(Data data)
{
var result = new DocumentStore();
await documentStore.InitializeAsync(data);
...
return result;
}
public Task<DocumentStore> DocumentStoreTask { get { return _documentStore; } }
}
protected void Application_Start()
{
var someFakeData = LoadSomeFakeData();
var documentStoreWrapper = new DocumentStoreWrapper(someFakeData);
...
// Registers this database wrapper as a singleton.
Container.Register(documentStoreWrapper);
}
或者,您可以使用 AsyncLazy<T>
,其功能大致相同,但使用后台线程来执行初始化代码。
public static class AsyncHelper
{
private static readonly TaskFactory MyTaskFactory = new
TaskFactory(CancellationToken.None,
TaskCreationOptions.None,
TaskContinuationOptions.None,
TaskScheduler.Default);
public static TResult RunSync<TResult>(Func<Task<TResult>> func)
{
return MyTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
public static void RunSync(Func<Task> func)
{
MyTaskFactory
.StartNew(func)
.Unwrap()
.GetAwaiter()
.GetResult();
}
}
然后用作
AsyncHelper.RunSync(ProcessAsync);
private async Task ProcessAsync(){ ....
您可以在 none 异步方法中使用 Task.Run(() => YourAsyncMethod());
,例如:
protected void Application_Start()
{
Task.Run(() => MyAsyncMethod(true));
}
这是一个老话题,但它出现在我的搜索中,也许其他人也会。
对于 OP 所请求的内容(即从同步方法内部以同步方式 运行 异步方法,并阻塞直到它完成),是否有某种原因使用 Task.WaitAll 不是解决这个问题的简单而充分的方法吗?
protected void Application_Start()
{
Task.WaitAll(MyAsyncMethod(true));
}