【问题标题】:Can't access method (Azure Tables with ASP.NET Core)无法访问方法(带有 ASP.NET Core 的 Azure 表)
【发布时间】:2018-09-30 16:16:33
【问题描述】:

我正在尝试从另一个类(我的视图的控制器)访问一个方法,在该类中我与 Azure Tables 建立连接并更新实体。

我的“控制器”拨打电话如下:

// this requires an object reference
HttpResponseMessage httpResponseMessage = AzureTableConn.UpdateTenantSettings(post);

这是我的课程,其中包含我与 Azure Tables 的连接,我从 Azure Key Vault 中提取连接字符串:

public class AzureTableConn
{
    public AzureTableConn(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    private IConfiguration Configuration { get; set; }

    private CloudTable TableConnection(string tableName)
    {
        var connectionString = Configuration["AzureTableStorageConnectionString"];
        var cloudStorageAccount = CloudStorageAccount.Parse(connectionString);
        CloudTableClient tableClient = cloudStorageAccount.CreateCloudTableClient();
        CloudTable cloudTable = tableClient.GetTableReference(tableName);
        return cloudTable;            
    }

    public HttpResponseMessage UpdateTenantSettings(TenantSettingsModel tenantSettingsModel)
    {
        CloudTable cloudTable = TableConnection("TenantSettings");
        Task<TableResult> mergeEntity = cloudTable.ExecuteAsync(TableOperation.Merge(tenantSettingsModel));
        return new HttpResponseMessage();
    }
}

我希望能够从我的控制器类中调用UpdateTenantSettings 方法,但它说我需要一个实例。这是有道理的,但是如果不向默认构造函数提供 IConfiguration 对象,我将无法创建实例。我觉得自己陷入了第 22 条陷阱,并且没有足够的知识来绕过它。

我的意图是在我的应用程序中使用我的 AzureTableConn 类,而不是在每次我想读/写 Azure 表时创建它的新实例。我尝试将我的AzureTableConn 类设置为静态,虽然这可以解决对象引用错误,但我对IConfiguration 的引用出现问题。我也尝试将我的构造函数设置为静态,但这再次打破它并告诉我“静态构造函数必须是无参数的”。

我还尝试将以下内容添加到我的 Startup.cs 文件中:

services.Configure<AzureTableConnectionString>(Configuration);

其中AzureTableConnectionString 定义为:

public class AzureTableConnectionString
{
    public string ConnectionString { get; set; }
}

但是,我不知道这是否正确或如何实现。

那么我怎样才能将我的 Azure Key Vault 配置设置拉到一个类中,然后使用同一个类中的方法来重新使用与 Azure 表的连接,并从另一个我需要提供参数的类访问这些方法,例如要创建/更新/删除/等的实体(数据)?

【问题讨论】:

    标签: c# azure azure-table-storage azure-keyvault


    【解决方案1】:

    您可以通过向 DI 容器注册 AzureTableConn 来让 ASP.NET Core 为您处理这个问题,如下所示(在 ConfigureServices 中):

    services.AddSingleton<AzureTableConn>();
    

    为了在您的控制器中使用它,只需将其作为参数添加到控制器的构造函数并存储以供以后使用,如下所示:

    public class SomeController : Controller
    {
        private readonly AzureTableConn _azureTableConn;
    
        public SomeController(AzureTableConn azureTableConn)
        {
            _azureTableConn = azureTableConn;
        }
    
        public IActionResult SomeAction()
        {
            ...
            var httpResponseMessage = _azureTableConn.UpdateTenantSettings(post);
            ...
        }
    }
    

    通过此示例,您可以在控制器的任何操作中使用_azureTableConn。因为我们使用了AddSingleton,所以每个控制器都会获得相同的实例,该实例只会被创建一次。

    文档很好地解释了这一点:Dependency injection in ASP.NET Core。

    【讨论】:

