0

Can someone please help me to fix this Issue. I am not able to debug from where it is going wrong. Basically I have created a WCF Rest API WebService using WCF Relay in Azure to have hybrid connection between on-premise and Azure. Also if I am ignoring any certificate validation, that endpoint is for on-premise as it is self-signed certificate but when making API call, I am using the base64 encoded public key provided by WCF Relay when publishing it in Azure.

WCF Contract And Implementation:

Contract Interface

Implementation

I am successfully able to get the "validationToken" in the WCF service and also returning the same validationToken immediately below 5 seconds. After returning, it always error out showing this message.

Postman Client For Sending HTTP Request

Error Response and no subscription created

EDIT

WCF Contract

[OperationContract]
        [WebInvoke(Method = "POST", UriTemplate = "webhookForConservation?validationToken={validationToken}", 
            BodyStyle = WebMessageBodyStyle.Bare)]
        string webhookForConservation(WebhookPayload data, string validationToken);

WCF Implementation:

1st approach to return 200 OK status code:

public string webhookForConservation(WebhookPayload data, string validationToken = "")
        {
            ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
            var client = new HttpClient();
            client.DefaultRequestHeaders.Add("Accept", "text/plain");
            client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
            HttpResponseMessage response = null;
            WebOperationContext ctx = WebOperationContext.Current;
            if (validationToken != null && validationToken != "")
            {
                response = client.PostAsync("http://localhost:8080/conversationWebHook/conversationSubscription?validationToken=" + validationToken, null).Result;
                var apiContent = response.Content.ReadAsStringAsync().Result;
                ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
                ctx.OutgoingResponse.ContentType = "text/plain";
                return apiContent;
            }
            else
            {
                StringContent strContent = new StringContent(DataContractJsonSerializerHelper.SerializeJson(data));
                strContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
                response = client.PostAsync("http://localhost:8080/conversationWebHook/conversationSubscription", strContent).Result;
            }
            var result = (response != null) ? response.Content.ReadAsStringAsync().Result : "";
            ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
            return result;
        }

2nd Approach to return 200 status code:

public WebFaultException<string> webhookForConservation(WebhookPayload data, string validationToken="")
        {
            ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
            var client = new HttpClient();
            client.DefaultRequestHeaders.Add("Accept", "text/plain");
            client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json");
            HttpResponseMessage response = null;
            if (validationToken != null && validationToken != "")
            {
                response = client.PostAsync("http://localhost:8080/conversationWebHook/conversationSubscription?validationToken=" + validationToken, null).Result;
                var apiContent = response.Content.ReadAsStringAsync().Result;
                return new WebFaultException<string>(apiContent, HttpStatusCode.OK);
            }
            else
            {
                StringContent strContent = new StringContent(DataContractJsonSerializerHelper.SerializeJson(data));
                strContent.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
                response = client.PostAsync("http://localhost:8080/conversationWebHook/conversationSubscription", strContent).Result;
            }
            var result = (response != null) ? response.Content.ReadAsStringAsync().Result : "";
            return new WebFaultException<string>(result, HttpStatusCode.OK); ;
        }

Same error seen after returning 200 OK response code from WCF Service

Postman Client Throws Error

Calling Relay WCF API directly with Postman:

WCF API Call From Postman

Headers:

WCF API Call Headers From Postman

Thank you in advance for all the help.

Tanuj
  • 53
  • 1
  • 8
  • Is your relay returning a 200 status code for the validation? Is the response type text/plain? Is your service behind the relay returning the validation token value? – baywet Mar 16 '20 at 11:34
  • Hi @baywet, many thanks for your help. Actual application is coded in Java (using SpringBoot) and when using ngrok it is working all fine and my subscription is registered properly. After this I used postman client and checked the Request Headers and Response Headers, it is defaulting this value which you are asking for. Is your relay returning a 200 status code for the validation? - Yes Is the response type text/plain? - Yes (confirmed by Postman client) Is your service behind the relay returning the validation token value? - Yes (confirmed by Postman client) – Tanuj Mar 17 '20 at 09:51
  • so it's working when you are not using the WCF relay you are building but not working when you are? – baywet Mar 17 '20 at 12:29
  • yes exactly you are correct. No clue at all where I am doing wrong. – Tanuj Mar 17 '20 at 12:43
  • from the code you posted I can see you are relaying the response body. However it's not clear whether you are relaying the status code and the content type, could you double check that? – baywet Mar 17 '20 at 21:58
  • @baywet 1st Approach to return 200 status code--- WebOperationContext ctx = WebOperationContext.Current; ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK; ---- 2nd Approach to return 200 status code--- return new WebFaultException("{response}", HttpStatusCode.OK); -------- Added headers: client.DefaultRequestHeaders.Add("Accept", "text/plain"); client.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/json"); --------- With these changes also it is throwing the same error. Let me know if you need a screenshot for it. – Tanuj Mar 18 '20 at 10:50
  • Please edit your question to include everything from the relay – baywet Mar 18 '20 at 11:16
  • Hi @baywet, please see the EDIT section and thank you so much for the patience and support. – Tanuj Mar 18 '20 at 12:18
  • thanks for adding the details. In both cases I don't see anywhere setting content-type the response of the relay (not the request to the downstream service) to "text/plain". Maybe ctx.OutgoingResponse.ContentType = "text/plain" ? but I don't know the WCF API that well – baywet Mar 18 '20 at 14:22
  • Yes you are correct there exists a property with ContentType under OutgoingResponse but sorry to say it did not work. I have updated my question to include ContentType value in OutgoingResponse property. – Tanuj Mar 19 '20 at 05:43
  • Can you edit your post to include using postman to the relay? (POST ?validationToken=something, no content type header, no accept header) – baywet Mar 19 '20 at 13:05
  • Sorry @baywet maybe I am dumb I do not understand what you are asking for? Are you asking me to change the title of the post to include Postman in title. Also I am sorry I cannot post Azure-Relay Url but I can add the image to show what validationToken value it is coming to azure relay and what response from JAVA App is coming back to relay. Will it help? – Tanuj Mar 19 '20 at 13:45
  • I was probably unclear in my last comment. Open Postman, send a POST request to https://yourNotificationEndpointRelayUrl?validationToken=something and add the results of that to the original question please – baywet Mar 19 '20 at 13:48
  • @baywet I have edited the question again. You can see at the bottom for the updated content. – Tanuj Mar 19 '20 at 14:07
  • The problem here is that the relay is adding an XML wrapper around the value provided in the validationToken query string parameter. The response body should ONLY contain the value from validationToken and nothing else. – baywet Mar 19 '20 at 15:01
  • @baywet Thank you so much. Yes indeed that was the problem. I changed the return value of the Web Service from String to Stream and then it worked :). Thank you so much. How can I mark this as answer. – Tanuj Mar 19 '20 at 15:23
  • I added a recap of our long discussion as an answer, you can mark it now :) – baywet Mar 19 '20 at 16:21
  • @baywet When I am marking as Answer it is telling me: "Thanks for the feedback! Votes cast by those with less than 15 reputation are recorded, but do not change the publicly displayed post score." but as soon as I have more reputation I will come back to this question and mark as answer again. Thanks again and have a great day! – Tanuj Mar 20 '20 at 02:18

1 Answers1

1

Two problems were preventing the WCF relay to work properly:

  • The relay wasn't setting the response content type to text/plain, this was fixed with ctx.OutgoingResponse.ContentType = "text/plain"
  • The relay was adding an XML wrapper to the required response body, this was addressed by changing the return value to Stream
baywet
  • 4,377
  • 4
  • 20
  • 49