首页 > 解决方案 > 如何将整个 http URL 传递给 asp.net API 中的存储过程?

问题描述

我的任务是创建一个 asp.net 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();
            }
        }
    }

非常感激地收到任何帮助

标签: c#asp.netxmlstored-proceduresparameter-passing

解决方案


这里有很多要解压的内容,并且缺少一些信息,另请参阅我对您问题的评论。尽管您的问题中有可回答的部分,但情况远非最佳。

如果我明白这一点,你想要这个:

  • 接受 GET 请求的 API 端点,其查询字符串完全由 XML 字符串组成。
  • 在此操作方法中,将 XML 字符串传递给 SQL 用户定义函数。
  • 这个函数解析 XML,做它的事情,并返回零个或多个记录。
  • 然后将这些记录作为列表返回给调用者。

因此,首先,您必须阅读该 XML。您的查询字符串似乎没有键(它直接以 开头?<xml...>)。这是故意的,还是创造这个问题的疏忽?您确定要从查询字符串中读取 XML,还是可以更改此设计?

如果您可以更改它,惯用的方法是使用查询字符串参数,然后将其绑定到您的操作方法参数:

// GET .../StockOrder?param1=42&param2=Foo&param3=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&param2=Foo&param3=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 被视为普通的旧字符串,因此您没有任何验证或安全措施。


推荐阅读