This sections explains how to use the AMI_Client component in an ASP.NET application.

AMI_Client component in an ASP.NET application

The AMI_Client component can also be used in an ASP.NET Web application to provide a Web based interface to an Asterisk system.

In order to use the AMI_Client in an ASP.NET Web Application, it must be created and initialized when the Web Application starts. This is done by writing an event handler for the Application_Start application level event. In ASP.NET the application and session level event handler are contained in the application file: Global.asax.cs (Or Global.asax.vb).

The example below show a Global.asax.cs file with application level event handlers. The first is for Application_Start global event which is invoqued only once when the application starts. This handlers creates dynamically a new AMI_Client object initialize it and call the Start method to connect and login to the given Asterisk system. It also sets an HttpApplicationState variable with the AMI_Client object so it can be accessed from individual sessions. And it sets a global event handler for the AMI_Client's NewCallEvent event. Finally a handler for the Application_Stop global event is used to call the AMI_Client Stop method when the Web Application is stopped.

Global.asax.cs

CopyC#
 1using System;
 2using AMIgo;
 3
 4namespace WebApplication1
 5{
 6
 7    public class Global : System.Web.HttpApplication
 8    {
 9        //+=====================================================+
10    // This global event is called when the application starts
11        void Application_Start(object sender, EventArgs e)
12        {
13          // Create a new instance of the AMI_Client
14          AMI_Client AMI_Client1 = new AMI_Client();
15          // Set the AMI Host to connect to.
16          AMI_Client1.AstMngrSiteName = "EdgePBX";
17          AMI_Client1.AstMngrHost = "192.168.1.10";
18          AMI_Client1.AstMngrPort = 5038;
19          AMI_Client1.AstMngrUserName = "admin";
20          AMI_Client1.AstMngrPassword = "noelbou";
21          // Set a global event handler for the NewCallEvent
22          AMI_Client1.NewCallEvent += new AMIgo.NewCallEventHandler(AMI_Client1_NewCallEvent);
23          AMI_Client1.Start();
24          // An HttpApplicationState object is set so that the AMI_Client object can be accessed from sessions.
25          Application["AMI_Client"] = AMI_Client1;
26        }
27        //+=====================================================+
28        void Application_End(object sender, EventArgs e)
29        {
30            //  This code is executed when the application stops.
31          AMI_Client AMI_ClientL = (AMI_Client)Application["AMI_Client"];
32          if (AMI_ClientL != null)
33            AMI_ClientL.Stop();
34        }
35        //+=====================================================+
36        // Handler for the NewCallEvent.
37        void AMI_Client1_NewCallEvent(object sender, AMIgo.NewCallEventArgs ev)
38        {
39          CallType ct = ev.call_type;
40          string phone_no = "";
41
42          if (ev.call_type == CallType.Outbound)
43          {
44            phone_no = ev.dst_caller_id;
45            if ((phone_no.Length > 0) && (phone_no[0] == '9'))
46              phone_no = phone_no.Substring(1);
47            extension = AClient.ExtractExtensionNo(ev.src_channel);
48            if (!String.IsNullOrEmpty(extension))
49              // Set a HttpApplicationState for given extension with Caller ID, Call Type and Timestamp
50              Application[extension] = phone_no + ";" + ev.call_type.ToString() + ";" + AMI_Client.UnixTimestampToString(ev.timestamp, false);
51          }
52          else if (ev.call_type == CallType.Inbound)
53          {
54            phone_no = ev.src_caller_id;
55            if ((phone_no.Length > 0) && (phone_no[0] == '1'))
56              phone_no = phone_no.Substring(1);
57            extension = ev.dst_channel;
58            if (!String.IsNullOrEmpty(extension))
59              // Set a HttpApplicationState for given extension with Caller ID, Call Type and Timestamp
60              Application[extension] = phone_no + ";" + ev.call_type.ToString() + ";" + AMI_Client.UnixTimestampToString(ev.timestamp, false);
61          }
62          else if (ev.call_type == CallType.Internal)
63          {
64          }
65        }
66        //+=====================================================+
67    }
68}

Handling the NewCallEvent

The startup code also sets an event handler for the AMI_Client NewCallEvent. This event is triggered when a new call is connected. In this exemple this event is used to set an application State variable named after the extension number that contains the Inbound CallerID number or Oubound called number to be used for the database calls lookup. This state variable is available from any page and can be retreived by using the intrinsic 'Application' object.

Exemple: This retreives any call data string set by the NewCallEvent handler in global.asax.cs:

CopyC#
1string call_data = (string) Application["6000"];

Displaying Asterisk objects and Status

The AMI_Client maintains several syncronized List which contains the definition and status of the connected Asterisk system. These can easily be displayed in a Web Application by using GridView controls and setting their DataSource properties to the AMI_Client List and calling the GridView's DataBind Method. See the ASP.NET demo for an example.

