ASP.NET Sample Application |

Version 27 - view current page

When planning where to place the integration points for your ASP.NET application, you may want to consider a Custom Web Control. As you may well know, Custom Server Controls in ASP.NET provide a hook for you to write configurable, reusable code that renders html to your ASP page. We quickly assembled an example in C# to use as a reference.


In the first part of the custom WebControl class we declare the sum of the properties needed for login and the getCell call, this way we can encapsulate the entire integration sequence using this one component:


[Bindable(true)]
[Category("UserGeneratedContent")]
[DefaultValue("")]
[Localizable(false)]
public string DeveloperSecret
{
get
{
String s = (String)ViewState["DeveloperSecret"];
return ((s == null) ? String.Empty : s);

}
set
{
ViewState["DeveloperSecret"] = value;
}
}

We expose the values for Developer Key, Developer Secret, Content Namespace, Wetpaint Api Host, User Email, User Id, User Url, User Email Opt In, and User Display Name as properties that can be set at design and/or run time. These values are all you need to add login and retrieval of an editable cell to your ASP page.

Now let's take care of the javascript needed for the cell's client calls:


protected override void OnPreRender(EventArgs e)
{
string ticket = LoginManager.ensureLogin(WetpaintApiHost, UserEmail, UserId,
UserUrl, UserEmailOptIn, UserDisplayName,
DeveloperKey, DeveloperSecret, ContentNamespace, ID);

Page.ClientScript.RegisterClientScriptInclude(typeof(Page),
"wetpaint-togo-bootstrap", WetpaintApiHost +
"/JavaScriptService/getBootstrap.do");
Page.ClientScript.RegisterClientScriptBlock(typeof(Page),
"wetpaint-togo-application",
"\t<script type=\'text/javascript\'>\r" +
"\t\tif( window.WPCAPI ) {\r" +
"\t\t\tWPCAPI.setLoginTicket('" + ticket + "');\r" +
"\t\t\tWPCAPI.setDeveloperKey('" + DeveloperKey + "');\r" +
"\t\t\tWPCAPI.setNamespace('" + ContentNamespace + "');\r" +
"\t\t}\r" +
"\t</script>\r");
base.OnPreRender(e);
}




Above, we take advantage of the Web Control's lifecycle to ensure that the javascript (found in step 3 of the integration guide) we need to write to the page is written once AND ONLY once no matter how many cells we add to a given page. We also call our LoginManager to ensure that the user has been logged in to Wetpaint.

protected override void RenderContents(HtmlTextWriter output)
{
try
{

output.Write(renderWetpaintContent());
}
catch (Exception e)
{
output.Write(e.Message);
}
}

private String renderWetpaintContent()
{
String url = WetpaintApiHost + "/WikiService/" +
"getCell.do?key=" + DeveloperKey + "&ns=" + ContentNamespace +
"&cell.cellId=" + ID + "&output=html";
HttpWebRequest request = (HttpWebRequest)WebRequest.CreateDefault(uri);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
return reader.ReadToEnd();
}




As you can see, to render the contents we make an HTTP request to retrieve the html for the cell. The login functionality called from OnPreRender is broken out into a helper class:

namespace Wetpaint_ToGo
{
public class LoginManager
{
private static String WetpaintTicket = "WetpaintTogoTicket";

public static String ensureLogin(String hostName, String userEmail, String userId,
String userUrl, String userEmailOptIn, String userDisplayName,
String developerKey, String developerSecret, String contentNamespace,
String cellId)
{
HttpContext context = HttpContext.Current;
String ticket = null;
if (context.Session[WetpaintTicket] == null)
{
TimeSpan ts = (DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0));
long unixTime = (long)ts.TotalSeconds;
String sigString = "key=" + developerKey + "&ts=" + unixTime + developerSecret;
SHA1 sha = new SHA1CryptoServiceProvider();
UTF8Encoding encoding = new UTF8Encoding();
byte[] sigHash = sha.ComputeHash(encoding.GetBytes(sigString));
string encodedSigString = GetAsHexaDecimal(sigHash);
string url = hostName + "/UserService/login.do";
string data = "key=" + developerKey + "&ns=" + contentNamespace +
"&output=api&user.userId=" +
userId + "&user.email=" + userEmail + "&user.emailOptIn=" +
userEmailOptIn + "&cred.ts=" + unixTime + "&cred.sig=" + encodedSigString +
"&user.profileUrl=" + userUrl + "&user.displayName=" + userDisplayName;
string encodedData = HttpUtility.UrlEncode(data);
Uri uri = new Uri(url);
HttpWebRequest request = (HttpWebRequest)WebRequest.CreateDefault(uri);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
request.ContentLength = data.Length;
StreamWriter writer = new StreamWriter(request.GetRequestStream());
writer.Write(data);
writer.Close();
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string responseString = reader.ReadToEnd();
if (!responseString.Contains("<ticket>"))
{
//throw an exception
}
else
{
String[] tokens = {"<ticket>", "</ticket>"};
String[] splits = responseString.Split(tokens, StringSplitOptions.RemoveEmptyEntries);
ticket = splits[1];
context.Session[WetpaintTicket] = ticket;
}
}
else
{
ticket = (String)context.Session[WetpaintTicket];
}
return ticket;
}

public static void logout()
{
HttpContext context = HttpContext.Current;
context.Session[WetpaintTicket] = null;
}

public static string GetAsHexaDecimal(byte[] bytes)
{
StringBuilder s = new StringBuilder();
int length = bytes.Length;
for (int n = 0; n < length; n++)
{
s.Append(String.Format("{0,2:x}", bytes[n]).Replace(" ", "0"));
}
return s.ToString();
}

}
}

The ensureLogin method checks the user session for a Wetpaint ticket. If the ticket is present in the session, it is returned. If the ticket is not present, an HTTP POST login request is made of the Wetpaint servers to retrieve a new ticket. The new ticket is added to the session and returned.

Warning: When converting the sha1 hash from byte array to hexadecimal string, be aware that .NET produces an array of unsigned bytes from the ComputeHash method. Java uses signed bytes (we use Java at wetpaint), when working in .NET take care of that fact when creating a hexadecimal string from the hash byte array. Use our GetAsHexaDecimal(byte[] bytes) method as an example.