Friday, April 3, 2015

Presenting at SATURN 2015.



I will be running an interactive session on architecting websites to handle high concurrent user load.  Will recommend two patterns that you should always keep in mind when building public facing websites.

I based some of this on the research I did for my MSDN Magazine article:
http://derricksweng.blogspot.ca/2013/02/building-simple-comet-application-using.html

Sunday, February 3, 2013

Building a simple COMET application using Microsoft.NET

MSDN Magazine published my article on using COMET principles and Microsoft.NET to implement web real-time. http://msdn.microsoft.com/en-ca/magazine/jj891053.aspx

Saturday, April 30, 2011

ASP.NET Drop down list and strongly typed DataTable

I had code where I populate the contents of an ASP.NET DropDownList with a strongly typed DataTable returned from an ASP.NET web service. In this code I bound the DataTable to the DataSource of the DropDownList and did a DataBind() in the Page_Load() method. This worked perfectly fine on my local box.

However, when I loaded up the ASP.NET page in the production data center, I got:

System.Web.HttpException: A
DropDownList cannot have multiple items selected

To solve this problem, after I bound the DataTable to the DropDownList, I iterated through each ListItem and set its Selected property to false:

foreach (ListItem myItem in myDropDownList)
{
myItem.Selected = false;
}

Wednesday, March 3, 2010

Calling an ASP.NET web service from a Java application

First, the Java application must contain a class that will encapsulate the functionality to invoke a XML web service via SOAP calls. The code is below:

import java.net.*;
import java.io.*;
import org.w3c.dom.Document;
import org.w3c.dom.*;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

public class WebServiceInvoker {
private String HTTPContinue = "^.*HTTP/[0-9].[0-9] 1[0-9][0-9].*$";
private String HTTPOk = "^.*HTTP/[0-9].[0-9] 200.*$";
private String HTTPSuccess = "^.*HTTP/[0-9].[0-9] 2[0-9][0-9].*$";
private String HTTPRedirect = "^.*HTTP/[0-9].[0-9] 3[0-9][0-9].*$";
private String HTTPClientError = "^.*HTTP/[0-9].[0-9] 4[0-9][0-9].*$";
private String HTTPServerError = "^.*HTTP/[0-9].[0-9] 5[0-9][0-9].*$";

private String _namespace;
private String _host;
private String _path;
private int _port;

private int _timeout;

/**
* @param host The server hosting the web service
* @param port The port on the server which will accept the call (default 80)
* @param wsPath The relative path of the web service on the server
* @param namespace The namespace defined in the webservice ("http://tempuri.org")
*/
public WebServiceInvoker(String host, int port, String wsPath,
String namespace) {
_host = host;
_port = port;
_path = wsPath;
_namespace = namespace;
_timeout = 60000;
}

public void setTimeout(int timeout) {
_timeout = timeout;
}

public int getTimeout() {
return _timeout;
}

public String invokeRPC(String remoteProcedure, ParameterCollection params)
throws Exception {
String result = "";

try {
String xmlData = ""
+ ""
+ "" + "<" + remoteProcedure + " xmlns=\""
+ _namespace + "\">";
for (int i = 0; i < params.size(); ++i) {
String[] sParam = params.Get(i);
if (sParam.length == 2) {
String paramName = sParam[0];
String paramValue = GeneralUtil.FixSpecialChar_forXML(sParam[1]);

xmlData += "<" + paramName + ">";
xmlData += paramValue;
xmlData += "";
} else {
System.out.println(xmlData);
throw new Exception("Poorly formatted parameter returned from Parameter Collection. WsTester.testWs");
}
}

xmlData += "" + "
"
+ "
";
InetAddress addr = InetAddress.getByName(_host);
Socket sock = new Socket(addr, _port);
sock.setSoTimeout(_timeout);

// Send header
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(sock.getOutputStream(), "UTF-8"));
wr.write("POST " + _path + " HTTP/1.1\r\n");
wr.write("Host: " + _host + "\r\n");
//wr.write("Content-Type: application/soap+xml; charset=\"utf-8\"; action=\"http://[URL to ASP.NET web service]\" \r\n");
wr.write("Content-Type: application/soap+xml; charset=\"utf-8\"; action=\"\" \r\n");
wr.write("Content-Length: " + xmlData.length() + "\r\n");
wr.write("\r\n");

// Send data
System.out.println("Soap Message:\n" + xmlData);
wr.write(xmlData);
wr.flush();

// Response
BufferedReader rd = new BufferedReader(new InputStreamReader(sock.getInputStream()));
String line = "";
String header = "";
boolean bContinue = true;
int byteCount = 0;
// Read Header
while (bContinue) {
do {
line = rd.readLine();
header += line + " ";
} while (!line.matches(""));

if (header.matches(HTTPContinue)) {
// Connection's established. Wait for the next header
header = "";
bContinue = true;
} else if (header.matches(HTTPOk)) {
// HTTP Ok. Retreive the data
byteCount = parseContentLength(header);
header = "";
bContinue = false;
} else if (header.matches(HTTPSuccess)) {
// Some other non-error success code
// Try again to see what happens, or wait until the socket
// times out
header = "";
bContinue = true;
} else if (header.matches(HTTPRedirect)) {
// Shouldn't encounter this one, but if we do I have no idea
// how to handle it
bContinue = false;
throw new Exception("HTTP Redirect encountered:\r\n"
+ header);
} else if (header.matches(HTTPClientError)) {
// Client error, most likely a Server not Found (404) or
// Forbidden (403, bad credentials).
//header = "";
bContinue = false;
throw new Exception("HTTP Client Error encountered:\r\n"
+ header);
} else if (header.matches(HTTPServerError)) {
// Server errors. Internal Service Error (500) type errors
byteCount = parseContentLength(header);
char c[] = new char[byteCount];
rd.read(c, 0, byteCount);

//header = "";
bContinue = false;

throw new Exception("HTTP Server Error encountered:\r\n" + header + "\r\n" + String.valueOf(c));
} else {
throw new Exception("Unknown HTTP header:\r\n" + header);
}
}

if (byteCount != 0) {
// Read Data
char c[] = new char[byteCount];
rd.read(c, 0, byteCount);

DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();

StringReader reader = new StringReader(String.valueOf(c)+ "\r\n");
InputSource source = new InputSource(reader);

Document doc = docBuilder.parse(source);
doc.getDocumentElement().normalize();

NodeList list = doc.getElementsByTagName(remoteProcedure + "Result");
if (list.getLength() > 0) {
result = list.item(0).getFirstChild().getNodeValue();
}
}
}

catch (Exception ex) {
System.out.println(ex.toString());
}

return result;
}

