Wednesday, March 21, 2007

.NET: A Simple C# Push Application

Note: This article is written by me and was published in the BlackBerry Developers Journal in July 2005

Push applications can be created using any development language that is able to initiate a network connection and perform an HTTP post. An HTTP post to the BlackBerry® Mobile Data Service (MDS) handles the delivery of pushed data to a BlackBerry device.

The post is made up of a standard HTTP request header, a few unique Browser Push headers and a stream of data.

Note: The web page does not have to be sent when performing a Browser Channel Delete Push Topics within this section include:
> Required HTTP request headers
* Required
* Optional
> How does the application work?
> Let's get started
> How the httpPush method performs the push

The following additional HTTP request headers are required for a browser push to take place:

Required

X-RIM-Push-Title
X-RIM-Push-Type

Optional

X-RIM-Push-Channel-ID
X-RIM-Push-UnRead-Icon-URL
X-RIM-Push-Read-Icon-URL

The "X-Rim-Push-Title" header contains the title that will appear either on the Home screen of the BlackBerry device for a Browser Channel Push, or in the subject of the message for a Browser Message Push.

The "X-RIM-Push-Type" header holds the value that represents the type of push being sent. Possible values are:
  • Browser-Channel
  • Browser-Message
  • Browser-Content
  • Browser-Channel-Delete

The "X- RIM-Push-Channel-ID" header contains the URL of the page to be pushed to the device. This is not required when performing a Browser Message or Browser Content push.

The "X-RIM-Push-UnRead-Icon-URL" and "X-RIM-Push- Read-Icon-URL" are optional headers that specify the URL of the icons to be used for a Browser Channel Push. If not specified then the default Browser Channel Push icons are used. These two headers are not required for Browser Message, Browser Content or Browser Channel Delete Push and may be omitted

This article will show how to create an application to push a URL to one or more BlackBerry device users. For further information, please refer to "Push Me! Pushing web content to BlackBerry" in Volume 2, Issue 1 of the BlackBerry Developer Journal.

How does the application work?

When you run the application you will see the screen below.

Figure 1

Figure 1

Click the "Open" button to select a file that contains a list of BlackBerry device users with their BlackBerry Enterprise Server host, port and email/PIN. The following line shows the format of a "User Information File":

localhost 8080 2100000A

In this example, localhost is the name of the server that push is being sent to, port 8080 is the web server listen port on that server, and the PIN is set to 2100000A.

Note: The "User Information File" must be saved with an extension of ".txt"

Select the push type to continue and then specify the URL and the push name. If you want a read and unread icon to be published, provide URLs. Otherwise, leave the settings blank.

Note: Run the MDS Simulator before the BlackBerry device simulator to see the following results.

When the Send Push button is pushed, you should see the following icon in your simulator screen.

RIM Homepage

Let's get started
Figure 2

Download and unzip BlackBerryBulkPush.zip, and then open BlackBerryBulkPush.sln. This is a solution file that includes the setup project and the source project. When you open this project you will see the screen in Figure 3.

The solution explorer shows six files in the BlackBerryBulkPush Project. The files have the following functions:

App.config Used for configuration of logging framework log4net
App.ico Icon file
AssemblyInfo.cs File generated by VS .Net
HttpPushWorker.cs Performs the push operation
PushDialog.cs The UI for the Bulk Push
README.doc Installation instructions and known issues as of a certain date

Figure 2

Figure 3

The two relevant classes are PushDialog.cs and HttpPushWorker.cs. When the Send Push button is pressed, it invokes the button1_Click event in PushDialog.cs. Let’s review the button1_Click code to see what happens:

private void button1_Click(object sender, System.EventArgs e)
{
int pos,start;
string BESAddress,BESPort,Email,url;
string fDelimiter= " ";

//verifying information is filled correctly
if(verifyFields())
{
url="http://"+PushURLTextBox.Text;
} else {
this.PushStatusBar.Text = "Missing Required Fields";
return;
}

//checking for correct file (.txt extension)
if((txtFileName.Text).Substring((txtFileName.Text).IndexOf(".",0)+1,3) != "txt")
{
MessageBox.Show("Please enter a file with extension .txt");
return;
}

//checking if file exists
if (!File.Exists(txtFileName.Text))
{
MessageBox.Show(this,"Incorrect file name");
return ;
}

//verifying url
PushStatusBar.Text = "Requesting Page Data";
HttpPushWorker pusher = new HttpPushWorker(ref PushStatusBar,ref url);

if ( url == "Wrong" )
{
PushStatusBar.Text = "Push Failed, bad URL";
return;
}

// create reader & open file
TextReader sr = new StreamReader(txtFileName.Text);

//reading contents into string variable
string fContent = sr.ReadLine();

/*looping thrugh the reader and parsing the BES address,port and email from the file*/
while (fContent != null)
{
pos=0;
start=0;
try
{
//looking for " "
pos=fContent.IndexOf(fDelimiter,start);

//pushing pos and start variable to parse Address
BESAddress=fContent.Substring(start,pos);

//setting start position for port
start=pos+1;

//looking for " "
pos=fContent.IndexOf(fDelimiter,start);

//using pos and start variable to parse Port
BESPort=fContent.Substring(start,pos-start);

//setting start
start=pos+1;

//using length and start to parse email
Email=fContent.Substring(start,fContent.Length-start);

//logging the parsed infomation
log.Info("Sending: " + BESAddress + " " + BESPort + " " + Email);

//Verifying the parsed information
if (verifyFile(BESAddress,BESPort,Email))
{
//calling the push method to perform push
pusher.httpPush(BESAddress,BESPort,
PushTypeBox.SelectedIndex,PushNameTextBox.Text,
"http://"+PushURLTextBox.Text,"http://"+ReadIconURLTextBox.Text,
"http://"+UnreadIconURLTextBox.Text, Email);
}
else
{
MessageBox.Show("Error:The file does not have proper formatting");
return;
}

//reading line
fContent= sr.ReadLine();
}
catch(Exception t)
{
log.Info("Exception: "+ t.Message,t);
sr.Close();
return;
}
}
//closing stream reader
sr.Close();
}

