Making telephone call from ASP.NET application - c#

I have a requirement that we need to make a telephone call using ASP.NET application.
Our ASP.NET application is used in call center. Currently, they make a call to customer manually. Now, the call should go from our application by clicking the phone number link and starts recording the conversation between the agent (application user) and customer.
What all would be the hardware requirements for the above scenario?
How can we implement telephone calling in asp.net application and what are the required components to implement the same?

Nexmo offers a range of cloud communication APIs including Voice API that allows you to fulfil this requirement.
All you need is to install the Nuget package:
Install-Package Nexmo.Csharp.Client
Then use the Call class:
Call.Do(new Call.CallCommand
{
to = new[]
{
new Call.Endpoint
{
type = "phone",
number = NEXMO_TO_NUMBER
}
from = new Call.Endpoint
{
type = "phone",
number = NEXMO_FROM_NUMBER
},
answer_url = new[]
{
NEXMO_CALL_ANSWER_URL
}
});
Here's a detailed post on how to make a phone call with Nexmo Voice API and ASP.Net

If you want to use phone line you should use Computer-telephony boards, for example Dialogic: http://www.dialogic.com/products/ip_enabled/ip_boards.htm They should have API, so you will be able to use it from your application.

In addition to Asterisk, you might also consider Twilio, a web based telephony service that provides you a rest based api for making and receiving phone calls. See http://www.twilio.com/docs/howto/ for info.

You Can Use Third party API To Make a Call Using Asp.net Code.First You Need To Register. Here's a detailed post on
How To Make a Call Using Asp.net Code
protected void btnCall_click(object sender, EventArgs e)
{
// Call porcessing happens here.
// Use your account SID and authentication token instead of
// the placeholders shown here.
var accountSID = "C0d09f4042d1ff4acb55329cf8e5efb";
var authToken = "05b278c6f3538d3a35f13b25c73dff";
// Instantiate an instance of the Twilio client.
TwilioClient.Init(accountSID, authToken);
// Retrieve the account, used later to retrieve the
var account = AccountResource.Fetch(accountSID);
// this.varDisplay.Items.Clear();
// Retrieve the values entered by the user.
var To =new PhoneNumber(txtMobileNumber.Text);
//twlio=14155992671
var from = new PhoneNumber("+918098641075");
var myMessage = this.txtMessage.Text;
// Create a URL using the Twilio message and the user-entered
// text. You must replace spaces in the user's text with '%20'
// to make the text suitable for a URL.
var url = #"http://twimlets.com/message?Message%5B0%5D={myMessage.Replace()}";
var twimlUri = new Uri(url);
// Display the endpoint, API version, and the URL for the message.
this.varDisplay.Items.Add(#"Using Twilio endpoint { }");
this.varDisplay.Items.Add(#"Twilioclient API Version is {apiVersion}");
this.varDisplay.Items.Add(#"The URL is {url}");
// Place the call.
var Call=CallResource.Create(To,from,url:twimlUri);
// var call = CallResource.create(to, from, url: twimlUri);
this.varDisplay.Items.Add("Call status: " + Call.Status);
}

Related

SOAP error when connecting to NetSuite web services: "Namespace prefix ' soapenv' not defined"

I am getting the following error when connecting to a NetSuite production account, through the Suitetalk API:
I don't have problems connecting to the Sandbox account for this client. I am connecting through a C# WCF project. I don't believe the problem is with the c# project, since this code is being used in Production with many other clients.
It seems to me like the SOAP message being returned is incorrectly formatted - there seems to be a line break before the 'soapenv' element in the SOAP message. I am getting this error when creating a "get" request against the API(using passport login). This error occurs on any API call though, I did try simply logging in through the API as well.
I have double checked the login details and account information for this client and everything seems in orders. Besides, if this information is incorrect, I should be getting authentication errors - not malformed SOAP messages.
Any help will be appreciated, thanks!
It turns out that I needed to use the webservices.na3.netsuite WSDL. I was under the impression that the regular "webservices.netsuite" WSDL would direct any requests to the correct server.
So when connecting to a NetSuite account through SuiteTalk, be sure to make use of the correct WSDL and specify the correct endpoint along with your login credentials. You can check which server your account is hosted on by looking at the URL when logged into your NetSuite account.
Update
I made use of the newest 'DataCenterAwareNetSuiteService' class to dynamically get the correct data center for the current account that I am trying to connect to:
class DataCenterAwareNetSuiteService : NetSuiteService
{
private System.Uri OriginalUri;
public DataCenterAwareNetSuiteService(string account, bool doNotSetUrl)
: base()
{
OriginalUri = new System.Uri(this.Url);
if (account == null || account.Length == 0)
account = "empty";
if (!doNotSetUrl)
{
//var temp = getDataCenterUrls(account);
DataCenterUrls urls = getDataCenterUrls(account).dataCenterUrls;
Uri dataCenterUri = new Uri(urls.webservicesDomain + OriginalUri.PathAndQuery);
this.Url = dataCenterUri.ToString();
}
}
public void SetAccount(string account)
{
if (account == null || account.Length == 0)
account = "empty";
this.Url = OriginalUri.AbsoluteUri;
DataCenterUrls urls = getDataCenterUrls(account).dataCenterUrls;
Uri dataCenterUri = new Uri(urls.webservicesDomain + OriginalUri.PathAndQuery);
this.Url = dataCenterUri.ToString();
}
}
The above is called like so:
new DataCenterAwareNetSuiteService("*account number*", false);
With the latest version of NetSuite, some changes have been made to URLs. For instance, now you can have more than one SandBox URL. Because of this, the URL format has changed. The account number used when authenticating is also now different. For sandboxes the account Id is now passed up as ACCOUNTNUMBER_SANDBOXID, for example 12345678_SB1.
You can determine the URLs for the SOAP and REST services by using the datacenterurls endpoint and supplying the account # you would like to determine the URLS for.
https://rest.netsuite.com/rest/datacenterurls?account=YOUR_ACCOUNT_NUMBER
The functionality below is based on the answer from #Charl above.
I have made a couple changes below that provides the same functionality without using inheritance.
This may be a simpler implementation for a newer programmer who does not know how to use an inherited class.
var accountId = "1234567"; // Insert your account ID here
var Service = new NetSuiteService();
Service.Url = new Uri(Service.getDataCenterUrls(accountId).dataCenterUrls.webservicesDomain + new Uri(Service.Url).PathAndQuery).ToString();

How to call, Hang up, put on hold and unhold calls using Twilio?

I have a Twilio number and I understood that in order to do those 4 actions(Call, Hang up, put onhold and unhold calls) I need to create a conference call, but I don't understand how I add my Twilio number to the conference and how do I add another number of a mobile of a client. For example, if my Twilio number is " +9728888888" and the customer's I want to call to mobile number is "+9725555555" – I want code examples of :
1. Calling the customer(from Twilio number " +9728888888" to mobile number "+9725555555")
2. Hold the call
3. UnHold the cold
4. Hangout the call.
I'm using Twilio NuGet on web api project. Can you give me the code examples , considering the numbers I gave(Twilio and mobile) for all of those four scenarios above? I would really appreciate it.
BTW, I saw the code example on their site:
using Twilio.TwiML;
class Example
{
static void Main()
{
var response = new VoiceResponse();
var dial = new Dial();
dial.Conference("moderated-conference-room",
startConferenceOnEnter: false);
response.Dial(dial);
System.Console.WriteLine(response.ToString());
}
}
but it doesn't acknowledge the Twilio or the mobile phone or even the Twilio authentication so I'm not sure how can it work..
Twilio developer evangelist here.
If you want to make a call from your Twilio number to a end user and put both your agent and the user into a conference call then this is the way that I would do it. I am not, however, a C# developer, so while I'll try to give code samples I'm not experienced in .NET web api projects.
You say that you are using the Twilio package from Nuget, that's a good start.
First up, you need to generate a call to your agent and place them in the conference call to wait for the user. To do this, you would use the Twilio REST API to place the call. That code looks a bit like this
const string accountSid = "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX";
const string authToken = "your_auth_token";
TwilioClient.Init(accountSid, authToken);
var to = new PhoneNumber("AGENT_PHONE_NUMBER");
var from = new PhoneNumber("+9728888888");
var call = CallResource.Create(
to,
from,
url: new Uri("http://example.com/conference")
);
When this call connects with the agent's number Twilio will make a request to the URL that is sent to the API. Your application needs to respond to tell Twilio what to do with the call. In this case, we should put the agent into a <Conference> to wait for the user. Within this action we also need to generate a call to the user.
public IHttpActionResult Conference()
{
// make the call to the user
var to = new PhoneNumber("+9725555555");
var from = new PhoneNumber("+9728888888");
var call = CallResource.Create(
to,
from,
url: new Uri("http://example.com/user_conference")
);
// return the TwiML
var response = new VoiceResponse();
var dial = new Dial();
dial.Conference("Conference", endConferenceOnExit: true);
response.Dial(dial);
Ok(response.ToString());
}
Note: I've set the agent side of this conference to endConferenceOnExit: true. This means that when the agent hangs up, the conference call will end for all participants.
Now, Twilio will make the call to the user and when that connects ask the new URL what to do with the call. This time you just need to respond with the TwiML to connect to the same conference. I'll leave that for you to deal with.
Finally, to put participants on hold you need to use the REST API again. You need to get the conference SID and the SID of the participant you want to put on hold. Since you will be putting the user on hold from your agent, you get both of these SIDs in the second webhook callback to your application.
With the conference and call SID, make a POST request like this:
const string conferenceSid = "CONFERENCE_SID";
const string callSid = "CALL_SID";
ParticipantResource.Update(
conferenceSid,
callSid,
hold: true,
holdUrl: new Uri("http://example.com/hold")
);
You can also provide a hold URL which can provide music while the user waits. For more information, check the participant resource documentation. Unholding the user is the same process, but you set hold to false.
Let me know if this gets you on the way to creating this feature.

Google Data API Authorization Redirect URI Mismatch

Background
I am wanting to write a small, personal web app in .NET Core 1.1 to interact with YouTube and make some things easier for me to do and I am following the tutorials/samples in Google's YouTube documentation. Sounds simple enough, right? ;)
Authenticating with Google's APIs seems impossible! I have done the following:
Created an account in the Google Developer Console
Created a new project in the Google Developer Console
Created a Web Application OAuth Client ID and added my Web App debug URI to the list of approved redirect URIs
Saved the json file provided after generating the OAuth Client ID to my system
In my application, my debug server url is set (and when my application launches in debug, it's using the url I set which is http://127.0.0.1:60077).
However, when I attempt to authenticate with Google's APIs, I recieve the following error:
That’s an error.
Error: redirect_uri_mismatch
The redirect URI in the request, http://127.0.0.1:63354/authorize/,
does not match the ones authorized for the OAuth client.
Problem
So now, for the problem. The only thing I can find when searching for a solution for this is people that say
just put the redirect URI in your approved redirect URIs
Unfortunately, the issue is that every single time my code attempts to authenticate with Google's APIs, the redirect URI it is using changes (the port changes even though I set a static port in the project's properties). I cannot seem to find a way to get it to use a static port. Any help or information would be awesome!
NOTE: Please don't say things like "why don't you just do it this other way that doesn't answer your question at all".
The code
client_id.json
{
"web": {
"client_id": "[MY_CLIENT_ID]",
"project_id": "[MY_PROJECT_ID]",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://accounts.google.com/o/oauth2/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_secret": "[MY_CLIENT_SECRET]",
"redirect_uris": [
"http://127.0.0.1:60077/authorize/"
]
}
}
Method That Is Attempting to Use API
public async Task<IActionResult> Test()
{
string ClientIdPath = #"C:\Path\To\My\client_id.json";
UserCredential credential;
using (var stream = new FileStream(ClientIdPath, FileMode.Open, FileAccess.Read))
{
credential = await GoogleWebAuthorizationBroker.AuthorizeAsync(
GoogleClientSecrets.Load(stream).Secrets,
new[] { YouTubeService.Scope.YoutubeReadonly },
"user",
CancellationToken.None,
new FileDataStore(this.GetType().ToString())
);
}
var youtubeService = new YouTubeService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = this.GetType().ToString()
});
var channelsListRequest = youtubeService.Channels.List("contentDetails");
channelsListRequest.Mine = true;
// Retrieve the contentDetails part of the channel resource for the authenticated user's channel.
var channelsListResponse = await channelsListRequest.ExecuteAsync();
return Ok(channelsListResponse);
}
Project Properties
The Original Answer works, but it is NOT the best way to do this for an ASP.NET Web Application. See the update below for a better way to handle the flow for an ASP.NET Web Application.
Original Answer
So, I figured this out. The issue is that Google thinks of a web app as a JavaScript based web application and NOT a web app with server side processing. Thus, you CANNOT create a Web Application OAuth Client ID in the Google Developer Console for a server based web application.
The solution is to select the type Other when creating an OAuth Client ID in the Google Developer Console. This will have Google treat it as an installed application and NOT a JavaScript application, thus not requiring a redirect URI to handle the callback.
It's somewhat confusing as Google's documentation for .NET tells you to create a Web App OAuth Client ID.
Feb 16, 2018 Updated Better Answer:
I wanted to provide an update to this answer. Though, what I said above works, this is NOT the best way to implement the OAuth workflow for a ASP.NET solution. There is a better way which actually uses a proper OAuth 2.0 flow. Google's documentation is terrible in regards to this (especially for .NET), so I'll provide a simple implementation example here. The sample is using ASP.NET core, but it's easily adapted to the full .NET framework :)
Note: Google does have a Google.Apis.Auth.MVC package to help simplifiy this OAuth 2.0 flow, but unfortunately it's coupled to a specific MVC implementation and does not work for ASP.NET Core or Web API. So, I wouldn't use it. The example I'll be giving will work for ALL ASP.NET applications. This same code flow can be used for any of the Google APIs you've enabled as it's dependent on the scopes you are requesting.
Also, I am assuming you have your application set up in your Google Developer dashboard. That is to say that you have created an application, enabled the necessary YouTube APIs, created a Web Application Client, and set your allowed redirect urls properly.
The flow will work like this:
The user clicks a button (e.g. Add YouTube)
The View calls a method on the Controller to obtain an Authorization URL
On the controller method, we ask Google to give us an Authorization URL based on our client credentials (the ones created in the Google Developer Dashboard) and provide Google with a Redirect URL for our application (this Redirect URL must be in your list of accepted Redirect URLs for your Google Application)
Google gives us back an Authorization URL
We redirect the user to that Authorization URL
User grants our application access
Google gives our application back a special access code using the Redirect URL we provided Google on the request
We use that access code to get the Oauth tokens for the user
We save the Oauth tokens for the user
You need the following NuGet Packages
Google.Apis
Google.Apis.Auth
Google.Apis.Core
Google.apis.YouTube.v3
The Model
public class ExampleModel
{
public bool UserHasYoutubeToken { get; set; }
}
The Controller
public class ExampleController : Controller
{
// I'm assuming you have some sort of service that can read users from and update users to your database
private IUserService userService;
public ExampleController(IUserService userService)
{
this.userService = userService;
}
public async Task<IActionResult> Index()
{
var userId = // Get your user's ID however you get it
// I'm assuming you have some way of knowing if a user has an access token for YouTube or not
var userHasToken = this.userService.UserHasYoutubeToken(userId);
var model = new ExampleModel { UserHasYoutubeToken = userHasToken }
return View(model);
}
// This is a method we'll use to obtain the authorization code flow
private AuthorizationCodeFlow GetGoogleAuthorizationCodeFlow(params string[] scopes)
{
var clientIdPath = #"C:\Path\To\My\client_id.json";
using (var fileStream = new FileStream(clientIdPath, FileMode.Open, FileAccess.Read))
{
var clientSecrets = GoogleClientSecrets.Load(stream).Secrets;
var initializer = new GoogleAuthorizationCodeFlow.Initializer { ClientSecrets = clientSecrets, Scopes = scopes };
var googleAuthorizationCodeFlow = new GoogleAuthorizationCodeFlow(initializer);
return googleAuthorizationCodeFlow;
}
}
// This is a route that your View will call (we'll call it using JQuery)
[HttpPost]
public async Task<string> GetAuthorizationUrl()
{
// First, we need to build a redirect url that Google will use to redirect back to the application after the user grants access
var protocol = Request.IsHttps ? "https" : "http";
var redirectUrl = $"{protocol}://{Request.Host}/{Url.Action(nameof(this.GetYoutubeAuthenticationToken)).TrimStart('/')}";
// Next, let's define the scopes we'll be accessing. We are requesting YouTubeForceSsl so we can manage a user's YouTube account.
var scopes = new[] { YouTubeService.Scope.YoutubeForceSsl };
// Now, let's grab the AuthorizationCodeFlow that will generate a unique authorization URL to redirect our user to
var googleAuthorizationCodeFlow = this.GetGoogleAuthorizationCodeFlow(scopes);
var codeRequestUrl = googleAuthorizationCodeFlow.CreateAuthorizationCodeRequest(redirectUrl);
codeRequestUrl.ResponseType = "code";
// Build the url
var authorizationUrl = codeRequestUrl.Build();
// Give it back to our caller for the redirect
return authorizationUrl;
}
public async Task<IActionResult> GetYoutubeAuthenticationToken([FromQuery] string code)
{
if(string.IsNullOrEmpty(code))
{
/*
This means the user canceled and did not grant us access. In this case, there will be a query parameter
on the request URL called 'error' that will have the error message. You can handle this case however.
Here, we'll just not do anything, but you should write code to handle this case however your application
needs to.
*/
}
// The userId is the ID of the user as it relates to YOUR application (NOT their Youtube Id).
// This is the User ID that you assigned them whenever they signed up or however you uniquely identify people using your application
var userId = // Get your user's ID however you do (whether it's on a claim or you have it stored in session or somewhere else)
// We need to build the same redirect url again. Google uses this for validaiton I think...? Not sure what it's used for
// at this stage, I just know we need it :)
var protocol = Request.IsHttps ? "https" : "http";
var redirectUrl = $"{protocol}://{Request.Host}/{Url.Action(nameof(this.GetYoutubeAuthenticationToken)).TrimStart('/')}";
// Now, let's ask Youtube for our OAuth token that will let us do awesome things for the user
var scopes = new[] { YouTubeService.Scope.YoutubeForceSsl };
var googleAuthorizationCodeFlow = this.GetYoutubeAuthorizationCodeFlow(scopes);
var token = await googleAuthorizationCodeFlow.ExchangeCodeForTokenAsync(userId, code, redirectUrl, CancellationToken.None);
// Now, you need to store this token in rlation to your user. So, however you save your user data, just make sure you
// save the token for your user. This is the token you'll use to build up the UserCredentials needed to act on behalf
// of the user.
var tokenJson = JsonConvert.SerializeObject(token);
await this.userService.SaveUserToken(userId, tokenJson);
// Now that we've got access to the user's YouTube account, let's get back
// to our application :)
return RedirectToAction(nameof(this.Index));
}
}
The View
#using YourApplication.Controllers
#model YourApplication.Models.ExampleModel
<div>
#if(Model.UserHasYoutubeToken)
{
<p>YAY! We have access to your YouTube account!</p>
}
else
{
<button id="addYoutube">Add YouTube</button>
}
</div>
<script>
$(document).ready(function () {
var addYoutubeUrl = '#Url.Action(nameof(ExampleController.GetAuthorizationUrl))';
// When the user clicks the 'Add YouTube' button, we'll call the server
// to get the Authorization URL Google built for us, then redirect the
// user to it.
$('#addYoutube').click(function () {
$.post(addYoutubeUrl, function (result) {
if (result) {
window.location.href = result;
}
});
});
});
</script>
As referred here, you need to specify a fix port for the ASP.NET development server like How to fix a port number in asp.NET development server and add this url with the fix port to the allowed urls. Also as stated in this thread, when your browser redirects the user to Google's oAuth page, you should be passing as a parameter the redirect URI you want Google's server to return to with the token response.
I noticed that there is easy non-programmatic way around.
If you have typical monotlith application built in typical MS convention(so not compatible with 12factor and typical DDD) there is an option to tell your Proxy WWW server to rewrite all requests from HTTP to HTTPS so even if you have set up Web App on http://localhost:5000 and then added in Google API url like: http://your.domain.net/sigin-google, it will work perfectly and it is not that bas because it is much safer to set up main WWW to rewrite all to HTTPS.
It is not very good practice I guess however it makes sense and does the job.
I've struggled with this issue for hours in a .net Core application. What finally fixed it for me was, in the Google developers console, to create and use a credential for "Desktop app" instead of a "Web application".
Yeah!! Using credentials of desktop app instead of web app worked for me fine. It took me more than 2 days to figure out this problem. The main problem is that google auth library dose not adding or supporting http://localhost:8000 as redirect uri for web app creds but credentials of desktop app fixed that issue. Cause its supporting http://___ connection instead of https: connection for redirect uri

Updating cell in public spreadsheet without need for auth?

I have set a spreadsheet to public which I assume would mean a user shouldn't need authorization to access and make changes to it, I should only need to provide my client id and secret? (I'm the only person who will be using this app and the spreadsheet is on my own Google account which is also the owner of the app)
I went through the documentation here: https://developers.google.com/google-apps/spreadsheets/?hl=en
My code works perfectly - it basically just updates a single cell in a spreadsheet with a function and then returns the value of that cell.
The issue is, I don't want to have to keep authorizing through the webpage. Is it possible to skip the need to authorize? Or at least authorize through code automatically instead of manually doing it through a webpage?
using Google.GData.Client;
using Google.GData.Spreadsheets;
namespace Spreadsheet{
class Program{
static void Main(){
OAuth2Parameters parameters = new OAuth2Parameters();
parameters.ClientId = "client-id-here";
parameters.ClientSecret = "client-secret-here";
parameters.RedirectUri = "urn:ietf:wg:oauth:2.0:oob"; //I'm not even sure what this is, I assume it's only necessary for web based applications
parameters.Scope = "https://spreadsheets.google.com/feeds https://docs.google.com/feeds";
//This is where the user is required to navigate to a page and retrieve access code
string authorizationUrl = OAuthUtil.CreateOAuth2AuthorizationUrl(parameters);
parameters.AccessCode = Console.ReadLine();
OAuthUtil.GetAccessToken(parameters);
string accessToken = parameters.AccessToken;
GOAuth2RequestFactory requestFactory =
new GOAuth2RequestFactory(null, "Spreadsheet", parameters);
SpreadsheetsService service = new SpreadsheetsService("Spreadsheet");
service.RequestFactory = requestFactory;
//spreadsheet related code here..
}
}
}
Where is this script running? The code sample you are using tries to get a token every time you run it. You have two options
If this code runs on a server and it can store the refresh token securely then, manually get a refresh token and change the script to just get a new access token (using that refresh token) to do the update.
Change to using a service account. Service accounts are built to handle these kind of use cases. You get a service account and in the spreadsheet give access to service account (share with it) and using service account you make a request to get an access token that you can use.

c# program to call Google+ API and Custom Search API from Google

Can you please tell me via a code sample how I can write a C# program that will call
the Google+ API and Custom Search API of Google.
I know there is a brief description of it on :::::
URL:https://developers.google.com/+/api/
URL:https://developers.google.com/custom-search/v1/using_rest
URL:http://code.google.com/p/google-api-dotnet-client/wiki/OAuth2
But the process mentioned in the links in doing the above as given in the documentation is
not very clear.
Is there a simple illustration through C# code that I can use to call Google+ API and Custom
Search API?
The Google API Dotnet Client project contains .NET wrappers form most of Google's APIs, including Google+.
They do have several examples but not for all of their APIs, yet.
A Google+ example from their page to query for public activities is:
CommandLine.EnableExceptionHandling();
CommandLine.DisplayGoogleSampleHeader("PlusService API");
// Create the service.
var objService= new PlusService();
objService.Key = ""; //put in user key.
var acts = objService.Activities.Search();
acts.Query = "super cool";
acts.MaxResults = 10;
var searchResults = acts.Fetch();
if (searchResults.Items != null)
{
foreach (Activity feed in searchResults.Items)
{
//extract any property of uer interest
CommandLine.WriteResult(feed.Title, feed.Actor);
}
}

Categories