如何始终执行功能,而不管调用的 API 路由如何?

How to always perform a function, regardless of the API route called?

我正在创建 NetCore 2 API 并连接到 SQL 服务器数据库。无论路由是什么,都可以始终调用一个函数吗?我的例子:

对于每个调用,我都会传递必要的参数以连接到 header 中的 SQL 数据库。我将在此 api 中进行数百次调用,因此我真的不想为每次调用都重复此操作:

    [HttpGet]
    public async Task<IEnumerable<DEPARTMENT>> Get(
        [FromHeader] string Server, 
        [FromHeader] string Database, 
        [FromHeader] string Username, 
        [FromHeader] string Password, 
        [FromHeader] string Trusted)
    {
        util.SetConnectionString(Server, Database, Username, Password, Trusted);
        return await this.departmentDataProvider.GetDepartments();
    }

    [HttpGet("{DepartmentId}")]
    public async Task<IEnumerable<DEPARTMENT>> Get(
        string DepartmentId,
        [FromHeader] string Server, 
        [FromHeader] string Database, 
        [FromHeader] string Username, 
        [FromHeader] string Password, 
        [FromHeader] string Trusted)
    {
        util.SetConnectionString(Server, Database, Username, Password, Trusted);
        return await this.departmentDataProvider.GetDepartment(DepartmentId);
    }

我想创建一个只有 header 连接参数的祖先函数,以及设置连接字符串的调用。最终目标是这样的:

祖先:

    [HttpGet]
    public async Task<IEnumerable<?>> Get(
        [FromHeader] string Server,
        [FromHeader] string Database,
        [FromHeader] string Username,
        [FromHeader] string Password,
        [FromHeader] string Trusted)
    {
        util.SetConnectionString(Server, Database, Username, Password, Trusted);
    }

Children:

    [HttpGet]
    public async Task<IEnumerable<DEPARTMENT>> Get()
    {
        return await this.departmentDataProvider.GetDepartments();
    }

    [HttpGet("{DepartmentId}")]
    public async Task<IEnumerable<DEPARTMENT>> Get(string DepartmentId)
    {
        return await this.departmentDataProvider.GetDepartment(DepartmentId);
    }

编辑:

添加 Util.cs & DepartmentDataProvider.cs 以获取更多信息。

Util.cs

public static class util
{
    public static string ConnectionString { get; set; }

    public static void SetConnectionString(string Server, string Database, string UserName, string Password, string Trusted)
    {
        if (Trusted == "true")             
            ConnectionString = "Server=" + Server + ";Database=" + Database + ";Trusted_Connection=True;";
        else
            ConnectionString = "Server=" + Server + ";Database=" + Database + ";User ID= " + UserName + ";Password=" + Password + ";Trusted_Connection=False;";
    }

    public static string GetConnectionString()
    {
        return ConnectionString;
    }
}

DepartmentDataProvider.cs

public class DepartmentDataProvider : IDepartmentDataProvider
{
    public async Task<DEPARTMENT> GetDepartment(int DepartmentId)
    {
        string connString = util.GetConnectionString();

        using (var sqlConnection = new SqlConnection(util.GetConnectionString()))
        {
            await sqlConnection.OpenAsync();
            var dynamicParameters = new DynamicParameters();
            dynamicParameters.Add("@DepartmentID", DepartmentId);
            return await sqlConnection.QuerySingleOrDefaultAsync<DEPARTMENT>(
                "Select * From DEPARTMENT Where DEPARTMENT_ID = @DepartmentID",
                dynamicParameters,
                commandType: CommandType.Text);
        }
    }
}

创建一个 class 来封装连接字符串数据,任何相关的 object 将被注入其中(例如可能是 HttpContext):

public class ConnectingStringParmsFromHeaders
{
    public string Server { get; private set; }
    // other properties

    // ideally you wouldn't depend on ASP.NET Core constructs such as HttContext
    //   but I'm using it here for brevity
    public ConnectionStringPropertiesFromHeaders( HttpContext httpContext )
    {
        ReadPropertiesFromHeaders( httpContext.Request.Headers );
    }

    private void ReadPropertiesFromHeaders( IHeaderDictionary headers )
    {
        // do your header-reading thing here
    }

    public string BuildConnectionString()
    {
        // your Util.SetConnectionString(...) code here
        //   using local instance properties and not static properties
    }
}

接下来,register 这个 class 的生命周期为 Scoped(在同一个 HTTP 请求中重复使用单个 object):

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddScoped<ConnectionStringParmsFromHeaders>();
}

最后,将此类型的参数添加到控制器的构造函数中,并设置一个 属性 或字段以用于操作方法:

public class DepartmentsController : Controller
{
    private ConnectionStringParmsFromHeaders ConnStrParms { get; private set; }

    public DepartmentsController( ConnectionStringParmsFromHeaders connStrParms )
    {
        ConnStrParms = connStrParms;
    }

    public async Task<IActionResult> Get()
    {
        // for illustrative purposes
        var connStr = connStrParms.BuildConnectionString();

        // remainder of your action method's code
    }
}

请注意,您的 Util class 设置静态 属性 和 per-http-request header 数据是一个问题 b/c 可以有多个并发线程读取和写入相同的 属性 和不同的数据——您将不知道您是否使用了正确的数据!将连接字符串生成代码移动到此新配置 class,以便您可以在 per-request 基础上访问它,如上面的代码示例所示。

上面的代码可能不是 100% 准确,因为我现在无法对其进行测试,但它应该足以让你到达你需要去的地方。