The method above declares variables and performs field, file, and URL verification and validation. It then passes the Status Bar and the URL by reference to an instance of HttpPushWorker class. A text reader is then created to read through the user file.

The httpPush method in the HttpPushWorker class is then called to push the web page to the user. Each user information is read and then the URL is pushed. Once all lines have been read from the user file the reader will close the file.

How the httpPush method performs the push

The httpPush method within the HttpPushWorker.cs class first reads in the source data and then adds it to the push connection. The method will also add all necessary HTTP headers that the BlackBerry Browser uses to identify this connection as an HTTP push.

Parameters Description
BESAddress Address (or IP) of the BlackBerry Enterprise Server/BlackBerry Mobile Data Service
BESWebserverListenPort Port the BlackBerry Mobile Data Service listens on for incoming connections
typeIndex Index of the push type (PUSH_TYPES)
pushTitle Title to use for the push
url URL of the source page
readIconURL URL of the read icon to use (for channel push)
unreadIconURL URL of the unread icon to use (for channel push)
pushPin PIN or Email address of the BlackBerry device user to push to
public void httpPush(string BESAddress, string BESWebserverListenPort, int typeIndex,
string pushTitle, string url, string readIconURL, string unreadIconURL, string pushPin)
{
string pushPort = "7874";
string pushType = PUSH_TYPES[typeIndex];
status.Text = "Sending Push";

//Create the push URL for MDS

string httpURL = "http://"+BESAddress+":"+BESWebserverListenPort
+ "/push?DESTINATION=" + pushPin+"&PORT=" + pushPort + "&REQUESTURI=/";

//make the connection
//we'll put this whole thing in a try/catch block for some basic error handling.
try
{
HttpWebRequest HttpWReq = (HttpWebRequest)WebRequest.Create(httpURL);
HttpWReq.Method = ("POST");

//add the headers nessecary for the push
HttpWReq.Headers.Add("Content-Location",url);
HttpWReq.Headers.Add("X-RIM-Push-Title", pushTitle);
HttpWReq.Headers.Add("X-RIM-Push-Type",pushType);

if (pushType.Equals("Browser-Channel") || pushType.Equals("Browser-Channel-Delete"))
{
HttpWReq.Headers.Add("X-RIM-Push-Channel-ID", url);
if (pushType.Equals("Browser-Channel"))
{
HttpWReq.Headers.Add("X-RIM-Push-UnRead-Icon-URL",unreadIconURL);
HttpWReq.Headers.Add("X-RIM-Push-Read-Icon-URL", readIconURL);
}
}

//add some of the headers from the source page
int headerCount = headers.Count;


//add some of the headers from the source page
int headerCount = headers.Count;

for (int i = 0; i
{
Console.Out.WriteLine("Adding Header = "+headers.GetKey(i));
if (headers.GetKey(i).ToLower().Equals("content-type"))
{
HttpWReq.ContentType = headers.Get(i);
}
}

HttpWReq.ContentLength = data.Length;

//Getting Request stream to write data to it
Stream requestStream = HttpWReq.GetRequestStream();

//Write the data from the source
requestStream.Write(data,0,data.Length);

//get the response (this should be HTTP 200)
HttpWebResponse HttpWRes = (HttpWebResponse)HttpWReq.GetResponse();

//Update status on the Status Bar wich Is passed by reference from PushDialog.cs
if (HttpWRes.StatusCode == HttpStatusCode.OK)
{
status.Text = "Pushed";
} else {
status.Text = "Push Failed, bad response";
log.Info("Failed to Push");
}

//Close the streams
status.Text = "Closing Streams";
requestStream.Close();
HttpWRes.Close();
status.Text = "Success with "+ timesFailed + " Failures";
}
catch(System.Exception e)
{
log.Error("Push Failed "+ e.Message,e);
++timesFailed;
status.Text = "Push Failed, could not send";
}
}

In the method above, the variable PUSH_TYPES is a String array with the following structure

public static string[] PUSH_TYPES = new string[]{
"Browser-Channel","Browser-Cache",
"Browser-Message","Browser-Channel-Delete"
};

PUSH_TYPES is declared in the HttpPushWorker class. After variable declaration, a URL is created that allows the application to perform the HTTP Post necessary to push the page to the BlackBerry Mobile Data Service and the BlackBerry device. Once created, the connection to MDS is established, specific headers are added to the request.

A request stream is then obtained to write source data (web page) to the destination. When the data has been written to the stream, the response from the HTTP request is checked for status 200. The response is used to inform the user about the status of the push. The status is displayed on the status bar in PushDialog.cs.

3 comments:

Anonymous said...

Hello,
Great blog i like it
BlackBerry has beaten the laptop in this technological competition and proved to be like a laptop without weight in your hands!

blackberry application development

Mobile Application Development said...

Hello,
Nice blog i like it
The scope of the mobile phone is growing by leaps and bounds every day. The iPhones and the BlackBerries have changed the way people use the mobile.

Mobile applicationdevelopment

Android app development said...

This is one of the thoughtful post.JAVA is one of the object Oriented programming language.I like your blog clarity.Good.
Android app developers