diff --git a/samples/Common/ProductUtilities.cs b/samples/Common/ProductUtilities.cs index 0635532ca..5883d3cd5 100644 --- a/samples/Common/ProductUtilities.cs +++ b/samples/Common/ProductUtilities.cs @@ -19,7 +19,7 @@ public static List GetNewProducts(int num) var product = new Product { ProductID = i, - Cost = 100, + Cost = 100 * i, Name = "test" }; products.Add(product); diff --git a/samples/GlobalSuppressions.cs b/samples/GlobalSuppressions.cs index 7f1a8bbb4..12f1747de 100644 --- a/samples/GlobalSuppressions.cs +++ b/samples/GlobalSuppressions.cs @@ -20,4 +20,5 @@ [assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Samples.OutputBindingSamples.AddProductsCollector.Run(Microsoft.AspNetCore.Http.HttpRequest,Microsoft.Azure.WebJobs.ICollector{Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common.Product})~Microsoft.AspNetCore.Mvc.IActionResult")] [assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Samples.OutputBindingSamples.TimerTriggerProducts.Run(Microsoft.Azure.WebJobs.TimerInfo,Microsoft.Extensions.Logging.ILogger,Microsoft.Azure.WebJobs.ICollector{Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common.Product})")] [assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Samples.InputBindingSamples.GetProducts.Run(Microsoft.AspNetCore.Http.HttpRequest,System.Collections.Generic.IEnumerable{Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common.Product})~Microsoft.AspNetCore.Mvc.IActionResult")] -[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Samples.InputBindingSamples.GetProductNamesView.Run(Microsoft.AspNetCore.Http.HttpRequest,System.Collections.Generic.IEnumerable{Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common.ProductName})~Microsoft.AspNetCore.Mvc.IActionResult")] \ No newline at end of file +[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Samples.InputBindingSamples.GetProductNamesView.Run(Microsoft.AspNetCore.Http.HttpRequest,System.Collections.Generic.IEnumerable{Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common.ProductName})~Microsoft.AspNetCore.Mvc.IActionResult")] +[assembly: SuppressMessage("Style", "IDE0060:Remove unused parameter", Justification = "Unused parameter is required by functions binding", Scope = "member", Target = "~M:Microsoft.Azure.WebJobs.Extensions.Sql.Samples.InputBindingSamples.GetProductsStoredProcedureFromAppSetting.Run(Microsoft.AspNetCore.Http.HttpRequest,System.Collections.Generic.IEnumerable{Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common.Product})~Microsoft.AspNetCore.Mvc.IActionResult")] \ No newline at end of file diff --git a/samples/InputBindingSamples/GetProductsStoreProcedureFromAppSetting.cs b/samples/InputBindingSamples/GetProductsStoreProcedureFromAppSetting.cs new file mode 100644 index 000000000..624e70390 --- /dev/null +++ b/samples/InputBindingSamples/GetProductsStoreProcedureFromAppSetting.cs @@ -0,0 +1,31 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System.Collections.Generic; +using Microsoft.AspNetCore.Http; +using Microsoft.AspNetCore.Mvc; +using Microsoft.Azure.WebJobs.Extensions.Http; +using Microsoft.Azure.WebJobs.Extensions.Sql.Samples.Common; + +namespace Microsoft.Azure.WebJobs.Extensions.Sql.Samples.InputBindingSamples +{ + /// + /// This shows an example of a SQL Input binding that uses a stored procedure + /// from an app setting value to query for Products with a specific cost that is also defined as an app setting value. + /// + public static class GetProductsStoredProcedureFromAppSetting + { + [FunctionName("GetProductsStoredProcedureFromAppSetting")] + public static IActionResult Run( + [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = "getproductsbycost")] + HttpRequest req, + [Sql("%Sp_SelectCost%", + CommandType = System.Data.CommandType.StoredProcedure, + Parameters = "@Cost=%ProductCost%", + ConnectionStringSetting = "SqlConnectionString")] + IEnumerable products) + { + return new OkObjectResult(products); + } + } +} \ No newline at end of file diff --git a/samples/local.settings.json b/samples/local.settings.json index e3a7a2e09..2ee8fdfec 100644 --- a/samples/local.settings.json +++ b/samples/local.settings.json @@ -3,6 +3,8 @@ "Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true", "FUNCTIONS_WORKER_RUNTIME": "dotnet", - "SqlConnectionString": "" + "SqlConnectionString": "", + "Sp_SelectCost": "SelectProductsCost", + "ProductCost": 100 } } \ No newline at end of file diff --git a/src/SqlAttribute.cs b/src/SqlAttribute.cs index 9175eb475..0e0c19745 100644 --- a/src/SqlAttribute.cs +++ b/src/SqlAttribute.cs @@ -40,6 +40,7 @@ public SqlAttribute(string commandText) /// For an input binding, either a SQL query or stored procedure that will be run in the database referred to in the ConnectionString. /// For an output binding, the table name. /// + [AutoResolve] public string CommandText { get; } /// diff --git a/test/Integration/SqlInputBindingIntegrationTests.cs b/test/Integration/SqlInputBindingIntegrationTests.cs index 1f53b3c0f..f8ad129ce 100644 --- a/test/Integration/SqlInputBindingIntegrationTests.cs +++ b/test/Integration/SqlInputBindingIntegrationTests.cs @@ -98,6 +98,26 @@ public async void GetProductsNameEmptyTest(int n, int cost) Assert.Equal(expectedResponse, actualResponse, StringComparer.OrdinalIgnoreCase); } + [Fact] + public async void GetProductsByCostTest() + { + this.StartFunctionHost(nameof(GetProductsStoredProcedureFromAppSetting)); + + // Generate T-SQL to insert n rows of data with cost + Product[] products = GetProducts(3, 100); + this.InsertProducts(products); + Product[] productsWithCost100 = GetProducts(1, 100); + + // Run the function + HttpResponseMessage response = await this.SendInputRequest("getproductsbycost"); + + // Verify result + string expectedResponse = JsonConvert.SerializeObject(productsWithCost100); + string actualResponse = await response.Content.ReadAsStringAsync(); + + Assert.Equal(expectedResponse, actualResponse, StringComparer.OrdinalIgnoreCase); + } + [Fact] public async void GetProductNamesViewTest() { @@ -132,6 +152,21 @@ private static Product[] GetProductsWithSameCost(int n, int cost) return result; } + private static Product[] GetProducts(int n, int cost) + { + var result = new Product[n]; + for (int i = 1; i <= n; i++) + { + result[i - 1] = new Product + { + ProductID = i, + Name = "test", + Cost = cost * i + }; + } + return result; + } + private static Product[] GetProductsWithSameCostAndName(int n, int cost, string name, int offset = 0) { var result = new Product[n];