【问题标题】:Querying eBay API with WCF使用 WCF 查询 eBay API
【发布时间】:2025-12-12 19:45:02
【问题描述】:

我正在尝试在我的 ASP.NET Core 2.0 网站中使用 eBay API。 eBay 的 .NET SDK 不适用于 .NET Core,所以我通过 WCF 添加了该服务。我是 WCF 的新手,但我无法让这个客户工作。无论我尝试什么,我都会收到此错误:

抛出异常:System.Private.CoreLib.dll 中的“System.ServiceModel.FaultException”

com.ebay.app.pres.service.hosting.WebServiceDisabledException:Web 服务 eBayAPI 未正确配置或未找到并被禁用。

我特别想查询GetItem。我的凭据确实有效,我可以使用 SoapUI 进行确认。

这是我尝试使用的代码示例。我错过了什么?我该如何完成这项工作?

var rawEbayConfig = Configuration.GetSection("Ebay");
var ebayConfig = rawEbayConfig.Get<EbayConfig>();

// https://api.sandbox.ebay.com/wsapi
var ebayEndpoint = new EndpointAddress(ebayConfig.ApiBaseUrl);

var ebayCreds = new CustomSecurityHeaderType
{
    Credentials = new UserIdPasswordType
    {
        AppId = ebayConfig.AppId,
        DevId = ebayConfig.DevId,
        AuthCert = ebayConfig.CertId
    },
    eBayAuthToken = ebayConfig.Token
};

var ebayClient = new eBayAPIInterfaceClient(
    eBayAPIInterfaceClient.EndpointConfiguration.eBayAPI, ebayEndpoint);

var reqType = new GetItemRequestType
{
    ItemID = "validItemId",
    Version = "809"
};

var itemResp = await ebayClient.GetItemAsync(_header, reqType); // error thrown here

// do more stuff

【问题讨论】:

  • WCF 是一门职业专长,你会花太多时间去弄明白。如果可以异步,为什么不直接使用 HTTP 和 HttpClient,如果要同步,为什么不使用 HttpWebRequest
  • 您确定 ebayConfig.ApiBaseUrl 中的内容是正确的吗? ebaydts.com/eBayKBDetails?KBid=861
  • @Crowcoder 哦,好的。我以前从未使用过 XML API,这就是为什么我试图找到一个无需解析的解决方案。不过,如果有必要,我可以这样做。
  • @rene 是的,在我的示例中,我拥有的 URL 是该行上方的注释:https://api.sandbox.ebay.com/wsapi。如果我阅读正确,这就是你的链接所说的使用。
  • 我不知道...我只是在阅读规范,因为您的代码已经设法与该服务器建立连接,否则您将不会遇到包含错误的错误异常易趣服务器....

标签: c# wcf ebay-api


【解决方案1】:

好吧,我设法弄明白了。让它工作的方法有点笨拙,可能有更好的方法,但我想不出来。系好安全带。

WCF 文档

在我开始之前,Microsoft 有很多关于 WCF here 的文档。如果您像我一样不熟悉 WCF,请查看它们。这是使用客户端,而不是服务器。我们只是在与 eBay 的服务器通信,而不是运行我们自己的服务器。

第 0 步:确保构建解决方案

在下一步之前,请确保您的解决方案已构建。除非成功构建,否则您无法添加连接的服务。

第 1 步:添加连接服务

第一步是将服务引用添加到项目并从 eBay 的服务器生成模型。 eBay 为此提供了 WSDL 文件。我们特别想要this one。您可以使用 Visual Studio 中的 Add Connected Service 工具来执行此操作。您必须选择一个 ASP.NET 项目,然后转到Tools &gt; Add Connected Service。使用Microsoft WCF Web Service Reference Provider 的选项。在URI 框中输入该.wsdl URL,单击Go,将命名空间更改为您想要的任何名称,然后单击Finish。命名空间纯粹是偏好,我做了我的EbayService。所有其他设置都可以保留为默认值。会弹出一个带有一堆日志记录的框,您可以忽略它并等待它完成。会有大量黄色警告,这些也可以忽略。

(注意:您也可以使用svcutility 来生成模型,而不是使用 Visual Studio 的 GUI,但我不会对此进行介绍。)

第 2 步:编辑服务参考文件

现在,Web 项目在解决方案资源管理器中的顶部附近应该有一个名为 Connected Services 的部分。里面应该有一个文件夹,命名为您之前提供的任何命名空间。内部将是一个名为Reference.cs 的文件,其中包含 eBay 服务的所有解析信息。这个文件很大,我的有将近 122k 行。我们需要在这里做几件事。

