ASP.NET调用Business Central OData服务时请求URI无效的解决方法
问题场景
要在ASP.NET项目中调用Business Central的OData服务,有效OData URI为:http://windowsbc:7048/BC230/ODataV4/Company('Copia%20Cronus')/Power_BI_Vendor_List,通过Postman请求可正常返回如下格式的数据:
{ "@odata.context": "http://windowsbc:7048/BC230/ODataV4/$metadata#Company('Copia%20Cronus')/Power_BI_Vendor_List", "value": [ { "Vendor_No": "01254796", "Vendor_Name": "Progressive Home Furnishings", "Balance_Due": 169430.59, "Posting_Date": "2024-12-31", "Applied_Vend_Ledger_Entry_No": 0, "Amount": 169430.59, "Amount_LCY": 170260.8, "Transaction_No": 99, "Entry_No": 71, "Remaining_Pmt_Disc_Possible": 0 } ] }
但编写的C#代码运行时抛出错误:
var credentials = new NetworkCredential("johon", "myPassword"); var settings = new ODataClientSettings("http://windowsbc:7048/BC230/ODataV4/Company('Copia%20Cronus')/Power_BI_Vendor_List/", credentials); var client = new ODataClient(settings); var Vendor = await client.For("Power_BI_Vendor_List").FindEntriesAsync();
WebRequestException:请求URI无效。由于段'Power_BI_Vendor_List'指向一个集合,它必须是请求URI中的最后一段,或者后续需绑定可关联的函数/动作,否则所有中间段必须指向单个资源。
解决方案
问题根源是重复指定了集合路径:你把完整的集合URI传给ODataClientSettings后,又通过For("Power_BI_Vendor_List")再次追加集合名称,导致最终请求的URI变成了http://windowsbc:7048/BC230/ODataV4/Company('Copia%20Cronus')/Power_BI_Vendor_List/Power_BI_Vendor_List,违反了OData规范。
以下是三种修正方案:
方案一:调整基础URI到Company层级
将ODataClientSettings的基础URI设置到Company节点,再通过For方法指定目标集合:
var credentials = new NetworkCredential("johon", "myPassword"); // 基础URI仅到Company节点 var settings = new ODataClientSettings("http://windowsbc:7048/BC230/ODataV4/Company('Copia%20Cronus')/", credentials); var client = new ODataClient(settings); // 直接指定要访问的集合名称 var vendors = await client.For("Power_BI_Vendor_List").FindEntriesAsync();
方案二:从服务根路径链式定位集合
如果希望基础URI为OData服务根路径,可通过链式调用逐步定位到目标集合:
var credentials = new NetworkCredential("johon", "myPassword"); var settings = new ODataClientSettings("http://windowsbc:7048/BC230/ODataV4/", credentials); var client = new ODataClient(settings); // 先定位到指定Company,再访问对应集合 var vendors = await client.For("Company").Key("'Copia%20Cronus'").For("Power_BI_Vendor_List").FindEntriesAsync();
方案三:直接请求完整URI(临时验证用)
若不想调整层级,可直接通过GetAsync方法请求完整的集合URI:
var credentials = new NetworkCredential("johon", "myPassword"); var settings = new ODataClientSettings("http://windowsbc:7048/BC230/ODataV4/", credentials); var client = new ODataClient(settings); var response = await client.GetAsync("Company('Copia%20Cronus')/Power_BI_Vendor_List"); var vendors = response.AsEnumerable();
推荐使用方案一或方案二,它们更符合ODataClient的设计逻辑,也便于后续扩展其他OData操作。
内容的提问来源于stack exchange,提问作者user2231301

