gpt4 book ai didi

c# - 是否有使用 basicHttpBinding 扩展 WCF 服务以允许 REST 服务与 JSON 通信的好方法?

转载 作者:太空狗 更新时间:2023-10-29 23:17:20 24 4
gpt4 key购买 nike

我们有一个在 VS2010 中构建并运行的 Web 服务。

一些运营合约如下所示:

    [OperationContract]
ITicket Login(string userName, byte[] passwordHash, string softwareVersion);

即他们的展台有复杂的参数和复杂的返回类型,甚至有多个返回。

我们最近启动了一个外包 iPhone 项目,并让他们使用此服务与我们的服务器进行通信。从我从他们那里学到的东西,我明白这不是与 iPhone 通信的好习惯(例如,缺乏使用 WSDL 的好方法)。因此,我开始考虑将服务公开为与 JSON 通信的 REST 服务的可能性。

我添加了一个新端点,使用 webHttpBinding,像这样装饰合约:

    [OperationContract]
[WebGet(UriTemplate = "/login?username={userName}&password={password}&softwareVersion={softwareVersion}", ResponseFormat=WebMessageFormat.Json)]
ITicket Login(string userName, string password, string softwareVersion);

此方法现在按预期工作。

然后我尝试像这样装饰另一个方法:

    [OperationContract]
[WebGet(UriTemplate = "/GetMetaData?ticket={ticket}",RequestFormat=WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
IMetaData GetMetaData(ITicket ticket);

当我现在尝试访问它时,我收到以下错误:

Server Error in '/Jetas5MobileService' Application. Operation 'GetMetaData' in contract 'IJetas5MobileService2' has a query variable named 'ticket' of type 'Jetas.MobileService.DataContracts.ITicket', but type 'Jetas.MobileService.DataContracts.ITicket' is not convertible by 'QueryStringConverter'. Variables for UriTemplate query values must have types that can be converted by 'QueryStringConverter'.

我已经设法构建了一个 OperationContract,它只接受一个字符串作为参数,然后在后端使用 DataContractJsonSerializer 进行精简解析,但这感觉更像是一个丑陋的 hack。

有什么办法可以更好地解决这个问题吗?我是 WCF 和 REST 的初学者,所以请不要害怕向我指出可能存在的任何初学者教程。我试图搜索它们,但大量的资源使得很难找到好的。

最佳答案

From what I have learnt from them I understood that this is not a good practice for communicating to the iPhone (lack of good ways to consume the WSDL for example).

最大的问题不是缺乏好的“工具”,而是缺乏对 WSDL 是什么以及 Web 服务如何工作的理解。所有这些为开发人员生成服务 stub 的工具导致开发人员不了解底层是什么。它适用于所有魔法都为您完成的基本场景,但一旦开发人员必须跟踪任何问题或使用其他功能扩展“工具”,他们就会遇到大问题(并且通常会导致糟糕的解决方案)。老实说SW开发不是关于基本场景的。

REST 对开发人员来说是一个巨大的挑战,因为它不提供任何“神奇”的工具。 REST 是关于 HTTP 协议(protocol)的正确使用,它充分利用了现有的 HTTP 基础设施。如果不了解 HTTP 协议(protocol)的基础知识,您将无法创建良好的 REST 服务。那是你应该开始的地方。

下面是一些不正确用法的例子:

[OperationContract]
[WebGet(UriTemplate = "/login?username={userName}&password={password}&softwareVersion={softwareVersion}", ResponseFormat=WebMessageFormat.Json)]
ITicket Login(string userName, string password, string softwareVersion);

Login 方法显然是执行某些操作的东西 - 我猜它会创建票证。它绝对不适合 GET HTTP 请求。这绝对应该是对登录资源的 POST 请求,为每次调用返回新的 ITicket 表示。为什么?因为 GET 请求应该是安全和幂等的。

  • 安全:请求不应引起任何副作用 = 它不应对资源进行任何更改,但在您的情况下,它很可能会创建新资源。
  • 幂等性:这个对于示例来说不是那么重要,因为您已经违反了安全规则,但这意味着对资源的请求应该是可重复的。这意味着具有相同用户名、密码和版本的第一个请求可以创建新资源,但是当再次执行请求时,它不应该创建新资源,而是返回已经创建的资源。当资源在服务器上持久化/维护时,这更有意义。

因为 HTTP GET 请求被 HTTP 基础设施认为是安全和幂等的,所以它以不同的方式处理。例如 GET 请求可以被缓存重定向等。当请求不安全和幂等时,它应该使用 POST 方法。所以正确的定义是:

[OperationContract]
[WebInvoke(UriTemplate = "/login?username={userName}&password={password}&softwareVersion={softwareVersion}", ResponseFormat=WebMessageFormat.Json)]
ITicket Login(string userName, string password, string softwareVersion);

因为 WebInvoke 默认为 POST 方法。这也是为什么所有协议(protocol)隧道(例如 SOAP)通常对所有请求使用 POST HTTP 方法的原因。

前一个示例中的另一个问题可能还是 REST 方法 = 充分利用 HTTP 基础架构。它应该使用基于 HTTP 的身份验证(登录)= Basic、Digest、OAuth 等。这并不意味着您不能拥有类似的资源,但您应该首先考虑使用标准的 HTTP 方式。

您的第二个示例实际上要好得多,但它存在 WCF 限制问题。 WCF 只能从 URL 中读取基本类型(顺便说一下,你想如何在 URL 中传递对象?)。任何其他参数类型都需要自定义 WCF 行为。如果您需要公开接受数据协定的方法,您必须再次使用在正文中接受参数的 HTTP 方法 - 再次使用 POST 并将 JSON 序列化票证放入请求正文:

[OperationContract]
[WebInvoke(UriTemplate = "/GetMetaData",RequestFormat=WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
IMetaData GetMetaData(ITicket ticket);

关于c# - 是否有使用 basicHttpBinding 扩展 WCF 服务以允许 REST 服务与 JSON 通信的好方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8167651/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com