Установить свойство контроллера асинхронно в конструкторе - PullRequest
1 голос
/ 03 октября 2019

У меня есть полностью асинхронный API MVC, который внедряет интерфейс во все его контроллеры:

public PageController(IDataAdapter dataAdapter) {
    _dataAdapter = dataAdapter;
}

Реализация интерфейса должна иметьмаркер доступа установлен в его объекте SQLConnection. Этот токен доступа необходим для безопасного доступа к управляемой идентификации (см. https://docs.microsoft.com/en-us/azure/app-service/app-service-web-tutorial-connect-msi).. Этот токен должен быть установлен при создании контроллера, то есть при каждом новом запросе. Токен может изменяться, поэтому мы не можем его иметь. статическое значение. Вот что мы имеем сегодня в реализации интерфейса:

public partial class DataAdapter : BaseEntityDataAdapter, IDataAdapter {
    AppInsightsLogger _log = new AppInsightsLogger();

    #region Constructor
    /// <summary>   
    /// Instantiate the data adapter and pull out the dsn information
    /// </summary>
    public DataAdapter() : base("db") {
        try {
            var conn = base.Database.Connection as System.Data.SqlClient.SqlConnection;
            conn.AccessToken = (new AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net/").Result;
        } catch (Exception ex) {
            _log.LogError(ex);
            throw;
        }
    }
}

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

public async Task<DataAdapter> ConstructAdapterAsync() {
    try {
        DataAdapter da = new DataAdapter();
        var conn = da.Database.Connection as System.Data.SqlClient.SqlConnection;
        conn.AccessToken = await (new AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net/");

        return da;
    } catch (Exception ex) {
        _log.LogError(ex);
        throw;
    }
}

Но это все еще оставляет меня с проблемой, что в конструкторе контроллера я не могу вызвать асинхронную фабричную функциюне заставляя его работать синхронно. В любом случае, я могу установить это свойство асинхронно?

1 Ответ

0 голосов
/ 03 октября 2019

Когда мне нужно что-то похожее, я использовал шаблон фабрики, но с двумя ключевыми вещами:

  1. Сделать метод фабрики статическим методом в самом классе, так как это дает вам доступ кprivate свойства и методы.
  2. Пометьте конструктор как private, чтобы никто не мог использовать класс без использования фабричного метода.

В вашем случае это будетвыглядеть примерно так:

public partial class DataAdapter : BaseEntityDataAdapter, IDataAdapter {
    AppInsightsLogger _log = new AppInsightsLogger();

    private DataAdapter() : base("db") { }

    public static async Task<DataAdapter> ConstructAdapterAsync() {
        DataAdapter da = new DataAdapter();
        try {
            var conn = da.Database.Connection as System.Data.SqlClient.SqlConnection;
            conn.AccessToken = await (new AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net/");

            return da;
        } catch (Exception ex) {
            da._log.LogError(ex);
            throw;
        }
    }
}
...