private int parseContentLength(String header) {
try {
int start = header.indexOf("Content-Length: ");
int end = header.indexOf(" ", start + 16);
String contentLine = header.substring(start, end);
contentLine = contentLine.replaceAll("^Content-Length: ", "");
contentLine = contentLine.trim();

return Integer.valueOf(contentLine).intValue();
} catch (Exception ex) {
return 0;
}
}
}

Also create a class called ParameterCollection which will hold the parameters to the web method invoked by the Java invoker:

public class ParameterCollection {
private String[][] _params;
int _index;
int _size = 10;

public ParameterCollection()
{
_params = new String[_size][2];
_index = 0;
}

public void Add(String param_name, String param_value)
{
if (_index >= _size)
{
IncreaseSize();
}

_params[_index][0] = param_name;
_params[_index][1] = param_value;

++ _index;
}

public String[] Get(int index) throws Exception
{
String[] retVal = new String[2];

if (index >= _index)
{
// Out of bounds
throw new Exception("Parameter Collection index is out of bounds: ParameterCollection.Get(" + index + ")");
}

retVal[0] = _params[index][0];
retVal[1] = _params[index][1];

return retVal;
}

public int size()
{
return _index;
}

private void IncreaseSize()
{
String[][] sOld = _params;
_size *= 2;

_params = new String[_size][2];

for (int i = 0; i < _size/2; ++i)
{
_params[i][0] = sOld[i][0];
_params[i][1] = sOld[i][1];
}
}
}


Next, after using the Visual Studio ASP.NET web service project wizard to create a web service project, add the following attribute to the class declaration of the class representing the web service:

[SoapDocumentService(RoutingStyle=SoapServiceRoutingStyle.RequestElement)]

The class declaration should look something like:
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[ToolboxItem(false)]
[SoapDocumentService(RoutingStyle=SoapServiceRoutingStyle.RequestElement)]
public class Service1 : System.Web.Services.WebService


In the java class that will invoke the web service, create an instance of the WebServiceInvoker class:

WebServiceInvoker proxy = new WebServiceInvoker(webserviceservername, port, webserviceurl);

Create a list of parameters and populate appropriately:
ParameterCollection() oColl = new ParameterCollection();
oCall.Add(“parameter1”, “value1”);

Then use this as a parameter to the invokeRPC method of the web service proxy class:

Proxy.invokeRPC(“Name of web method to call”, oCall);

In IIS, make sure the ASP.NET web service accepts anonymous connections, and set which user the anonymous connections will use to access resources.

Friday, October 23, 2009

Deploying applications to iPhone/iTouch via XCode

To complete all these steps, you must be set up as the Agent of you iPhone Developer Portal. I’m also assuming that you paid the subscription fee so that you are allowed access.

Go to http://developer.apple.com/iphone

Log in as yourself. Then click on the iPhone Developer Program Portal link.

1) Get the Development Certificate:
Create the certificate request using the Keychain Access utility on your Mac.
Submit it to the iPhone Developer Program website.
Download the generated certificate.

2) Register your device:
Go to the Devices tab in the Program Portal and register your device.

