Image cache refreshing

Jul 10, 2007 at 9:42 AM
The image cache is driving me mad, as I keep having to rename some of my images to get them to update on the user profile widget for my app, and that's not really an option all the time.

I can't find a way to clear the facebook image cache for a given url in the .net wrapper you guys have created. The default facebook interface apparently has a facebook.fbml.refreshImgSrc('imgURL') call, though it's undocumented and only mentioned in the dev wiki here: http://wiki.developers.facebook.com/index.php/UsageNotes/Images.

Am I missing something, or is it just not implemented in the .NET wrapper?

Coordinator
Jul 10, 2007 at 2:16 PM
Just not implemented, since this is the first I/we have heard of it. I'll add an issue, and we will get it added.

Jul 10, 2007 at 4:11 PM
Thanks! It's just one of those useful development tools which seems to have no documentation. I look forward to this addition, and in the meantime keep renaming images :(
Jul 12, 2007 at 7:23 PM
If you'd like a slightly better temporary fix, I put together this "Extended Facebook API" class that uses a lot of code from the Facebook client library. I needed the RefreshRefUrl so you'll see that in my class but not RefreshImgSrc. But if you copy-paste my function as a starting point then you should be able to support RefreshImgSrc with minimal tweaking.

Here is the sample usage:
ExtendedFacebookAPI exFacebook = new ExtendedFacebookAPI(FBAPPLICATIONKEY, "1.0", FB_SECRET, _fbService.SessionKey);
Response.Output.Write("Refresh Result: " + exFacebook.RefreshRefUrl(fbRefUrl));

Note that this requires you to have an authenticated session's sessionKey. There is some discussion on the FB boards around workarounds for this...


Ryan - I'll try to message you about contributing the useful part of this source (the new function) into the tree. I'm also curious about why I can't seem to compile the DLLs on my box. The first error is around loading version 1.0.61025.0 of System.Web.Extensions! I saw your discussion on the boards about playing with different .net versions but haven't had time to follow those yet...

-------------------
using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Globalization;
using System.Security.Cryptography;
using System.Text;
using System.Collections.Generic;
using System.Net;
using System.IO;
using System.Xml;


/// <summary>
/// Summary description for ExtendedFacebookAPI
/// </summary>
public class ExtendedFacebookAPI
{
String _applicationKey;
String _version;
String _secret;
String _sessionKey = null;

String RESOURCEFACEBOOKNAMESPACE = "http://api.facebook.com/1.0/";

XmlNamespaceManager _nsManager;

public ExtendedFacebookAPI(String applicationKey, String version, String secret)
{
_applicationKey = applicationKey;
_version = version;
_secret = secret;
}



public ExtendedFacebookAPI(String applicationKey, String version, String secret, String sessionKey)
{
_applicationKey = applicationKey;
_version = version;
_secret = secret;
_sessionKey = sessionKey;
}



internal List<string> ParameterDictionaryToList(IEnumerable<KeyValuePair<string, string>> parameterDictionary)
{
List<string> parameters = new List<string>();

foreach (KeyValuePair<string, string> kvp in parameterDictionary)
{
parameters.Add(String.Format(CultureInfo.InvariantCulture, "{0}", kvp.Key));
}
return parameters;
}

/// <summary>
/// This method generates the signature based on parameters supplied
/// </summary>
/// <param name="parameters">List of paramenters</param>
/// <returns>Generated signature</returns>
internal string GenerateSignature(IDictionary<string, string> parameters)
{
StringBuilder signatureBuilder = new StringBuilder();
// Sort the keys of the method call in alphabetical order
List<string> keyList = ParameterDictionaryToList(parameters);
keyList.Sort();
// Append all the parameters to the signature input paramaters
foreach (string key in keyList)
signatureBuilder.Append(String.Format(CultureInfo.InvariantCulture, "{0}={1}", key, parameterskey));

// Append the secret to the signature builder
signatureBuilder.Append(_secret);
byte[] hash;

MD5 md5 = MD5.Create();
// Compute the MD5 hash of the signature builder
hash = md5.ComputeHash(Encoding.Default.GetBytes(
signatureBuilder.ToString().Trim()));

// Reinitialize the signature builder to store the actual signature
signatureBuilder = new StringBuilder();

// Append the hash to the signature
foreach (byte hashByte in hash)
signatureBuilder.Append(hashByte.ToString("x2", CultureInfo.InvariantCulture));

return signatureBuilder.ToString();
}


internal string CreateHTTPParameterList(IDictionary<string, string> parameterList)
{
StringBuilder queryBuilder = new StringBuilder();

parameterList.Add("api_key", _applicationKey);
parameterList.Add("v", _version);
parameterList.Add("call_id", DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture));
parameterList.Add("sig", GenerateSignature(parameterList));

// Build the query
foreach (KeyValuePair<string, string> kvp in parameterList)
{
queryBuilder.Append(kvp.Key);
queryBuilder.Append("=");
queryBuilder.Append(HttpUtility.UrlEncode(kvp.Value));
queryBuilder.Append("&");
}
queryBuilder.Remove(queryBuilder.Length - 1, 1);

return queryBuilder.ToString();
}