CopyC#
 1namespace WebApplication1
 2{
 3    public partial class _Default : System.Web.UI.Page
 4    {
 5        protected void Page_Load(object sender, EventArgs e)
 6        {
 7          AMI_Client AClient = (AMI_Client)Application["AMI_Client"];
 8          if (AClient != null)
 9          {
10            GridView1.DataSource = AClient.AstUsersObjectsList;
11            GridView1.DataBind();
12            GridView2.DataSource = AClient.AstChannelsList;
13            GridView2.DataBind();
14            GridView3.DataSource = AClient.AstQueuesList;
15            GridView3.DataBind();
16            GridView4.DataSource = AClient.AstQueuesMembersList;
17            GridView4.DataBind();
18            GridView5.DataSource = AClient.AstAgentsList;
19            GridView5.DataBind();
20            GridView6.DataSource = AClient.AstConferencesList;
21            GridView6.DataBind();
22            GridView7.DataSource = AClient.AstConferenceUsersList;
23            GridView7.DataBind();
24          }
25        }
26    }        
27  }

Database Lookup

This shows how to retreive the call data information stored by the NewCallEvent handler in global.asax.cs and to do a call lookup and display any record found in a DetailView control.

The following code can be used in the code behind file for any page in an application. This example uses an SqlDataSource and DetailView control to display records from the Northwind Database's 'Customer' table. A label control is used to display the call data string, or 'NONE' if not set for the currently logged UserName / Extension.

If first retreive the logged user extension and test if any application state variable has been set for this extension. This happens when a call is received or on an outbound call in the NewCallEvent handler in the global.asax.cs file (see above). If a call data application state variable is found the phone number is extracted and the select query of the SqlDataSource is invoqued using the phone number as a parameter. The query will retreive any record in the Northwind Database's 'Customer' table that matches the phone number and it will be displayed in the DetailView control.

CopyC#
 1 namespace WebApplication1
 2{
 3  public partial class CallsLookup : System.Web.UI.Page
 4  {
 5    protected void Page_Load(object sender, EventArgs e)
 6    {
 7      // Retreive the logged UserName / Extension
 8      string user = Context.User.Identity.Name;
 9      // Test if user logged and if an Application State variable exist for that user extension
10      // Note: In this example we use the logged user name as the extension number.
11      if ((user != null) && (Application[user] != null))
12      {
13        // Retreive the call datat string set by the NewCallEvent handler in global.asax.cs
14        string[] call_data = ((string)Application[user]).Split(';');
15        if (call_data.Length > 0)
16        {
17          // The call data contains the Caller ID / Oubound phone number, the call type and a timestamp
18          LabelLastCall.Text = user + " : " + call_data[0] + " " + call_data[1] + " " + call_data[2];
19          // Set a parameter for the SELECT query of the DetailView's SqlDataSource
20          SqlDataSource2.SelectParameters.Clear();
21          SqlDataSource2.SelectParameters.Add(new Parameter("Phone", System.TypeCode.String, call_data[0]));
22          // This execute the Query and get any entry that matches the 'PhoneNo' in the Customers Table
23          SqlDataSource2.Select(DataSourceSelectArguments.Empty);
24        }
25      }
26      else
27        LabelLastCall.Text = "None";
28
29    }
30  }
31}

Click to Call feature

The next code excerpt show how to retreive and use the AMI_Client from with a session to provide a click to call feature. Here we have a button and a textBox which contains the full number to dial, including the trunk access prefix (usually '9'). A reference to the global AMI_Client object is retreived by using the intrinsinc 'Application' object.

Excerpt from ASP.NET doc.: A single instance of an HttpApplicationState class is created the first time a client requests any URL resource from within a particular ASP.NET application virtual directory. A separate single instance is created for each ASP.NET application on a Web server. A reference to each instance is then exposed via the intrinsic 'Application' object.

The following is a button Click event handler that could be used in the code behind file for a page, say default.aspx.cs.

Default.asax.cs

CopyC#
 1protected void ButtonCall_Click(object sender, EventArgs e)
 2{
 3  // Get the AMI_Client instance from this HttpApplicationState instance through the 'Application' intrinsic object.
 4  // The returned object need to be typecast to the AMI_Client type
 5  AMI_Client AClient = (AMI_Client)Application["AMI_Client"];
 6  // To keep this example simple, the user contains the extension number. Ex 6000
 7  string tech = null, user = Context.User.Identity.Name;
 8  if (AClient != null)
 9  {
10    if (user == null) // 
11      LabelResultMsg.Text = "Please login with extension as user name first.";
12    else
13    {
14      // Find the extension's tech. (SIP / IAX / Zap/DAHDI)from AMI_Client's AstUsersObjectsList 
15      for (int i = 0; i < AClient.AstUsersObjectsList.Count; i++)
16      {
17        if (AClient.AstUsersObjectsList[i].ObjName == user)
18          tech = AClient.AstUsersObjectsList[i].ChannelType;
19      }
20      if (tech == null)
21        LabelResultMsg.Text = "Extension not found. Please login with extension as user name first.";
22      else
23      {
24        // We can now use the AMI_Client object to originate a call from the user's extension to the given phone number
25        // Asterisk will call the extension, and then go to the dialplan context to dial the given number 
26        AClient.OriginateExtension(tech + "/" + user, "DLPN_DialPlan1", TextBoxPhoneNo.Text, "1", "");
27        LabelResultMsg.Text = "Calling extension: " + tech + "/" + user + " for PhoneNo: " + TextBoxPhoneNo.Text;
28      }
29    }
30  }
31}

See Also

Other Resources