我们需要做几个查找/替换操作。为此,我们必须查找/替换两个字符串。 在替换窗口中打开正则表达式,然后将, Order=\d{1,3} 替换为空。这捕获了Order 是属性上的多个参数之一的情况。然后做同样的事情,但替换Order=\d{1,3}。这样做会破坏我遇到的其中一个课程,因此请找到课程ReviseInventoryStatusRequestType。它有一个名为any1Field 的字段和一个名为Any1 的属性。删除这两个。

请记住,如果您从服务器重新生成服务,则需要重做这些步骤,因为该过程会覆盖 Reference.cs

(为什么要这样做?eBay WSDL 文件指定了元素从 API 返回时的顺序,但它们甚至不接近正确。因此,几乎没有响应实际上会正确解析。我们需要删除订单规范并让程序通过名称来处理解析。)

第 3 步:编写客户端包装器

可以直接使用此服务,但这样做会真的变得一团糟。因此,我围绕客户端编写了一个包装器,大大简化了这一点。注释代码如下,DI 将在下一步出现,所以不用担心。您需要为要使用的每个 API 端点添加一个函数。

public class EbayClient
{
    // Don't do this, use a proper method of storing app secrets.
    // I have it this way for simplicity in this example.
    const string AppId = "MyAppId";
    const string DevId = "MyDevId";
    const string CertId = "MyCertId";
    const string AuthToken = "MyAuthToken";

    // This is the version of the API that your WSDL file is from. As of this answer
    // the latest version is 1039. All calls need this passed as a parameter.
    const string Version = "1039";

    // This is the base URL for the API.
    // Sandbox: https://api.sandbox.ebay.com/wsapi
    // Production: https://api.ebay.com/wsapi
    const string BaseApiUrl = "https://api.sandbox.ebay.com/wsapi";

    // This is the actual client from the service we just imported. It's being injected
    // here via the built-in DI in ASP.NET Core.
    readonly eBayAPIInterfaceClient _ebay;

    // All of the functions in this class need these credentials passed, so declare it in
    // the constructor to make things easier.
    readonly CustomSecurityHeaderType _creds;

    public EbayClient(eBayAPIInterfaceClient ebay)
    {
        _ebay = ebay;

        _creds = new CustomSecurityHeaderType
        {
            Credentials = new UserIdPasswordType
            {
                AppId = AppId,
                DevId = DevId,
                AuthCert = CertId
            },
            eBayAuthToken = AuthToken
        };
    }

    // This is a wrapper around the API GetItem call.
    public async Task<GetItemResponse> GetItemAsync(string itemId)
    {
        // All of the API requests and responses use their own type of object.
        // This one, naturally, uses GetItemRequest and GetItemResponse.
        var reqType = new GetItemRequest
        {
            GetItemRequest1 = new GetItemRequestType
            {
                ItemID = itemId,
                Version = Version
            },
            RequesterCredentials = _creds
        };

        // The service isn't smart enough to know the endpoint URLs itself, so
        // we have to set it explicitly.
        var addr = new EndpointAddress($"{ApiBaseUrl}?callname=GetItem");

        // This creates a channel from the built-in client's ChannelFactory.
        // See the WCF docs for explanation of this step.
        var ch = _ebay.ChannelFactory.CreateChannel(addr);

        // Actually call the API now
        var itemResp = await ch.GetItemAsync(reqType);

        // Check that the call was a success
        if (itemResp.GetItemResponse1.Ack == AckCodeType.Success)
        {
            // The call succeeded, so handle the data however you want. I created
            // a class to simplify the API class because the API class is massive.
            return new EbayItem
            {
                ItemId = itemResp.GetItemResponse1.Item.ItemID,
                Price = Convert.ToDecimal(itemResp.GetItemResponse1.Item.BuyItNowPrice.Value),
                QuantityAvailable = itemResp.GetItemResponse1.Item.QuantityAvailable
            };
        }

        // Handle an API error however you want. Throw an
        // exception or return null, whatever works for you.
        return null;
    }
}

第四步:设置依赖注入

我使用built-in ASP.NET Core DI,所以需要设置。基本的 eBay 客户端类可以是单例,但你的包装类应该是作用域的。

Startup.cs/ConfigureServices():

// This is the base client
services.AddSingleton(new eBayAPIInterfaceClient(eBayAPIInterfaceClient.EndpointConfiguration.eBayAPI));

// This is our wrapper
services.AddScoped<EbayClient>();

第 5 步:在代码中调用包装器

您的控制器可能如下所示:

public class ProductsIdExternalController : Controller
{
    // This is the wrapper class
    readonly EbayClient _ebay;

    public ProductsIdExternalController(EbayClient ebay)
    {
        _ebay = ebay;
    }

    [HttpGet]
    public async Task<IActionResult> Index(string itemId)
    {
        var item = await _ebay.GetItemAsync(itemId);

        // Use the item however you want.
        // Make sure to handle errors in case the item ID doesn't exist.
    }
}

【讨论】:

  • 如果还显示一个帖子请求,那将是一个黄金......