/// <summary>
/// Get Query Response
/// </summary>
/// <param name="requestUrl">Request Url</param>
/// <param name="postString">posted query</param>
/// <returns>Response data</returns>
internal static string GetQueryResponse(string requestUrl, string postString)
{
// Create a web request for input path.
WebRequest webRequest = WebRequest.Create(requestUrl);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";

if (!String.IsNullOrEmpty(postString))
{
byte[] parameterString = Encoding.ASCII.GetBytes(postString);
webRequest.ContentLength = parameterString.Length;

using (Stream buffer = webRequest.GetRequestStream())
{
buffer.Write(parameterString, 0, parameterString.Length);
buffer.Close();
}
}

WebResponse webResponse = webRequest.GetResponse();

string responseData;
using (StreamReader streamReader = new StreamReader(webResponse.GetResponseStream()))
{
responseData = streamReader.ReadToEnd();
}
return responseData;
}



internal XmlDocument LoadXMLDocument(string rawXML)
{
// Parse the data and extract the session details
XmlDocument xmlDocument = new XmlDocument();

xmlDocument.LoadXml(rawXML);

_nsManager = new XmlNamespaceManager(xmlDocument.NameTable);
nsManager.AddNamespace("Facebook", RESOURCEFACEBOOK_NAMESPACE);

ErrorCheck(xmlDocument);
return xmlDocument;
}


/// <summary>
/// Parse the Facebook result for an error, and throw an exception.
/// For some of the different types of exceptions, custom action might be desirable.
/// </summary>
/// <param name="doc">The XML result.</param>
internal static void ErrorCheck(XmlDocument doc)
{
XmlNodeList errorNodes = doc.GetElementsByTagName("error_response");
String errList = "";

if (errorNodes.Count > 0)
{
foreach (XmlNode errNode in errorNodes)
{
errList = errNode.OuterXml;
}
throw new Exception("Facebook Exception: " + errList );
}
}



internal string ExecuteApiCallString(IDictionary<string, string> parameterDictionary, bool useSession)
{
if (useSession)
{
if (null == _sessionKey)
return "<error>Error: not using an authenticated session when needed in ExtendedFacebookAPI</error>";
parameterDictionary.Add("session_key", _sessionKey);
}

string requestUrl = "http://api.facebook.com/bestserver.php";
string parameters = CreateHTTPParameterList(parameterDictionary);
return GetQueryResponse(requestUrl, parameters);
}


public string RefreshRefUrl(string url)
{
string results = string.Empty;

Dictionary<string, string> parameterList = new Dictionary<string, string>(3);
parameterList.Add("method", "facebook.fbml.refreshRefUrl");
parameterList.Add("url", string.Format(CultureInfo.InstalledUICulture, url));

string xml = ExecuteApiCallString(parameterList, true);
if (!String.IsNullOrEmpty(xml))
{
XmlDocument xmlDocument = LoadXMLDocument(xml);

XmlNodeList nodeList = xmlDocument.GetElementsByTagName("fbmlrefreshRefURLresponse");

if (nodeList != null && nodeList.Count > 0)
{
if (nodeList0.HasChildNodes)
{
results = nodeList0.InnerText;
}
}
}


return results;
}

}