调用具有多个参数的WCF RESTful服务方法时出现InvalidOperationException?

时间:2015-01-19 11:30:43

标签: c# json wcf rest

我有一个名为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&#39; Login&#39;合同&#39; IAuthenticationService&#39;指定要序列化的多个请求正文参数,而不包含任何包装元素。最多可以在没有包装元素的情况下序列化一个body参数。删除额外的body参数或将WebGetAttribute / WebInvokeAttribute上的BodyStyle属性设置为Wrapped。

IAuthenticationService.cs代码中可以看出,我已将BodyStyle设置为Wrapped。有人可以指导我做我在这里做错的事吗?

请注意以下事项:

  • 我已经在Stackoverflow和互联网上搜索解决方案了。几乎所有解决方案都是关于设置BodyStyle。它可能对其他人有所帮助,但对我没有多大帮助。
  • 我尝试了LoginLoginAsync;它的结果相同
  • 我通过添加服务参考&#34;添加服务参考&#34;来引用该服务。在Visual Studio 2013(终极版,如果你想知道)
  • 我知道我可以用其他方式拨打电话;例如,HttpClient,但我想知道的是为什么自动生成的客户端无法正常工作

2 个答案:

答案 0 :(得分:1)

这是您应该如何致电服务。

    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();
                }

            }
        }
    }

答案 1 :(得分:0)

添加到登录/ 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