WCF Webinvoke POST дает (400) Неверный запрос на конкретный c сервер - PullRequest
1 голос
/ 24 марта 2020

Доброе утро / вечер,

Я новичок в WCF и создал образец приложения. Проблема в том, что я передаю json строку в качестве запроса, но получаю 400: Ошибка ошибочного запроса. Подробности моего примера приведены ниже:

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

SampleService.sv c .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

Что я пробовал: я изменил тайм-аут для отправки и получения, тип контента - приложение / json. Запрос выдает ошибку только для этого сервера. У меня есть другой сервер, на котором я пытался, и POST проходит на сервере. Оба сервера имеют одинаковую конфигурацию. Когда я запускаю Fiddler для ошибочного сервера, вызов POST завершается успешно. Отправка точно такого же запроса от POSTMAN на ошибочный сервер дает статус успеха (200 OK), и я получаю правильный ответ в обоих этих случаях.

Примечание: WEBGET, WEBInvoke DELETE работают нормально для сервера. Только WEBInvoke POST не работает для указанного c сервера. Кто-нибудь может мне помочь в этом? Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 25 марта 2020

Эта часть полезной нагрузки мне не подходит. Я изменил 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\""
+"}";
0 голосов
/ 25 марта 2020

Почему вы вызываете службу WCF Restful, используя прокси (фабрика каналов)? Если действительно, мы должны использовать базовый адрес службы вместо POST URL. Кроме того, договор на обслуживание должен быть таким же, как и у сервера.

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

Этот фрагмент кода должен использовать базовый адрес службы для отправки запроса через прокси.
Фактически мы обычно отправляем запрос через POSTMan / fiddler при вызове службы WCF, созданной Webhttpbinding. Кроме того, мы должны использовать Uri, украшенный атрибутом URITemplate.
Не стесняйтесь, дайте мне знать, если проблема все еще существует.

...