3) Create the App ID:
Click on the New App ID button.
Enter a description or name for your application.
If this is the first time creating an App ID, leave the bundle seed ID to Generate New.
Put * for the Bundle Identifier.
You will see an ID for the App created under the ID column beside the application name of your choice. Note this alphanumeric string as you will need it for later. For this example, let’s assume the App ID is 123D4EFGHI.

4) Create the Provisioning Profile:
Click on New Profile.
Enter a profile name that you will remember.
Check all the certificates you wish included, including the certificate you created in step 1.
Select the App ID you created in step 3.
Check the devices you wish to install this application on for development purposes.
Download the provisioning profile to your Mac.

5) Install the Development Certificate:
Start Keychain Access on your Mac.
Doubleclick on the login keychain on the top left hand panel, which should also be your default keychain.
Go to the File menu and select Import Items…
Select the Development Certificate downloaded in step 1, and make sure the Destination Keychain is set to login.
To ensure the certificate is correct, view it in the Certificates Category for the login keychain. There should be a widget beside it that when you click on it, a private key should appear below the certificate.

6) Installing the Provisioning Profile:
Start XCode, go to the Window menu item and click on Organizer.
Make sure you are on the Summary tab.
Under the Devices topic, you should see your device if it has been registered properly and is now attached to your Mac.
The summary panel is split into 2 halves: the top half is for your device and the bottom half is called Provisioning.
Click on the + icon in the bottom half and open the provisioning profile downloaded from step 4.
Next, in the iPhone Development topic, there should be a subtopic named Provisioning Profiles.
Click on Provisioning Profiles.
The panel on the right should be divided into 3 sections, with the top section having 2 columns: Name and Expiration Date.
Find the provisioning profile you downloaded in step 4 and drag it into the top section.

7) XCode Project Settings:
Go to Project menu item in XCode and choose Edit Project Settings.
In the settings window, select the Build tab.
Make sure the Base SDK in the Architectures section matches your device.
In Code Signing, go to the Code Signing Identity section and select Any iPhone OS Device.
The value should be the exact same as your Developer certificate’s CN, and should be of the form: iPhone Developer: Firstname Lastname (32SDKRR55I)
Go back to the Project menu and select Edit Active Target.
Click on the Properties tab.
In the Identifier field, make sure it starts with the App ID you created in step 3: for example: 123D4EFGHI.com.apple.samplecode

8) Deploy to the iPhone device
Click on the Build and Go button.

Sunday, June 7, 2009

Troubleshooting LINQ exceptions.

Once I was testing a deployment I made of an application that used LINQ to SQL, and I received the following exception when I ran it:

Exception thrown: at System.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection) at System.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj) at System.Data.SqlClient.TdsParser.Run(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj) at
System.Data.SqlClient.SqlDataReader.ConsumeMetaData() at System.Data.SqlClient.SqlDataReader.get_MetaData() at
System.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString) at System.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior,
RunBehavior runBehavior, Boolean returnStream, Boolean async) at System.Data.SqlClient.SqlCommand.RunExecuteReader
(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method, DbAsyncResult result) at System.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method) at System.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior, String method) at System.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior) at System.Data.Common.DbCommand.ExecuteReader() at System.Data.Linq.SqlClient.SqlProvider.Execute(Expression query, QueryInfo queryInfo, IObjectReaderFactory factory, Object[] parentArgs, Object[] userArgs, ICompiledSubQuery[] subQueries, Object lastResult) at System.Data.Linq.SqlClient.SqlProvider.ExecuteAll(Expression query, QueryInfo[]
queryInfos, IObjectReaderFactory factory, Object[] userArguments, ICompiledSubQuery[] subQueries) at System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(Expression query) at System.Data.Linq.DataQuery`1.System.Collections.Generic.IEnumerable.GetEnumerator() at
System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source) at Canwest.Broadcasting.Windows.Forms.Translator.translatePlaylistsForChannels() at
Canwest.Broadcasting.Windows.Forms.Translator.translateAllPlaylistFiles() at
Canwest.Broadcasting.Web.PlaylistAsrun.PlaylistAsrunService.RunTranslation() in
H:\ProgramCode\Win32_Applications\PlaylistAsrunTranslator\PlaylistAsrunASPNETWebService\PlaylistAsrunService.asmx.cs:line 151

This exception was being thrown at the point where I was dumping the results of a LINQ to SQL result set to a List by using the ToList() method. When digging deeper, I realized the result set being returned was based on a template in the LINQ designer (dbml) file, which expected the SQL table to have one more column then the table actually contained. I added the missing column to the table and the error message went away.

The lesson is: when receiving exceptions like the above, check to make sure the database tables on the database server match what is shown in the LINQ designer view. One can just use SQL Management Studio to make a graphical comparison.

Monday, May 25, 2009

Behaviour of the AutoIncrementSeed property

Oftentimes we will need to reset the seed to 0 when refilling a DataTable with new data. Due to the implementation of set_AutoIncrementSeed, we cannot just set AutoIncrementSeed = 0. We must do the following:
AutoIncrementStep = -1;
AutoIncrementSeed = 1;
AutoIncrementStep = 1;