I try to send the SMS from Azure Function, it show the error. But if i do in Web or console app the sms succesfully sent. The error is this:
System.TypeInitializationException:'The type initializer for 'Nexmo.Api.Configuration' threw an exception.'
MissingMethodException:
Method not found: 'Microsoft.Extensions.Configuration.IConfigurationBuilder Microsoft.Extensions.Configuration.MemoryConfigurationBuilderExtensions.AddInMemoryCollection(Microsoft.Extensions.Configuration.IConfigurationBuilder, System.Collections.Generic.IEnumerable1<System.Collections.Generic.KeyValuePair2>)'.
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var client = new Nexmo.Api.Client(creds: new Credentials(Api_KEY, Api_Secret));
var results = client.SMS.Send(request: new SMS.SMSRequest()
{
from = nexmo.Sender,
text = nexmo.Msg,
to = nexmo.Receiver
});
I faced the same problem, it seems that the Nexmo.Csharp.Client package does not work correctly on Azure Functions. This could be because one of the assemblies is not compatible with Azure (not all are) or some configuration setting that is not supported on Azure Functions.
I was surprised by how many references/assemblies are installed by:
Install-Package Nexmo.Csharp.Client
So I gave up on trying to identify what is the cause. Instead a much simpler solution is to create your own HttpClient and use the REST API directly (that is probably what the weighty package does anyhow).
var client = new HttpClient();
var requestContent = new FormUrlEncodedContent(new[] {
new KeyValuePair<string, string>("api_key", "YOURKEY"),
new KeyValuePair<string, string>("api_secret", "YOURSECRET"),
new KeyValuePair<string, string>("to", "TO!!!"),
new KeyValuePair<string, string>("from", "MisterCook"),
new KeyValuePair<string, string>("text", "MisterCook Says Hi")
});
HttpResponseMessage response = await client.PostAsync(
"https://rest.nexmo.com/sms/json",
requestContent);
HttpContent responseContent = response.Content;
using (var reader = new StreamReader(await responseContent.ReadAsStreamAsync()))
{
// If you need it...
}
This will spare you from deploying the bulky Nexmo.Csharp.Client package deployment and works in Azure Functions.
I realise this is an old question, but I noticed it's still not had an answer accepted.
I've just used the latest version of the .Net SDK (5.9.0) with Functions v1, v3 and v4 using the below code and had no issues
using Vonage;
using Vonage.Request;
using Vonage.Messaging;
var credentials = Credentials.FromApiKeyAndSecret("abcd123efg", "abcdefgfgfgfgf");
var VonageClient = new VonageClient(credentials);
var response = VonageClient.SmsClient.SendAnSms(new SendSmsRequest()
{
To = "0123456789",
From = "Vonage APIs",
Text = "A text message sent using the Vonage SMS API"
});
If it works locally or in another context, then the code is correct. For Azure Functions in particular I would check that the dependencies are installed as you expect, and that the variables like API key have the values you expect (add some logging to test this) - these work differently in the serverless context. Hope that helps!
I also was able to get the new WhatsApp API running with Mister Cook's approach.
public bool Send(Message msg)
{
var task = SendAsync(msg);
task.Wait();
return task.Result;
}
public async Task<bool> SendAsync(Message msg)
{
var requestJson = CreateJson(msg);
Console.WriteLine(requestJson);
var content = new StringContent(requestJson);
content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
var client = new HttpClient();
try
{
HttpResponseMessage response = await client.PostAsync("https://messages-sandbox.nexmo.com/v0.1/messages", content);
string responseJson = await response.Content.ReadAsStringAsync();
return MessageSucceeded(responseJson);
}
catch
{
return false;
}
}
private string CreateJson(Message msg)
{
JObject request = new JObject();
JObject from = new JObject();
from.Add("type", "whatsapp");
from.Add("number", "14157386170");
request.Add("from", from);
JObject to = new JObject();
to.Add("type", "whatsapp");
to.Add("number", ConnectionData);
request.Add("to", to);
JObject message = new JObject();
JObject content = new JObject();
content.Add("type", "text");
content.Add("text", msg.Text);
message.Add("content", content);
request.Add("message", message);
return request.ToString();
}
private bool MessageSucceeded(string json)
{
var obj = JObject.Parse(json);
JToken token;
return obj.TryGetValue("message_uuid", out token);
}
The RequestJson for Sandbox Testing is:
{
"from": { "type": "whatsapp", "number": "14157386170" },
"to": { "type": "whatsapp", "number": "YOUR_WHITELIST_NUMBER" },
"message": {
"content": { "type": "text", "text": "Test succeeded. Congrats" }
}
}
If the Request succeeded, the ResponseJson will contain a message_uuid. I only check wether it is contained or not
{"message_uuid": "e6859d67-1a94-44c4-bf09-a3e3fa7f8691"}
Related
I am following the developer docs of this website: Yoco Charge API.
I am using C# with Dotnet core 6 for my backend server, I can see the request does return with 201 however my api always comes back with an error 500, I would like to know how I should Alter my Code to return the correct results. Here is my code:
public async Task<string> CreatePayment(string Token)
{
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Add("X-Auth-Secret-Key", paymentSeceret);
try
{
Dictionary<string, string> values = new Dictionary<string, string>
{
{"token", Token },
{"amountInCents", "1000" },
{"currency", "ZAR" }
};
var myContent = JsonSerializer.Serialize(values);
var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var result = await client.PostAsync(paymentString, byteContent);
return "";
}
catch (Exception ex)
{
return "Error";
}
finally
{
client.Dispose();
}
...
}
After the request goes through, I always get the following error:
Serialization and deserialization of 'System.Action' instances are not supported. Path: $.MoveNextAction.
System.NotSupportedException: Serialization and deserialization of 'System.Action' instances are not supported. Path: $.MoveNextAction.
I am trying to upload the Video from Xamarin.Forms (Portable) to YouTube, I have tried to use the Google APIs but the Google APIs are not compatible with the Xamarin.Forms (Portable) at this stage. So, I compulsory have to upload it via HttpClient but I am getting Unauthorised in StatusCode
public async Task UploadVideoAsync(Stream stream)
{
//var token = flow.LoadTokenAsync("", CancellationToken.None).Result;
string json = #"{
""snippet"": {
""title"": ""using API"",
""description"": ""This is a description of my video"",
""tags"": [""cool"", ""video"", ""more keywords""],
""categoryId"": ""21"",
},
""status"": {
""privacyStatus"": ""public"",
""embeddable"": true,
""license"": ""youtube""
}
}";
var JsonReqMsg = new StringContent(json);
JsonReqMsg.Headers.ContentType = new MediaTypeHeaderValue("application/json")
{
CharSet = "UTF-8"
};
var request = new HttpRequestMessage
(HttpMethod.Post, new Uri("https://www.googleapis.com/upload/youtube/v3/videos?uploadType=resumable&part=snippet,status"));
request.Headers.Add("X-Upload-Content-Length", stream.Length.ToString());
request.Headers.Add("x-upload-content-type", "video/*");
request.Content = JsonReqMsg;
var httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Add("Authorization", Constants.API.Google.AccessTokenType + " " + Constants.API.Google.AccessToken);
var UploadReq = await httpClient.SendAsync(request);
if (UploadReq.IsSuccessStatusCode)
{
IEnumerable<string> _VideoUrl = null;
var res = await UploadReq.Content.ReadAsStringAsync();
UploadReq.Headers.TryGetValues("Location", out _VideoUrl);
var binaryContent = new StreamContent(stream);
var UploadReq_ = await httpClient.PutAsync(new Uri(_VideoUrl.ToString()), binaryContent);
if (UploadReq_.IsSuccessStatusCode)
{
var res_ = await UploadReq_.Content.ReadAsStringAsync();
}
}
}
Is there anything wrong in the code?
You're authorization is incorrect. You should be using "bearer" or a developer key. Here is the YouTube documentation: https://developers.google.com/youtube/2.0/developers_guide_protocol#OAuth2_Calling_a_Google_API
I have previously been adding users programmatically using Active Directory Authentication Library (ADAL), but now I need to define "signInNames" (= users email), and that doesn't seem to be possible with ADAL (please tell me if im wrong).
Now I'm trying to add a new user (local account) programmatically using HTTP POST, following the documentation on MSDN.
//Get access token (using ADAL)
var authenticationContext = new AuthenticationContext(AuthString, false);
var clientCred = new ClientCredential(ClientId, ClientSecret);
var authenticationResult = authenticationContext.AcquireTokenAsync(ResourceUrl, clientCred);
var token = authenticationResult.Result.AccessToken;
//HTTP POST CODE
const string mail = "new#email.com";
// Create a new user object.
var user = new CustomUser
{
accountEnabled = true,
country = "MS",
creationType = "LocalAccount",
displayName = mail,
passwordPolicies = "DisablePasswordExpiration,DisableStrongPassword",
passwordProfile = new passwordProfile { password = "jVPmEm)6Bh", forceChangePasswordNextLogin = true },
signInNames = new signInNames { type = "emailAddress", value = mail }
};
var url = "https://graph.windows.net/" + TenantId + "/users?api-version=1.6";
var jsonObject = JsonConvert.SerializeObject(user);
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
var response = client.PostAsync(url,
new StringContent(JsonConvert.SerializeObject(user).ToString(),
Encoding.UTF8, "application/json"))
.Result;
if (response.IsSuccessStatusCode)
{
dynamic content = JsonConvert.DeserializeObject(
response.Content.ReadAsStringAsync()
.Result);
// Access variables from the returned JSON object
var appHref = content.links.applications.href;
}
}
But i have no success, getting this response:
{StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content:....}
Any ideas what i should do? I succeeded using Powershell-script, but I need to do this in my C# app.
Thank you for your response Fei Xue, i believe i had the right permissions. What i did to solvem my problem.
First off i removed my own custom class "NewUser", then i downloaded this sample-project: https://github.com/AzureADQuickStarts/B2C-GraphAPI-DotNet/blob/master/B2CGraphClient/B2CGraphClient.cs to eliminate the risk that my code was wrong. I modified it to support my needs, then i created a simple JObject:
var jsonObject = new JObject
{
{"accountEnabled", true},
{"country", customer.CustomerBase.Company},
{"creationType", "LocalAccount"},
{"displayName", pendingCustomer.Email.Trim()},
{"passwordPolicies", "DisablePasswordExpiration,DisableStrongPassword"},
{"passwordProfile", new JObject
{
{"password", pwd},
{"forceChangePasswordNextLogin", true}
} },
{"signInNames", new JArray
{
new JObject
{
{"value", pendingCustomer.Email.Trim()},
{"type", "emailAddress"}
}
}
}
};
client = new B2CGraphClient(ClientId, ClientSecret, TenantId);
var response = await client.CreateUser(jsonObject.ToString());
var newUser = JsonConvert.DeserializeObject<User>(response);
From B2CGraphClient.cs
private async Task<string> SendGraphPostRequest(string api, string json)
{
// NOTE: This client uses ADAL v2, not ADAL v4
var result = authContext.AcquireToken(Globals.aadGraphResourceId, credential);
var http = new HttpClient();
var url = Globals.aadGraphEndpoint + tenant + api + "?" + Globals.aadGraphVersion;
var request = new HttpRequestMessage(HttpMethod.Post, url);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
request.Content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await http.SendAsync(request);
if (!response.IsSuccessStatusCode)
{
var error = await response.Content.ReadAsStringAsync();
var formatted = JsonConvert.DeserializeObject(error);
//Console.WriteLine("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
Logger.Error("Error Calling the Graph API: \n" + JsonConvert.SerializeObject(formatted, Formatting.Indented));
}
Logger.Info((int)response.StatusCode + ": " + response.ReasonPhrase);
return await response.Content.ReadAsStringAsync();
}
This finally solved all my problems, it was probably an format-error in the serialization of my NewCustomer-class, which then got rejected by the API.
Did you grant the app sufficient permission to operate users? The create user REST API works well for me for the B2C tenant.
Here are the steps I tested:
1.Create the app via the PowerShell below
PowerShell:
$bytes = New-Object Byte[] 32
$rand = [System.Security.Cryptography.RandomNumberGenerator]::Create()
$rand.GetBytes($bytes)
$rand.Dispose()
$newClientSecret = [System.Convert]::ToBase64String($bytes)
New-MsolServicePrincipal -DisplayName "My New B2C Graph API App" -Type password -Value
2.Grant the app to User Account Administrator role.
Add-MsolRoleMember -RoleObjectId fe930be7-5e62-47db-91af-98c3a49a38b1 -RoleMemberObjectId 7311370c-dac3-4f34-b2ce-b22c2a5a811e -RoleMemberType servicePrincipal
3.Get the token for the app with client credential flow
POST: https://login.microsoftonline.com/adb2cfei.onmicrosoft.com/oauth2/token
grant_type=client_credentials&client_id={AppPrincipalId return by PowerShell}&client_secret={client_secret}&resource=https%3A%2F%2Fgraph.windows.net
4.Create the user with REST below:
POST: https://graph.windows.net/adb2cfei.onmicrosoft.com/users?api-version=1.6
authorization: bearer {token}
content-type: application/json
{
"accountEnabled": true,
"creationType": "LocalAccount",
"displayName": "Alex Wu",
"passwordProfile": {
"password": "Test1234",
"forceChangePasswordNextLogin": false
},
"signInNames": [
{
"type": "userName",
"value": "AlexW"
},
{
"type": "emailAddress",
"value": "AlexW#example.com"
}
]
}
I've implemented Twilio REST API with C# successfully earlier. However, all of a sudden the API calls that are made keep getting 400 - BAD REQUEST.
The response body doesn't contain any specific error either...
I'll say it again, it worked for a week or two and all of sudden it returns BAD REQUEST.
The code is exact the following below.
public async Task SendSmsAsync(string number, string message)
{
var accountSid = _configuration["Authentication:Twilio:AccountSID"];
var authToken = _configuration["Authentication:Twilio:AuthToken"];
var twilioNumber = _configuration["Authentication:Twilio:Number"];
var credentials = new NetworkCredential(accountSid, authToken);
var handler = new HttpClientHandler { Credentials = credentials };
using (var client = new HttpClient(handler))
{
var url = $"https://api.twilio.com/2010-04-01/Accounts/{ accountSid }/Messages";
var body = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("To", number),
new KeyValuePair<string, string>("From", twilioNumber),
new KeyValuePair<string, string>("Body", message),
};
var content = new FormUrlEncodedContent(body);
content.Headers.ContentType.CharSet = "UTF-8";
var response = await client.PostAsync(url, content);
if (response.IsSuccessStatusCode)
{
//Uri success = response.Headers.Location;
}
}
}
I have deployed an AzureML published experiment with deployed web service. I tried to use the sample code provided in the configuration page, but universal apps do not implement Http.Formatting yet, thus I couldn't use postasjsonasync.
I tried to follow the sample code as much as possible, but I'm getting statuscode of 415 "Unsupported Media Type", What's the mistake I'm doing?
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", apiKey);
// client.BaseAddress = uri;
var scoreRequest = new
{
Inputs = new Dictionary<string, StringTable>() {
{
"dataInput",
new StringTable()
{
ColumnNames = new [] {"Direction", "meanX", "meanY", "meanZ"},
Values = new [,] { { "", x.ToString(), y.ToString(), z.ToString() }, }
}
},
},
GlobalParameters = new Dictionary<string, string>() { }
};
var stringContent = new StringContent(scoreRequest.ToString());
HttpResponseMessage response = await client.PostAsync(uri, stringContent);
Many Thanks
You'll need to serialize the object to a JSON string (I recommend using NewtonSoft.Json to make it easier) and set the content type accordingly. Here's an implementation I'm using in my UWP apps (note that _client is an HttpClient):
public async Task<HttpResponseMessage> PostAsJsonAsync<T>(Uri uri, T item)
{
var itemAsJson = JsonConvert.SerializeObject(item);
var content = new StringContent(itemAsJson);
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
return await _client.PostAsync(uri, content);
}