使用多个参数调用 WCF RESTful 服务方法时出现 InvalidOperationException?
InvalidOperationException when calling a WCF RESTful service method with multiple arguments?
我有以下代码用于名为 AuthenticationService
的服务:
IAuthenticationService.cs
[ServiceContract]
public interface IAuthenticationService
{
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
bool Login(string username, string password, string applicationName);
}
AuthenticationService.svc.cs
public sealed class AuthenticationService : IAuthenticationService
{
public bool Login(string username, string password, string applicationName)
{
// TODO: add the logic to authenticate the user
return true;
}
}
Web.config
<system.serviceModel>
<!-- START: to return JSON -->
<services>
<service name="ImageReviewPoc.Service.AuthenticationService">
<endpoint contract="ImageReviewPoc.Service.Contracts.IAuthenticationService" binding="webHttpBinding" behaviorConfiguration="jsonBehavior"/>
</service>
</services>
<!-- END: to return JSON -->
<behaviors>
<!-- START: to return JSON -->
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<!-- END: to return JSON -->
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
并且我有以下使用该服务的控制台应用程序:
Program.cs
internal class Program
{
private static void Main(string[] args)
{
Login().Wait();
}
private static async Task Login()
{
var client = new AuthenticationServiceClient();
var ok = await client.LoginAsync("User", "Password!", "Console Application");
client.Close();
Console.WriteLine(ok);
}
}
App.config
<system.serviceModel>
<client>
<endpoint address="http://localhost:62085/AuthenticationService.svc/"
binding="webHttpBinding"
contract="AuthenticationServiceReference.IAuthenticationService"
kind="webHttpEndpoint" />
</client>
</system.serviceModel>
我使用 Postman 来测试发送以下 JSON 数据的服务并且它有效:
{"username": "reviewer", "password": "456", "applicationName": "123"}
但是,当我使用控制台应用程序测试服务时,我得到了
System.InvalidOperationException: Operation 'Login' of contract 'IAuthenticationService' specifies multiple request body parameters to be serialized without any wrapper elements. At most one body parameter can be serialized without wrapper elements. Either remove the extra body parameters or set the BodyStyle property on the WebGetAttribute/WebInvokeAttribute to Wrapped.
从IAuthenticationService.cs
代码可以看出,我已经将BodyStyle
设置为Wrapped
。有人可以指导我这里做错了什么吗?
注意以下几点:
- 我已经在 Whosebug 和互联网上搜索解决方案。几乎所有的解决方案都是关于设置
BodyStyle
。它可能对其他人有帮助,但对我没有太大帮助。
Login
和 LoginAsync
我都试过了;结果是一样的
- 我通过 "Add Service Reference" 在 Visual Studio 2013(终极版,如果你想知道的话)中添加它来引用该服务
- 我知道我可以使用其他方式调用该服务;例如,HttpClient,但我想知道为什么自动生成的客户端不起作用
这是您调用服务的方式。
public void DoLogin()
{
string uri = "http://localhost:62085/AuthenticationService.svc/Login";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "text/json";
string data = "{\"username\": \"reviewer\", \"password\": \"456\", \"applicationName\": \"123\"}";
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] bytes = encoding.GetBytes(data);
request.ContentLength = bytes.Length;
using (Stream requestStream = request.GetRequestStream())
{
// Send the data.
requestStream.Write(bytes, 0, bytes.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(x))
{
using(var responseStream = response.GetResponseStream())
{
using(var reader = new StreamReader(responseStream))
{
//Here you will get response
string loginResponse = reader.ReadToEnd();
}
}
}
}
添加到 Login/LoginAsync 客户端合同方法
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)].
因此您的客户合同将如下所示:
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.IAuthenticationService")]
public interface IAuthenticationService {
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IAuthenticationService/Login", ReplyAction="http://tempuri.org/IAuthenticationService/LoginResponse")]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
bool Login(string username, string password, string applicationName);
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IAuthenticationService/Login", ReplyAction="http://tempuri.org/IAuthenticationService/LoginResponse")]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
System.Threading.Tasks.Task<bool> LoginAsync(string username, string password, string applicationName);
}
客户合同自动生成。因此,您应该在每次更新服务参考后执行此操作。
enter link description here
我有以下代码用于名为 AuthenticationService
的服务:
IAuthenticationService.cs
[ServiceContract]
public interface IAuthenticationService
{
[OperationContract]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
bool Login(string username, string password, string applicationName);
}
AuthenticationService.svc.cs
public sealed class AuthenticationService : IAuthenticationService
{
public bool Login(string username, string password, string applicationName)
{
// TODO: add the logic to authenticate the user
return true;
}
}
Web.config
<system.serviceModel>
<!-- START: to return JSON -->
<services>
<service name="ImageReviewPoc.Service.AuthenticationService">
<endpoint contract="ImageReviewPoc.Service.Contracts.IAuthenticationService" binding="webHttpBinding" behaviorConfiguration="jsonBehavior"/>
</service>
</services>
<!-- END: to return JSON -->
<behaviors>
<!-- START: to return JSON -->
<endpointBehaviors>
<behavior name="jsonBehavior">
<webHttp/>
</behavior>
</endpointBehaviors>
<!-- END: to return JSON -->
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="false"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add scheme="http" binding="webHttpBinding"/>
</protocolMapping>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true" multipleSiteBindingsEnabled="true"/>
</system.serviceModel>
并且我有以下使用该服务的控制台应用程序:
Program.cs
internal class Program
{
private static void Main(string[] args)
{
Login().Wait();
}
private static async Task Login()
{
var client = new AuthenticationServiceClient();
var ok = await client.LoginAsync("User", "Password!", "Console Application");
client.Close();
Console.WriteLine(ok);
}
}
App.config
<system.serviceModel>
<client>
<endpoint address="http://localhost:62085/AuthenticationService.svc/"
binding="webHttpBinding"
contract="AuthenticationServiceReference.IAuthenticationService"
kind="webHttpEndpoint" />
</client>
</system.serviceModel>
我使用 Postman 来测试发送以下 JSON 数据的服务并且它有效:
{"username": "reviewer", "password": "456", "applicationName": "123"}
但是,当我使用控制台应用程序测试服务时,我得到了
System.InvalidOperationException: Operation 'Login' of contract 'IAuthenticationService' specifies multiple request body parameters to be serialized without any wrapper elements. At most one body parameter can be serialized without wrapper elements. Either remove the extra body parameters or set the BodyStyle property on the WebGetAttribute/WebInvokeAttribute to Wrapped.
从IAuthenticationService.cs
代码可以看出,我已经将BodyStyle
设置为Wrapped
。有人可以指导我这里做错了什么吗?
注意以下几点:
- 我已经在 Whosebug 和互联网上搜索解决方案。几乎所有的解决方案都是关于设置
BodyStyle
。它可能对其他人有帮助,但对我没有太大帮助。 Login
和LoginAsync
我都试过了;结果是一样的- 我通过 "Add Service Reference" 在 Visual Studio 2013(终极版,如果你想知道的话)中添加它来引用该服务
- 我知道我可以使用其他方式调用该服务;例如,HttpClient,但我想知道为什么自动生成的客户端不起作用
这是您调用服务的方式。
public void DoLogin()
{
string uri = "http://localhost:62085/AuthenticationService.svc/Login";
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "text/json";
string data = "{\"username\": \"reviewer\", \"password\": \"456\", \"applicationName\": \"123\"}";
System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
byte[] bytes = encoding.GetBytes(data);
request.ContentLength = bytes.Length;
using (Stream requestStream = request.GetRequestStream())
{
// Send the data.
requestStream.Write(bytes, 0, bytes.Length);
}
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(x))
{
using(var responseStream = response.GetResponseStream())
{
using(var reader = new StreamReader(responseStream))
{
//Here you will get response
string loginResponse = reader.ReadToEnd();
}
}
}
}
添加到 Login/LoginAsync 客户端合同方法
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)].
因此您的客户合同将如下所示:
[System.ServiceModel.ServiceContractAttribute(ConfigurationName="ServiceReference1.IAuthenticationService")]
public interface IAuthenticationService {
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IAuthenticationService/Login", ReplyAction="http://tempuri.org/IAuthenticationService/LoginResponse")]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
bool Login(string username, string password, string applicationName);
[System.ServiceModel.OperationContractAttribute(Action="http://tempuri.org/IAuthenticationService/Login", ReplyAction="http://tempuri.org/IAuthenticationService/LoginResponse")]
[WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped, RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
System.Threading.Tasks.Task<bool> LoginAsync(string username, string password, string applicationName);
}
客户合同自动生成。因此,您应该在每次更新服务参考后执行此操作。 enter link description here