1

早上好/晚上好,

我是 WCF 的新手,并创建了一个示例应用程序。问题是我将 json 字符串作为请求传递,但收到 400:Bad request 错误。我的样本的详细信息如下:

ISampleService.cs:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Text;

namespace SampleWCF
{
    [ServiceContract]
    public interface ISampleService
    {
        [OperationContract]
        [WebInvoke(UriTemplate = "/folder_entries/{mFileID_param}/shares?notify=true", Method = "POST", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        string AddShareToFileNotify(string mFileID_param, string rqst_param);
    }
}


#region TestSample
[DataContract]
public class TestSample
{
    public TestSample() { }

    [DataMember(Name = "recipient")]
    public Recipient Recipient { get; set; }

    [DataMember(Name = "role")]
    public String Role { get; set; }

    [DataMember(Name = "access")]
    public TestAccess access{ get; set; }

    [DataMember(Name = "can_share")]
    public bool CanShare { get; set; }

    [DataMember(Name = "days_to_expire")]
    public int DaysToExpire { get; set; }

}

    #region TestAccess 
    [DataContract]
    public class TestAccess 
    {
        #region Attributes

        [DataMember(Name = "role")]
        public String Role { get; set; }

        [DataMember(Name = "rights")]
        public AccessRights AccessRights { get; set; }

        #endregion

        #region Constructor
        public TestAccess () { }
        #endregion
    }
    #endregion

    #region rights
    [DataContract]
    public class AccessRights
    {
        public AccessRights() { }

        [DataMember(Name = "testinternal")]
        public Boolean Internal { get; set; }

        [DataMember(Name = "testexternal")]
        public Boolean External { get; set; }

        [DataMember(Name = "public")]
        public Boolean Public { get; set; }

        [DataMember(Name = "max_role")]
        public String Max_Role { get; set; }

        [DataMember(Name = "grant")]
        public Boolean Grant { get; set; }

    }
    #endregion

    #region Recipient
    [DataContract]
    public class Recipient
    {
        public Recipient() { }

        [DataMember(Name = "id")]
        public string ID { get; set; }

        [DataMember(Name = "type")]
        public string Type { get; set; }

    }
    #endregion
#endregion

示例服务.svc.cs

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;
using System.ServiceModel.Web;
using System.ServiceModel.Security;
using System.Net;
using System.IO;
using System.Threading;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;

namespace SampleWCF
{
    public class SampleService : ISampleService
    {
        private ISampleService client = null;
        private WebChannelFactory<ISampleService> cf = null;
        private Uri uri = null;
        private WebHttpSecurityMode mode = WebHttpSecurityMode.Transport;
        public const string CERTIFICATE_TRUST_STORE_NAME = "Trust";

