Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Posting image from .NET to Facebook wall using the Graph API

I'm using the Facebooks Javascript API to develop an application that will need to be able to post an image to a users wall. That part of the app needs to be server-side as far as I can tell, since it needs to post the image data as "multipart/form-data".

Note: It's not the simple version using "post", but the real "photos" method.

http://graph.facebook.com/me/photos

I think I'm facing two problems, a .NET and a Facebook problem:

Facebook problem: I'm not quite sure if all parameters should be send as multipart/form-data (including the access_token and message). The only code example there is uses the cUrl util/application.

.NET problem: I have never issued multipart/form-data requests from .NET , and I'm not sure if .NET automatically creates the mime-parts, or if I have to encode the parameters in some special way.

It's a bit hard to debug, since the only error response I get from the Graph API is "400 - bad request". Below is the code as it looked when I decided to write this question (yes, it's a bit verbose :-)

The ultimate answer would of course be a sample snippet posting an image from .NET, but I can settle for less.

string username = null;
string password = null;
int timeout = 5000;
string requestCharset = "UTF-8";
string responseCharset = "UTF-8";
string parameters = "";
string responseContent = "";

string finishedUrl = "https://graph.facebook.com/me/photos";

parameters = "access_token=" + facebookAccessToken + "&message=This+is+an+image";
HttpWebRequest request = null;
request = (HttpWebRequest)WebRequest.Create(finishedUrl);
request.Method = "POST";
request.KeepAlive = false;
//application/x-www-form-urlencoded | multipart/form-data
request.ContentType = "multipart/form-data";
request.Timeout = timeout;
request.AllowAutoRedirect = false;
if (username != null && username != "" && password != null && password != "")
{
    request.PreAuthenticate = true;
    request.Credentials = new NetworkCredential(username, password).GetCredential(new Uri(finishedUrl), "Basic");
}
//write parameters to request body
Stream requestBodyStream = request.GetRequestStream();
Encoding requestParameterEncoding = Encoding.GetEncoding(requestCharset);
byte[] parametersForBody = requestParameterEncoding.GetBytes(parameters);
requestBodyStream.Write(parametersForBody, 0, parametersForBody.Length);
/*
This wont work
byte[] startParm = requestParameterEncoding.GetBytes("&source=");
requestBodyStream.Write(startParm, 0, startParm.Length);
byte[] fileBytes = File.ReadAllBytes(Server.MapPath("images/sample.jpg"));
requestBodyStream.Write( fileBytes, 0, fileBytes.Length );
*/
requestBodyStream.Close();

HttpWebResponse response = null;
Stream receiveStream = null;
StreamReader readStream = null;
Encoding responseEncoding = System.Text.Encoding.GetEncoding(responseCharset);
try 
{
    response = (HttpWebResponse) request.GetResponse();
    receiveStream = response.GetResponseStream();
    readStream = new StreamReader( receiveStream, responseEncoding );
    responseContent = readStream.ReadToEnd();
}
finally 
{
    if (receiveStream != null)
    {
        receiveStream.Close();
    }
    if (readStream != null)
    {
        readStream.Close();
    }
    if (response != null)
    {
        response.Close();
    }
}
like image 382
Torben Warberg Rohde Avatar asked Feb 04 '11 14:02

Torben Warberg Rohde


1 Answers

Here is a sample of how to upload binary data. But an uploading to /me/photos won't publish the image into wall :( The image saving into your app's album. I'm stuck on how to announce it in the feed. Yet another way is to post an image into "Wall Album", by URL=="graph.facebook.com/%wall-album-id%/photos". But didn't found any way to create sucha album (user creates it when uploading an image via the site).

{
    string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
    uploadRequest = (HttpWebRequest)WebRequest.Create(@"https://graph.facebook.com/me/photos");
    uploadRequest.ServicePoint.Expect100Continue = false;
    uploadRequest.Method = "POST";
    uploadRequest.UserAgent = "Mozilla/4.0 (compatible; Windows NT)";
    uploadRequest.ContentType = "multipart/form-data; boundary=" + boundary;
    uploadRequest.KeepAlive = false;

    StringBuilder sb = new StringBuilder();

    string formdataTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n";
    sb.AppendFormat(formdataTemplate, boundary, "access_token", PercentEncode(facebookAccessToken));
    sb.AppendFormat(formdataTemplate, boundary, "message", PercentEncode("This is an image"));

    string headerTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n";
    sb.AppendFormat(headerTemplate, boundary, "source", "file.png", @"application/octet-stream");

    string formString = sb.ToString();
    byte[] formBytes = Encoding.UTF8.GetBytes(formString);
    byte[] trailingBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");

    long imageLength = imageMemoryStream.Length;
    long contentLength = formBytes.Length + imageLength + trailingBytes.Length;
    uploadRequest.ContentLength = contentLength;

    uploadRequest.AllowWriteStreamBuffering = false;
    Stream strm_out = uploadRequest.GetRequestStream();

    strm_out.Write(formBytes, 0, formBytes.Length);

    byte[] buffer = new Byte[checked((uint)Math.Min(4096, (int)imageLength))];
    int bytesRead = 0;
    int bytesTotal = 0;
    imageMemoryStream.Seek(0, SeekOrigin.Begin);
    while ((bytesRead = imageMemoryStream.Read(buffer, 0, buffer.Length)) != 0)
    {
        strm_out.Write(buffer, 0, bytesRead); bytesTotal += bytesRead;
        gui.OnUploadProgress(this, (int)(bytesTotal * 100 / imageLength));
    }

    strm_out.Write(trailingBytes, 0, trailingBytes.Length);

    strm_out.Close();

    HttpWebResponse wresp = uploadRequest.GetResponse() as HttpWebResponse;
}
like image 156
fltz Avatar answered Oct 03 '22 14:10

fltz