Подтвердить что ты не робот

Как вызвать некоторый асинхронный код в ASP.NET application_start

В нашем приложении application_startup мы запустили нашу базу данных с некоторыми поддельными данными, если данных не существует.

Для этого мы используем методы Async для хранения данных. Отлично. Единственная проблема заключается в том, что мы не знаем, как это сделать в application_startup, потому что это не метод асинхронизации.

Я потратил столько времени, пытаясь понять учебники @StevenCleary, и я всегда получаю тупики. Я полностью понимаю, что он постоянно говорит:

Как правило, вы должны использовать "async all the down"; то есть не блокировать асинхронный код

но я просто не понимаю, как это сделать, в этом случае: (

Позволяет себе представить, что это код, который я пытаюсь воспроизвести с помощью...

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, синхронно. Конечно, я теряю преимущества async blah blah de blah.. но я доволен этим. Это запускается, и я счастлив заблокировать при запуске.

4b9b3361

Ответ 1

В этом случае вы асинхронно инициализируете общий ресурс. Поэтому я рекомендую вам либо сохранить сам 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>, который делает то же самое, но использует фоновый поток для выполнения кода инициализации.

Ответ 2

Ваш ожидаемый метод InitializeAsync() должен возвращать Задачу. Вы можете сделать этот вызов синхронно, ожидая завершения задачи.

Один из способов сделать это в коде:

documentStore.InitializeAsync().Wait();

Вы можете быть в порядке, потому что это происходит при запуске приложения. Это должно произойти только один раз для запуска приложения.

Однако вы можете также рассмотреть возможность запуска его в другом потоке. Я не знаю, что вы в значительной степени выиграете, сделав это, в вашем случае. Вероятно, вы не хотите начинать обработку других веб-запросов до тех пор, пока эта работа по запуску не будет выполнена. В конце концов, это настройка вашего хранилища документов, который, как я полагаю, станет ключевой частью ваших будущих запросов приложений.

Вы можете узнать больше о ожидании выполнения задач: https://msdn.microsoft.com/en-us/library/dd537610(v=vs.110).aspx

Вы можете утверждать, что ваш метод инициализации не обязательно должен поддерживать async. Но это дизайнерское решение для вас. Лучшая причина для поддержки асинхронного вызова вашей базы данных заключается в том, что если все сделано правильно, потоки, обслуживающие эти веб-запросы, могут бесплатно обслуживать другие веб-запросы во время завершения операции с базой данных. Все это происходит в миллисекундах. Однако, если ваш веб-сайт может обслуживать статический файл в 12 мс, но ему требуется 50 мс для записи в базу данных (составленные номера), тогда этот поток, возможно, подобрал и выполнил еще несколько запросов за это время.

Ответ 4

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(){ ....