    • 对不起,今天早上有点厚。因此,如果我理解正确,我基本上是在创建一个引入 IConfiguration Configuration 的类,因此我可以在该类中使用它,但 AzureStorageConn 类是在启动时使用单例(一个实例)命令创建的。然后,您可以引用AzureStorageConn 的方法,如上所示。我不得不移动相当多的代码来防止破坏,但这看起来会起作用!
    • 是的,这听起来很对。既然您不想将 AzureTableConn 作为静态类依赖,您需要使用构造函数等通过 DI 传递实例,因此对此进行了一些更改,但您的 AzureTableConn 至少应该保持原样.我已经用引用 AzureStorageConn 方法的具体示例更新了答案。
    • 您可以使用@Nkosi 的方法从您的AzureTableConn 类中删除对IConfiguration 的依赖,这当然也值得考虑。我认为您的问题有一个答案位于此答案和@Nkosi 的答案之间,该答案也消除了上述IConfiguration 依赖,但整体抽象较轻。
    • 太好了,当我从旧方法转换每个方法的引用时,我显然需要在每个方法中添加对AzureTableConn 的引用,这样我就可以使用_azureTableConn 来获取这些方法。完美的。现在开始变得更有意义了:)
    • 是的 - 使用 DI 的缺点是实际获取实例有点困难(您需要将它们传递下来等),但灵活性方面的好处远远超过了这一点。
    【解决方案2】:

    考虑创建一个抽象。

    public interface IAzureTableConnection {
        Task<HttpResponseMessage> UpdateTenantSettings(TenantSettingsModel tenantSettingsModel);
    }
    

    通常建议避免与IConfiguration 耦合。相反,在组合根中获取您需要的内容并将其传递给依赖类。

    Startup

    private IConfiguration Configuration { get; set; }
    
    public void ConfigureServices(IServiceCollection services) {
    
        //...
    
        var connectionString = Configuration["AzureTableStorageConnectionString"];
        var cloudStorageAccount = CloudStorageAccount.Parse(connectionString);
        CloudTableClient tableClient = cloudStorageAccount.CreateCloudTableClient();
    
        services.AddScoped<IAzureTableConnection>(_ => new AzureTableConnection(tableClient));
    
        //...
    }
    

    依赖类将只需要依赖于配置的CloudTableClient

    public class AzureTableConnection: IAzureTableConnection {
        private readonly CloudTableClient tableClient;
    
        public AzureTableConnection(CloudTableClient tableClient) {
            this.tableClient = tableClient;
        }
    
        private CloudTable TableConnection(string tableName) {
            CloudTable cloudTable = tableClient.GetTableReference(tableName);
            return cloudTable;            
        }
    
        public async Task<HttpResponseMessage> UpdateTenantSettings(TenantSettingsModel tenantSettingsModel) {
            CloudTable cloudTable = TableConnection("TenantSettings");
            var mergeEntity = await cloudTable.ExecuteAsync(TableOperation.Merge(tenantSettingsModel));
    
            //...do something with the result
    
            return new HttpResponseMessage();
        }
    }
    

    您的控制器将通过构造函数注入显式依赖IAzureTableConnection 抽象,并在需要时访问注入的实例

    public class MyController : Controller {
        private readonly IAzureTableConnection tableConnection;
    
        public MyController(IAzureTableConnection tableConnection) {
            this.tableConnection = tableConnection;
        }
    
        public async Task<IActionResult> MyAction() {
    
    
            //...
    
            HttpResponseMessage httpResponseMessage = await tableConnection.UpdateTenantSettings(post);
    
            //...
        }
    }
    

    【讨论】:

    • 这也很有帮助。我之前没有创建过接口。在你的例子中它在哪里(public interface IAzureTableConnection)?
    猜你喜欢
    • 1970-01-01
    • 2019-05-09
    • 1970-01-01
    • 1970-01-01
    • 2017-01-01
    • 2019-05-05
    • 1970-01-01
    • 2019-07-26
    • 2016-08-11
    相关资源
    最近更新 更多