        //Method to Validate if the server certificate is valid or not
        private static bool ValidateServerCertificate(object sender,
                                                      X509Certificate certificate,
                                                      X509Chain chain,
                                                      SslPolicyErrors sslPolicyErrors)
        {
            bool result = false;
            X509Store store = null;

            try
            {
                // If the certificate is valid signed certificate, return true.
                if (SslPolicyErrors.None == sslPolicyErrors)
                {
                    return true;
                }

                // If there are errors in the certificate chain, look in the certificate store to check
                // if the user has already trusted the certificate or not.
                if ((0 != (sslPolicyErrors & SslPolicyErrors.RemoteCertificateChainErrors)) ||
                    (0 != (sslPolicyErrors & SslPolicyErrors.RemoteCertificateNameMismatch)))
                {
                    store = new X509Store(CERTIFICATE_TRUST_STORE_NAME, StoreLocation.CurrentUser);
                    store.Open(OpenFlags.ReadOnly);
                    result = store.Certificates.Contains(certificate);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("Could not validate certificate!");
                result = false;
            }
            finally
            {
                if (store != null)
                    store.Close();
            }

            return result;
        }


        public ISampleService initClient(string servername,
                                         string protocol,
                                         string username,
                                         string password)
        {
            uri = new Uri(protocol + "://" + servername + ":" + @"/rest");
            WebHttpBinding binding = new WebHttpBinding();
            binding.ReaderQuotas.MaxStringContentLength = int.MaxValue;
            binding.MaxReceivedMessageSize = int.MaxValue;
            binding.ReceiveTimeout = TimeSpan.FromMinutes(10.0);
            binding.SendTimeout = TimeSpan.FromMinutes(10.0);
            System.Net.ServicePointManager.DefaultConnectionLimit = 200;

            binding.Security.Mode = mode;
            binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

            cf = new WebChannelFactory<ISampleService>(binding, uri);
            cf.Credentials.UserName.UserName = username;
            cf.Credentials.UserName.Password = password;

            client = cf.CreateChannel();

            System.Net.ServicePointManager.ServerCertificateValidationCallback = ValidateServerCertificate;
            System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;

            Thread.Sleep(500);
            return client;
        }

        public string AddShareToFileNotify(string mFileID_param, string rqst_param)
        {
            using (new OperationContextScope((IContextChannel)client))
            {
                string rsp = null;
                try
                {
                    rsp = client.AddShareToFileNotify(mFileID_param, rqst_param);
                }
                catch (Exception ce)
                {
                    Console.WriteLine("Exception found!{0}",ce);
                    return rsp;
                }
                return rsp;
            }
        }
    }
}

主要调用函数:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TriggerMain
{
    class Program
    {
        static void Main(string[] args)
        {

            string mFileID = "xxxxxx";
            string rqst = "{"
    +"\"access\":{"
        +"\"role\":\"VIEWER\","
        +"\"sharing\":{"
            +"\"external\":false,"
            +"\"grant\":false,"
            +"\"internal\":false,"
            +"\"max_role\":null,"
            +"\"public\":false"

        +"}"
    +"},"
    +"\"can_share\": false,"
    +"\"days_to_expire\": 30,"
    +"\"recipient\": {"
        +"\"id\": <yyyyyy>,"
        +"\"type\": \"user\""
            +"},"
    +"\"role\": \"VIEWER\""
+"}";
            string rsp = null;

            SampleWCF.SampleService sample = new SampleWCF.SampleService();
            sample.initClient("<URL1.xxx.com>", "https", "<Username>", "<Password>");
            rsp = sample.AddShareToFileNotify(mFileID, rqst);
            Console.ReadLine();
        }
    }
}

运行应用程序时出现以下错误:

Exception found!System.ServiceModel.ProtocolException: The remote server returned an unexpected response: (400) Bad Request. ---> System.Net.WebException: The remote server returned an error: (400) Bad Request.
   at System.Net.HttpWebRequest.GetResponse()
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   --- End of inner exception stack trace ---

Server stack trace:
   at System.ServiceModel.Channels.HttpChannelUtilities.ValidateRequestReplyResponse(HttpWebRequest request, HttpWebResponse response, HttpChannelFactory`1 factory, WebException responseException, ChannelBinding channelBinding)
   at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
   at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:
   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
   at SampleWCF.ISampleService.AddShareToFileNotify(String mFileID_param, String rqst_param)
   at SampleWCF.SampleService.AddShareToFileNotify(String mFileID_param, String rqst_param) in c:\Users\SBasu\Documents\Visual Studio 2013\Projects\SampleWCF\SampleWCF\SampleService.svc.cs:line 103

我试过的:我改变了发送和接收的超时时间,内容类型是application/json。该请求仅针对此服务器引发错误。我有另一台服务器,我尝试过,POST 正在服务器中传递。两台服务器具有相同的配置。当我为错误的服务器运行 Fiddler 时,POST 调用成功。从 POSTMAN 向错误服务器发送完全相同的请求会给出成功(200 OK)状态,并且在这两种情况下我都得到了正确的响应。

注意:WEBGET、WEBInvoke DELETE 在服务器上工作正常。只有WEBInvoke POST不适用于特定服务器。有人可以帮我解决这个问题吗?提前致谢。

4

2 回答 2

0

为什么使用代理(通道工厂)调用 WCF Restful 服务?如果确实如此,我们应该使用服务基地址而不是POST URL. 此外,服务合同应与服务器相同。

uri = new Uri(protocol + "://" + servername + ":" + @"/rest") // where is the service port number? also, is the format right?

此代码片段应使用服务基地址通过代理发送请求。
实际上,我们通常在调用由Webhttpbinding. 此外,我们应该使用由 URITemplate 属性修饰的 Uri。
如果问题仍然存在,请随时告诉我。

于 2020-03-25T03:20:07.957 回答
0

有效载荷的这一部分对我来说看起来不正确。我更改了 1 行,见下文。

recipient.id唯一的补充是在值周围添加引号

string rqst = "{"
+"\"access\":{"
    +"\"role\":\"VIEWER\","
    +"\"sharing\":{"
        +"\"external\":false,"
        +"\"grant\":false,"
        +"\"internal\":false,"
        +"\"max_role\":null,"
        +"\"public\":false"

    +"}"
+"},"
+"\"can_share\": false,"
+"\"days_to_expire\": 30,"
+"\"recipient\": {"
    +"\"id\": \"<yyyyyy>\"," // this line I think was wrong. added quotes around the value
    +"\"type\": \"user\""
        +"},"
+"\"role\": \"VIEWER\""
+"}";
于 2020-03-25T03:34:55.270 回答