【问题标题】:Posting image from .NET to Facebook wall using the Graph API使用 Graph API 将图像从 .NET 发布到 Facebook 墙上
【发布时间】:2011-06-21 09:37:33
【问题描述】:

我正在使用 Facebook 的 Javascript API 开发一个需要能够将图像发布到用户墙上的应用程序。 据我所知,应用程序的该部分需要在服务器端,因为它需要将图像数据发布为“multipart/form-data”。

注意:不是使用“post”的简单版本,而是真正的“photos”方法。

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

我认为我面临两个问题,一个 .NET 和一个 Facebook 问题:

Facebook 问题:我不太确定是否所有参数都应作为 multipart/form-data(包括 access_token 和消息)发送。唯一的代码示例使用 cUrl util/application。

.NET 问题:我从未从 .NET 发出 multipart/form-data 请求,我不确定 .NET 是否会自动创建 mime-parts,或者我是否必须进行编码以某种特殊方式的参数。

调试有点困难,因为我从 Graph API 得到的唯一错误响应是“400 - 错误请求”。 下面是我决定写这个问题时的代码(是的,它有点冗长:-)

最终的答案当然是从 .NET 发布图像的示例 sn-p,但我可以接受更少。

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();
    }
}

【问题讨论】:

    标签: c# .net facebook facebook-graph-api


    【解决方案1】:

    这里是如何上传二进制数据的示例。但是上传到 /me/photos 不会将图像发布到墙上 :( 图像保存到您的应用程序的相册中。我不知道如何在提要中宣布它。另一种方法是将图像发布到“墙相册”,通过 URL=="graph.facebook.com/%wall-album-id%/photos"。但没有找到任何方法来创建这样的相册(用户在上传图片来自网站)。

    {
        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;
    }
    

    【讨论】:

    • 谢谢@fltz。通过调整您的示例(在 sn-p 范围之外声明的一些变量)设法使其工作。
    • 您的应用程序是将图像发布到墙上还是仅将其上传到应用程序的相册中?在我的测试中,在墙上/提要上没有看到上传的图像。
    • 我还没有开始。到目前为止,我只在创建应用程序的默认相册时在墙上看到它。但根据this post 应该是可以的。
    • 我在这里回答“如何在自己的时间线上发布照片”的问题。查看何时将某些照片发布到时间线,它遵循 2 个步骤 1. 将照片添加到相册“Timeline_Photos” 2. 发布带有照片(上方)ID 的新帖子(提要),以便它可以显示为缩略图。在使用 Graph API 时,我们还必须遵循相同的步骤 1. POST /version/me/photos 2. POST /version/me/feed
    【解决方案2】:

    使用@fitz 的代码清理了类方法。传入图像的字节数组或文件路径。如果上传到现有专辑,则传入专辑 ID。

    public string UploadPhoto(string album_id, string message, string filename, Byte[] bytes, string Token)
    {
        // Create Boundary
        string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x");
    
        // Create Path
        string Path = @"https://graph.facebook.com/";
        if (!String.IsNullOrEmpty(album_id))
        {
            Path += album_id + "/";
        }
        Path += "photos";
    
        // Create HttpWebRequest
        HttpWebRequest uploadRequest;
        uploadRequest = (HttpWebRequest)HttpWebRequest.Create(Path);
        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;
    
        // New String Builder
        StringBuilder sb = new StringBuilder();
    
        // Add Form Data
        string formdataTemplate = "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}\r\n";
    
        // Access Token
        sb.AppendFormat(formdataTemplate, boundary, "access_token", HttpContext.Current.Server.UrlEncode(Token));
    
        // Message
        sb.AppendFormat(formdataTemplate, boundary, "message", message);
    
        // Header
        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", filename, @"application/octet-stream");
    
        // File
        string formString = sb.ToString();
        byte[] formBytes = Encoding.UTF8.GetBytes(formString);
        byte[] trailingBytes = Encoding.UTF8.GetBytes("\r\n--" + boundary + "--\r\n");
        byte[] image;
        if (bytes == null)
        {
            image = File.ReadAllBytes(HttpContext.Current.Server.MapPath(filename));
        }
        else
        {
            image = bytes; 
        }
    
        // Memory Stream
        MemoryStream imageMemoryStream = new MemoryStream();
        imageMemoryStream.Write(image, 0, image.Length);
    
        // Set Content Length
        long imageLength = imageMemoryStream.Length;
        long contentLength = formBytes.Length + imageLength + trailingBytes.Length;
        uploadRequest.ContentLength = contentLength;
    
        // Get Request Stream
        uploadRequest.AllowWriteStreamBuffering = false;
        Stream strm_out = uploadRequest.GetRequestStream();
    
        // Write to Stream
        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;
        }
        strm_out.Write(trailingBytes, 0, trailingBytes.Length);
    
        // Close Stream
        strm_out.Close();
    
        // Get Web Response
        HttpWebResponse response = uploadRequest.GetResponse() as HttpWebResponse;
    
        // Create Stream Reader
        StreamReader reader = new StreamReader(response.GetResponseStream());
    
        // Return
        return reader.ReadToEnd();
    }
    

    【讨论】:

      【解决方案3】:

      您必须使用字节数组自己构造多部分/表单数据。 无论如何,我已经这样做了。您可以通过http://computerbeacon.net/ 查看 Facebook Graph Toolkit。我会在几天内将工具包更新到 0.8 版,其中将包括“将照片发布到 facebook 墙”功能以及其他新功能和更新。

      【讨论】:

      • 谢谢 - 期待试一试。
      • 无法访问此站点
      【解决方案4】:

      我可以使用RestSharp发布图片:

      // url example: https://graph.facebook.com/you/photos?access_token=YOUR_TOKEN
      request.AddFile("source", imageAsByteArray, openFileDialog1.SafeFileName, getMimeType(Path.GetExtension(openFileDialog1.FileName)));
      request.addParameter("message", "your photos text here");
      

      User APIPage API 用于发布照片

      How to convert Image to Byte Array

      注意:我传递了一个空字符串作为 mime 类型,而 facebook 足够聪明,可以弄清楚。

      【讨论】:

        【解决方案5】:

        也许有用

                [TestMethod]
                [DeploymentItem(@".\resources\velas_navidad.gif", @".\")]
                public void Post_to_photos()
                {
                    var ImagePath = "velas_navidad.gif";
                    Assert.IsTrue(File.Exists(ImagePath));
        
                    var client = new FacebookClient(AccessToken);
                    dynamic parameters = new ExpandoObject();
        
                    parameters.message = "Picture_Caption";
                    parameters.subject = "test 7979";
                    parameters.source = new FacebookMediaObject
        {
            ContentType = "image/gif",
            FileName = Path.GetFileName(ImagePath)
        }.SetValue(File.ReadAllBytes(ImagePath));
        
                    //// Post the image/picture to User wall
                    dynamic result = client.Post("me/photos", parameters);
                    //// Post the image/picture to the Page's Wall Photo album
                    //fb.Post("/368396933231381/", parameters); //368396933231381 is Album id for that page.
        
                    Thread.Sleep(15000);
                    client.Delete(result.id);
                }
        

        参考: Making Requests

        【讨论】:

          猜你喜欢
          • 2012-12-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-30
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多