c# - 如何将整个 http URL 传递给 asp.net API 中的存储过程?
问题描述
我的任务是创建一个 asp.net API,其中:
- 用户将 XML 发布到我的 APi 端点
- API 将整个 XML 直接传递给存储过程
- 存储过程将一些 XML 返回给用户的 API
对 api 的示例调用:
https://localhost:44308/api/OrderProcessing?<?xml version="1.0"encoding="utf-8"?><Param1>abc123</Param1><Param2>5</Param2><Param3>123456</Param3>etc.. etc
我发现了许多从 asp.net 调用过程的示例,所有这些示例都显示 XML 节点被解析为参数以传递给存储过程:
usp_myproc @param1 =abc123, @param2 =5, @param3 =123456 etc.
我不知道如何将 xml 作为单个字符串传递,如下所示 EG
usp_myproc @param1 =xml version="1.0"encoding="utf-8"?><Param1>abc123</Param1><Param2>5</Param2><Param3>123456</Param3>etc.. etc
到目前为止,我有以下代码,当然只是传递第一个参数,例如。 usp_myproc @param1
不是整个字符串
namespace OrderProcessingApp.Controllers
{
public class OrderProcessingController : ApiController
{
[HttpGet]
public IHttpActionResult StockOrder(string param1)
{
StockFinderEntities sd = new StockFinderEntities();
var results = sd.fn_ProcessOrder(param1).ToList();
}
}
}
非常感激地收到任何帮助
解决方案
这里有很多要解压的内容,并且缺少一些信息,另请参阅我对您问题的评论。尽管您的问题中有可回答的部分,但情况远非最佳。
如果我明白这一点,你想要这个:
- 接受 GET 请求的 API 端点,其查询字符串完全由 XML 字符串组成。
- 在此操作方法中,将 XML 字符串传递给 SQL 用户定义函数。
- 这个函数解析 XML,做它的事情,并返回零个或多个记录。
- 然后将这些记录作为列表返回给调用者。
因此,首先,您必须阅读该 XML。您的查询字符串似乎没有键(它直接以 开头?<xml...>
)。这是故意的,还是创造这个问题的疏忽?您确定要从查询字符串中读取 XML,还是可以更改此设计?
如果您可以更改它,惯用的方法是使用查询字符串参数,然后将其绑定到您的操作方法参数:
// GET .../StockOrder?param1=42¶m2=Foo¶m3=Bar
public IHttpActionResult StockOrder(string param1, string param2, string param3) { ... }
假设您真的想将原始查询字符串读取为 XML,而不是单个参数:
// GET .../StockOrder?xmlString=<xml...>
public IHttpActionResult StockOrder(string xmlString) { ... }
然后你根本不需要参数:
// GET .../StockOrder?<xml...>
public IHttpActionResult StockOrder()
{
string xmlString = this.Request.RequestUri.Uri.Query.Value;
...
}
所以现在您有了 XML 字符串,您将把它传递给数据库中的用户定义函数。虽然 Entity Framework 会将其打包在 SQL 参数中,但至少您可以在此处免受 SQL 注入:
// GET .../StockOrder?<xml...>
public IHttpActionResult StockOrder()
{
string xmlString = this.Request.RequestUri.Uri.Query.Value;
if (xmlString?.Length > 0)
{
// Remove the question mark from the start
xmlString = xmlString.Substring(1);
}
var results = sd.fn_ProcessOrder(xmlString).ToList();
...
}
但这仍然远非最佳!调用者可以传递无效的 XML,这只能由 SQL Server 检测到,这在过程中为时已晚。或者更糟糕的是,它可能是 SQL Server 会阻塞的特制 XML(如 XML 炸弹),或者更糟糕的是(执行 XML 中包含的任意代码)。所以我不喜欢将用户输入以 XML 的形式直接发送到 SQL Server,不。
最佳方式如下所示:
public class GetStockOrderModel
{
[Required]
public string Param1 { get; set; }
[Required]
public string Param2 { get; set; }
[Required]
public string Param3 { get; set; }
}
// GET .../StockOrder?param1=42¶m2=Foo¶m3=Bar
public IHttpActionResult StockOrder([FromUri] GetStockOrderModel model)
{
if (!ModelState.IsValid)
{
// ...
}
var records = sd.fn_ProcessOrder(model.Param1, model.Param2, model.Param3).ToList();
var models = records.Select(o => new
{
FieldToReturn = o.Field1,
OtherField = o.Field2,
// ...
}).ToList();
return Ok(models);
}
在这里,您有一个模型要绑定并执行验证,数据库函数被更改为接受实际参数而不是 XML,并返回一个与数据库分离的模型。
现在如果你说你不能改变这个函数,因为其他应用程序调用它,你可能仍然可以。您调用的函数由两部分组成:一部分从 XML 中读取参数,另一部分使用这些参数执行查询。
因此,您保留原始函数,并在提取参数后让它调用新函数。然后,您还可以使用代码中的参数调用该新函数。
实际上,您不想将用户 XML 传递给您的数据库服务器。当然,您会说,它只会由受信任的各方调用。但是这些派对上的每个人都值得信任吗?他们从来没有犯过错误吗?
因此,如果您真的不想更改端点或函数的任何内容,并且您将使用第四个(或第二个)代码块,至少读取控制器中的 XML 字符串,解析它,提取参数,验证它们,并从安全的模板字符串或类似的东西重建 XML。
因为对于 ASP.NET,该 XML 被视为普通的旧字符串,因此您没有任何验证或安全措施。