使用eBay SDK添加商品兼容性时出现LookupAttribute相关报错
eBay API 添加配件兼容性信息报错排查
问题描述
我有一款用于库存管理并发布eBay拍卖商品的C# WinForms应用程序。尝试修改商品listings添加配件兼容性信息时,出现以下报错:
"No <Item.LookupAttributeArray.LookupAttribute> exists or <Item.LookupAttributeArray.LookupAttribute> is specified as an empty tag"
eBay API参考文档相关说明:
ConditionID(新增):ConditionID在沙箱环境的部分分类中受支持,自2010年5月起,在生产环境的大多数分类中生效。当GetCategoryFeatures显示商品主分类的ConditionEnabled为Enabled或Required时,应使用ConditionID替代AttributeSetArray、LookupAttributeArray或ItemSpecifics来指定商品状态。
相关代码
MainForm 代码
public partial class MainForm : Form { public List<string[]> CsvData { get; set; } = []; public string? SerialNumber { get; set; } public string? File { get; set; } public MainForm() { InitializeComponent(); } private void MainForm_Load(object sender, EventArgs e) { Logger.Logger.LogInfo("Starting Up..."); } private void TbSerial_TextChanged(object sender, EventArgs e) { SerialNumber = tbSerial.Text; } private void btnCSV_Click(object sender, EventArgs e) { var dialog = new OpenFileDialog(); dialog.ShowDialog(); File = dialog.FileName; CreateDataTable(); } private void CreateDataTable() { var dataTable = new DataTable(); dataTable.Columns.Add("Year"); dataTable.Columns.Add("Make"); dataTable.Columns.Add("Line"); dataTable.Columns.Add("Model"); if (File != null) { var streamReader = new StreamReader(File); while (!streamReader.EndOfStream) { var totalData = streamReader.ReadLine()?.Split(','); if (totalData is not { Length: > 0 }) continue; CsvData.Add(totalData); dataTable.Rows.Add(totalData[0], totalData[1], totalData[2], totalData[3]); } } dataGridView1.DataSource = dataTable; } private void BtnEbayUpdate_Click(object sender, EventArgs e) { if (CsvData.Count <= 0) Logger.Logger.LogError("You must upload a fitment file first!!"); if (string.IsNullOrEmpty(SerialNumber)) Logger.Logger.LogError("You must input a serial number!!"); var itemCompatibilityTypeCollection = new ItemCompatibilityTypeCollection(); for (var i = 0; i < CsvData.Count; i++) { var line = CsvData[i]; if (i == 0) { continue; } var year = line[0]; var make = line[1]; var model = line[3]; var fitmentYear = new NameValueListType { Name = "Year", Value = [year] }; var fitmentMake = new NameValueListType { Name = "Make", Value = [make] }; var fitmentModel = new NameValueListType { Name = "Model", Value = [model] }; NameValueListTypeCollection fitmentData = [ fitmentYear, fitmentMake, fitmentModel ]; var itemCompatibilityType = new ItemCompatibilityType { NameValueList = fitmentData }; itemCompatibilityTypeCollection.Add(itemCompatibilityType); } var db = new GWDB.GWDB(); var invRecord = db.Inventories .Where(s => s.SerialNumber == SerialNumber && s.Status == "Auction") .Select(x => x) .FirstOrDefault(); if (invRecord == null) return; var eBayId = invRecord.eBayID; var auction = eBay.eBay.GetItemRequest(eBayId); if (auction.Item == null) return; auction.Item.ItemCompatibilityList = new ItemCompatibilityListType { Compatibility = itemCompatibilityTypeCollection }; auction.Item.ConditionID = 4000; var response = eBay.eBay.ReviseItem(auction.Item); if (response.Ack != AckCodeType.Success) return; Logger.Logger.LogInfo(@$"Auction {eBayId} has been updated with fitment info."); } }
eBay 工具类代码
public class eBay { public static eBayAPIInterfaceService eBayServiceCall(string callName) { var endpoint = "https://api.ebay.com/wsapi"; const string siteId = "100"; var appId = AppSettingsHelper.AppID; // use your app ID var devId = AppSettingsHelper.DevID; // use your dev ID var certId = AppSettingsHelper.CertID; // use your cert ID const string version = "965"; // Build the request URL var requestURL = endpoint + "?callname=" + callName + "&siteid=" + siteId + "&appid=" + appId + "&version=" + version + "&routing=default"; var service = new eBayAPIInterfaceService(); // Assign the request URL to the service locator. service.Url = requestURL; // Set credentials service.RequesterCredentials = new CustomSecurityHeaderType { eBayAuthToken = AppSettingsHelper.Token, // use your token Credentials = new UserIdPasswordType { AppId = appId, DevId = devId, AuthCert = certId } }; return service; } /// <summary> /// Verify whether item is ready to be added to eBay. /// </summary> public static string AddEbayItem(ItemType item) { var service = eBayServiceCall("VerifyAddItem"); var request = new VerifyAddItemRequestType { Version = "949", ErrorLanguage = "en_US", WarningLevel = WarningLevelCodeType.High, Item = item }; try { var response = service.VerifyAddItem(request); if (response != null) { switch (response.Ack) { case AckCodeType.Warning: { for (var i = 0; i < response.Errors.Count; i++) { Logger.Logger.LogWarning(response.Errors[i].LongMessage); i++; } break; } case AckCodeType.Failure: { for (var i = 0; i < response.Errors.Count; i++) { Logger.Logger.LogError(response.Errors[i].LongMessage); i++; } break; } case AckCodeType.Success: { Logger.Logger.LogInfo((response.Message)); break; } case AckCodeType.PartialFailure: break; case AckCodeType.CustomCode: break; default: throw new ArgumentOutOfRangeException(); } // If item is verified, the item will be added. if (response.ItemID != "0") return null; } var ebayID = AddItemRequest(item); return ebayID; } catch (Exception ex) { Logger.Logger.LogError(@"Exception:"); Logger.Logger.LogError($@"{ex.Message}"); return null; } } /// <summary> /// Add item to eBay. Once verified. /// </summary> /// <param name="item">Accepts ItemType object from VerifyAddItem method.</param> public static string AddItemRequest(ItemType item) { try { var service = eBayServiceCall("AddItem"); var request = new AddItemRequestType { Version = "949", ErrorLanguage = "en_US", WarningLevel = WarningLevelCodeType.High, Item = item }; var response = service.AddItem(request); Logger.Logger.LogInfo($@"ItemID: {response.ItemID}"); #if DEBUG //Process.Start($@"http://ebay.com/itm/{response.ItemID}"); #else //Process.Start($@"http://ebay.com/itm/{response.ItemID}"); #endif return response.ItemID; } catch (Exception ex) { Logger.Logger.LogError(@"Exception:"); Logger.Logger.LogError($@"{ex.Message}"); return null; } } /// <summary> /// Retrieve item details. /// </summary> /// <param name="ItemID">eBay Item ID</param> public static GetItemResponseType GetItemRequest(string ItemID) { var service = eBayServiceCall("GetItem"); var request = new GetItemRequestType { Version = "949", ItemID = ItemID }; var response = service.GetItem(request); return response; } public static ReviseItemResponseType ReviseItem(ItemType item) { var service = eBayServiceCall("ReviseItem"); var request = new ReviseItemRequestType { Version = "949", Item = item }; var response = service.ReviseItem(request); return response; } public static bool EndEbayItem(string itemID) { try { var status = false; var service = eBayServiceCall("EndItem"); var request = new EndItemRequestType { Version = "949", ErrorLanguage = "en_US", WarningLevel = WarningLevelCodeType.High, EndingReason = EndReasonCodeType.NotAvailable, ItemID = itemID }; var response = service.EndItem(request); if (response.Ack == AckCodeType.Success) status = true; Logger.Logger.LogInfo($@"Auction ID {itemID} ended: {response.Ack}"); return status; } catch (Exception ex) { Logger.Logger.LogError(@"Exception:"); Logger.Logger.LogError($@"{ex.Message}"); return false; } } }
问题原因与修复方案
核心原因
调用ReviseItem时,从GetItem返回的Item对象中保留了旧的LookupAttributeArray空值或无效数据,而当前商品分类要求用ConditionID替代该字段,导致API校验失败;同时API请求版本不统一(工具类用965,修改请求用949),也可能引发字段处理逻辑冲突。
修复步骤
- 清空旧属性数组
在设置ConditionID和兼容性信息后,显式清空Item对象中的LookupAttributeArray和AttributeSetArray字段,避免旧数据干扰:
auction.Item.ItemCompatibilityList = new ItemCompatibilityListType { Compatibility = itemCompatibilityTypeCollection }; auction.Item.ConditionID = 4000; // 显式清空旧的属性数组,解决API校验报错 auction.Item.LookupAttributeArray = null; auction.Item.AttributeSetArray = null; var response = eBay.eBay.ReviseItem(auction.Item);
- 统一API版本号
修改ReviseItem方法中的版本号,和eBayServiceCall保持一致:
public static ReviseItemResponseType ReviseItem(ItemType item) { var service = eBayServiceCall("ReviseItem"); var request = new ReviseItemRequestType { Version = "965", // 改为与工具类一致的版本号 Item = item }; var response = service.ReviseItem(request); return response; }
- 额外检查项
- 调用
GetCategoryFeatures接口确认当前商品分类的ConditionEnabled状态,确保ConditionID的使用符合分类要求; - 验证CSV数据读取逻辑,确保兼容性信息(Year/Make/Model)无空值,避免生成无效的
NameValueList。
内容的提问来源于stack exchange,提问作者Drew Jackson
相关产品推荐
相关产品推荐

