18

Is it possible to create HTTP(s) post request inside Azure Function? I am trying to create a custom webhook that is listening to one service and when triggered then its calling another service over HTTP using post.

My code looks like that:

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{

    BitbucketRequest data = await req.Content.ReadAsAsync<BitbucketRequest>();
    //DO STH WITH DATA TO GET e.g. USER STORY ID

    using(var client = new HttpClient()){
        client.BaseAddress = new Uri("https://SOME_TARGETPROCESS_URL/api/v1");
        var body = new { EntityState = new  { Id = 174 } };
        var result = await client.PostAsJsonAsync(
                       "/UserStories/7034/?resultFormat=json&access_token=MYACCESSTOKEN",
                       body);
        string resultContent = await result.Content.ReadAsStringAsync();
    }

    return req.CreateResponse<string>(HttpStatusCode.OK,"OKOK");
}

I suppose the problem is that currently HttpRequestMessage is occupying web socket and I can not create new Http Request.

Errors that I found in Exceptions details:

  • The underlying connection was closed: An unexpected error occurred on a send.
  • Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
  • Socket Exception Error Code : 10054
SteveC
  • 15,808
  • 23
  • 102
  • 173
Przemek Marcinkiewicz
  • 1,267
  • 1
  • 19
  • 32
  • 4
    Found the issue By default no support for TLS 1.2 was enabled (which was used by endpoint I was calling). System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12; – Przemek Marcinkiewicz Feb 27 '17 at 10:46
  • You're correct; this also worked for me! – Peter R Oct 17 '17 at 08:53

5 Answers5

20

For anyone else who lands here when searching for HttpClient in Azure functions.

https://learn.microsoft.com/en-us/azure/azure-functions/manage-connections

// Create a single, static HttpClient
private static HttpClient httpClient = new HttpClient();

public static async Task Run(string input)
{
    var response = await httpClient.GetAsync("https://example.com");
    // Rest of function
}
Ryan E.
  • 977
  • 8
  • 16
9

It is certainly possible and the following code block works just fine in my test function:

using(var client = new HttpClient())
{
    client.BaseAddress = new Uri("https://www.google.com");
    var result = await client.GetAsync("");
    string resultContent = await result.Content.ReadAsStringAsync();
    log.Info(resultContent);
}

It prints out HTML of google.com. POST also works: returns Error 405 (Method Not Allowed)!!1 from google.

Can it be that your callee is failing?

Mikhail Shilkov
  • 34,128
  • 3
  • 68
  • 107
  • 17
    It's worth pointing out that you should be aware of this anti-pattern when using HttpClient in a function. https://learn.microsoft.com/en-us/azure/architecture/antipatterns/improper-instantiation/ – Aidos Oct 02 '17 at 08:52
6

I've done the HTTP post inside Azure Function like so:

using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using Newtonsoft.Json;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, string arg1, string arg2, string arg3, TraceWriter log)
{
    log.Info("C# HTTP trigger function processed a request.");
    var text = String.Format("arg1: {0}\narg2: {1}\narg3: {2}", arg1, arg2, arg3);
    log.Info(text);

    var results = await SendTelegramMessage(text);
    log.Info(String.Format("{0}", results));

    return req.CreateResponse(HttpStatusCode.OK);
}

public static async Task<string> SendTelegramMessage(string text)
{
    using (var client = new HttpClient())
    {

        Dictionary<string, string> dictionary = new Dictionary<string, string>();
        dictionary.Add("PARAM1", "VALUE1");
        dictionary.Add("PARAM2", text);

        string json = JsonConvert.SerializeObject(dictionary);
        var requestData = new StringContent(json, Encoding.UTF8, "application/json");

        var response = await client.PostAsync(String.Format("url"), requestData);
        var result = await response.Content.ReadAsStringAsync();

        return result;
    }
}

As you could guess by the name, I'm using this to send a POST request to a telegram bot

4c74356b41
  • 69,186
  • 6
  • 100
  • 141
2

I just spent quite a few hours myself trying to get this to work. This was in NodeJS. The thing I figured out, was that I apparently needed to have an endpoint running HTTPS, and with a valid certificate.

Not sure if this is documented anywhere.

0

At that point no support for TLS 1.2 was enabled in Azure Functions. The endpoint on the other hand was using TLS 1.2.

Adding this before POST request was sent solved the problem:

System.Net.ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12;
Przemek Marcinkiewicz
  • 1,267
  • 1
  • 19
  • 32