在 .NET 中的 picasa 中创建新相册

发布于 2024-12-03 14:37:52 字数 1452 浏览 1 评论 0 原文

我尝试将相册发布到 picasa,但总是收到“错误请求”响应。 我应该使用 HttpRequest 类吗?

System.Net.WebClient wc = new System.Net.WebClient();
wc.Headers.Add("Authorization", "AuthSub token=\"" + token + "\"");
wc.Headers.Add("GData-Version", "2");

string data =   "<entry xmlns='http://www.w3.org/2005/Atom' " +
                        "xmlns:media='http://search.yahoo.com/mrss/' " +
                        "xmlns:gphoto='http://schemas.google.com/photos/2007'>" +
                    "<title type='text'>" + name + "</title>" +
                    "<summary type='text'>" + descr + "</summary>" +
                    "<gphoto:location>asd</gphoto:location>" +
                    "<gphoto:access>" + access + "</gphoto:access>" +
                    "<gphoto:timestamp>1152255600000</gphoto:timestamp>" +
                    "<media:group>" +
                        "<media:keywords>adds</media:keywords>" +
                    "</media:group>" +
                    "<category scheme='http://schemas.google.com/g/2005#kind' " +
                        "term='http://schemas.google.com/photos/2007#album'></category>" +
                "</entry>";


try
{
    string response = wc.UploadString("https://picasaweb.google.com/data/feed/api/user/default", "post", data);
    return response;
}

catch (Exception e)
{
    return e.ToString();
}

I am trying to post an album to picasa, but always get "bad request" response.
Should I use HttpRequest class instead?

System.Net.WebClient wc = new System.Net.WebClient();
wc.Headers.Add("Authorization", "AuthSub token=\"" + token + "\"");
wc.Headers.Add("GData-Version", "2");

string data =   "<entry xmlns='http://www.w3.org/2005/Atom' " +
                        "xmlns:media='http://search.yahoo.com/mrss/' " +
                        "xmlns:gphoto='http://schemas.google.com/photos/2007'>" +
                    "<title type='text'>" + name + "</title>" +
                    "<summary type='text'>" + descr + "</summary>" +
                    "<gphoto:location>asd</gphoto:location>" +
                    "<gphoto:access>" + access + "</gphoto:access>" +
                    "<gphoto:timestamp>1152255600000</gphoto:timestamp>" +
                    "<media:group>" +
                        "<media:keywords>adds</media:keywords>" +
                    "</media:group>" +
                    "<category scheme='http://schemas.google.com/g/2005#kind' " +
                        "term='http://schemas.google.com/photos/2007#album'></category>" +
                "</entry>";


try
{
    string response = wc.UploadString("https://picasaweb.google.com/data/feed/api/user/default", "post", data);
    return response;
}

catch (Exception e)
{
    return e.ToString();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浊酒尽余欢 2024-12-10 14:37:52

Google 为 picasa [.net] 集成提供了一个方便的 api:

http:// code.google.com/apis/picasaweb/docs/1.0/developers_guide_dotnet.html

手动编写所有代码毫无意义!

这是一些代码(vb.net,但很简单):

Public Shared Function CreateAlbum(ByVal albumTitle As String) As AlbumAccessor

    Dim newAlbum As New AlbumEntry()
    newAlbum.Title.Text = albumTitle

    Dim ac As New AlbumAccessor(newAlbum)
    ac.Access = "public"

    Dim feedUri As New Uri(PicasaQuery.CreatePicasaUri(ConfigurationManager.AppSettings("GData_Email")))
    Dim albumEntry As PicasaEntry = CreateAuthenticatedRequest().Insert(feedUri, newAlbum)

    Return New AlbumAccessor(albumEntry)

End Function

Public Shared Function CreateAuthenticatedRequest() As PicasaService
    Dim service As New PicasaService(ConfigurationManager.AppSettings("GData_AppName"))
    service.setUserCredentials(ConfigurationManager.AppSettings("GData_Email"), ConfigurationManager.AppSettings("GData_Password"))
    Return service
End Function

Google makes a handy api for picasa [.net] integration:

http://code.google.com/apis/picasaweb/docs/1.0/developers_guide_dotnet.html

No sense writing all that code by hand!

Here is some code (vb.net, but it's straightforward):

Public Shared Function CreateAlbum(ByVal albumTitle As String) As AlbumAccessor

    Dim newAlbum As New AlbumEntry()
    newAlbum.Title.Text = albumTitle

    Dim ac As New AlbumAccessor(newAlbum)
    ac.Access = "public"

    Dim feedUri As New Uri(PicasaQuery.CreatePicasaUri(ConfigurationManager.AppSettings("GData_Email")))
    Dim albumEntry As PicasaEntry = CreateAuthenticatedRequest().Insert(feedUri, newAlbum)

    Return New AlbumAccessor(albumEntry)

End Function

Public Shared Function CreateAuthenticatedRequest() As PicasaService
    Dim service As New PicasaService(ConfigurationManager.AppSettings("GData_AppName"))
    service.setUserCredentials(ConfigurationManager.AppSettings("GData_Email"), ConfigurationManager.AppSettings("GData_Password"))
    Return service
End Function
昇り龍 2024-12-10 14:37:52

我知道这是较旧的,所以你可能已经有了答案。我也知道 Google 确实制作了一个 API,但对于 .net,它仅适用于 Picasa 的第一个版本,而您正在尝试使用第二个版本,就像我一样。我看到了您的帖子,并认为我可以为您提供答案如果您仍在尝试解决此问题,或者其他人看到该帖子并想要答案。

我发现有几件事可能会导致您的问题。首先,您似乎将身份验证协议与版本混合和匹配。对于第二个版本的 Google Picasa API,我相信您需要使用 OAuth2 协议,而不是 AuthSub 协议。我还没有尝试过 AuthSub。第二个问题是,我不认为您的标头中包含足够的信息(缺少内容长度、内容类型和主机[尽管使用网络客户端时可能不需要主机])。我发现确保我的请求正常运行(老实说是救星)的一种方法是访问 Google 上的 OAuth2Playground:Oauth2Playground。您可以在此处创建令牌和请求,并在成功发出请求时轻松查看其标头和发布信息。

这是我编写的一段代码,用于创建相册。为了创建,您必须拥有带有访问代码的经过身份验证的令牌(您需要首先获取用户权限并存储其刷新令牌,然后刷新以获取会话 access_token) access_token 在标头的授权行中传递。它还解析响应并从响应中获取成功变量以及专辑。专辑的整个 xml feed 都会在响应时返回,因此如果需要,您可以详细阅读并直接使用它)

public bool CreatePicasaAlbum(GoogleUtility.Picasa.AlbumEntry.entry a, IGoogleOauth2AccessToken token)
    {


        TcpClient client = new TcpClient(picasaweb.google.com, 443);
        Stream netStream = client.GetStream();
        SslStream sslStream = new SslStream(netStream);
        sslStream.AuthenticateAsClient(picasaweb.google.com);

        byte[] contentAsBytes = Encoding.ASCII.GetBytes(a.toXmlPostString());
        string data = a.toXmlPostString();

        StringBuilder msg = new StringBuilder();
        msg.AppendLine("POST /data/feed/api/user/default HTTP/1.1");
        msg.AppendLine("Host: picasaweb.google.com");
        msg.AppendLine("Gdata-version: 2");
        msg.AppendLine("Content-Length: " + data.Length);
        msg.AppendLine("Content-Type: application/atom+xml");
        msg.AppendLine(string.Format(GetUserInfoDataString(), token.access_token));
        msg.AppendLine("");

        byte[] headerAsBytes = Encoding.ASCII.GetBytes(msg.ToString());
        sslStream.Write(headerAsBytes);
        sslStream.Write(contentAsBytes);

        StreamReader reader = new StreamReader(sslStream);
        bool success = false;
        string albumID = "";
        while (reader.Peek() > 0)
        {  
            string line = reader.ReadLine();
            if (line.Contains("HTTP/1.1 201 Created")) { success = true; }
            if (line.Contains("Location: https") && string.IsNullOrWhiteSpace(albumID))
            {
                var aiIndex = line.LastIndexOf("/");
                albumID = line.Substring(aiIndex + 1);
            }
            System.Diagnostics.Debug.WriteLine(line);
            if (line == null) break;
        }
        return success;
    }

/// <summary>
/// User Info Data String for Authorization on TCP requests
/// [Authorization: OAuth {0}"]
/// </summary>
/// <returns></returns>

private string GetUserInfoDataString()
{
    return "Authorization: OAuth {0}";
}

抱歉,我应该补充一点,我创建了一个返回专辑 feed 字符串的对象像上面那样输入 xml。 feed xml 与文档匹配。我将时间戳留空,因为默认时间戳是您创建时间戳时的,而且我还没有弄清楚是否可以将任何内容放入类别中,所以我也将其留空。

<entry xmlns='http://www.w3.org/2005/Atom' xmlns:media='http://search.yahoo.com/mrss/' xmlns:gphoto='http://schemas.google.com/photos/2007'>
    <title type='text'>Created from code</title>
    <summary type='text'>Code created this album</summary>     
    <gphoto:location>somewhere</gphoto:location>
    <gphoto:access>public</gphoto:access>
    <gphoto:timestamp></gphoto:timestamp>
    <media:group>
        <media:keywords>test, album, fun</media:keywords>
    </media:group>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/photos/2007#album'>
    </category>
</entry>

另一项编辑: IGoogleOauth2AccessToken 是我创建的另一个类,用于容纳令牌详细信息。您真正需要传入的是刷新 OAuth2 令牌时获得的 access_token 字符串。我的令牌住房代码只有 access_code、token_type,并且作为对象的一部分过期。您只需要访问令牌字符串即可进行授权。

I know this is older so you may already have an answer. I also know that Google does make an API but with .net it only works for the first version of Picasa and you are trying to work with version two, as am I. I came across your post and thought I would offer an answer for you in case you are still trying to work this out or someone else comes across the post and wants an answer.

I see a couple of things that may be causing your issue. The first is that you seem to be mixing and matching the authentication protocol with the version. For the second version of the Google Picasa API, I believe you need to be using OAuth2 protocol, not AuthSub protocol. I haven't tried with AuthSub. The second issue is that I do not believe you have enough information in your headers (missing content-length, content-type, and host[although you may not need host when using a webclient]). One way that I've found to make sure that my requests are working well (and honestly has been a lifesaver) is to go to the OAuth2Playground on Google: Oauth2Playground. Here you can create your tokens and requests and easily see their headers and post information when successful requests are made.

Here is a snippet of code that I wrote which allows for creation of an album. In order to create, you must have an authenticated token with an access code (you would want to first get user permissions and store their refresh token and then refresh to get the session access_token) The access_token is passed in the authorization line of the header. It also parses the response and gets a success variable from the response as well as the albumid. The entire xml feed for the album is returned on response, so you could go into the detail of reading that in and working with it directly if you wanted)

public bool CreatePicasaAlbum(GoogleUtility.Picasa.AlbumEntry.entry a, IGoogleOauth2AccessToken token)
    {


        TcpClient client = new TcpClient(picasaweb.google.com, 443);
        Stream netStream = client.GetStream();
        SslStream sslStream = new SslStream(netStream);
        sslStream.AuthenticateAsClient(picasaweb.google.com);

        byte[] contentAsBytes = Encoding.ASCII.GetBytes(a.toXmlPostString());
        string data = a.toXmlPostString();

        StringBuilder msg = new StringBuilder();
        msg.AppendLine("POST /data/feed/api/user/default HTTP/1.1");
        msg.AppendLine("Host: picasaweb.google.com");
        msg.AppendLine("Gdata-version: 2");
        msg.AppendLine("Content-Length: " + data.Length);
        msg.AppendLine("Content-Type: application/atom+xml");
        msg.AppendLine(string.Format(GetUserInfoDataString(), token.access_token));
        msg.AppendLine("");

        byte[] headerAsBytes = Encoding.ASCII.GetBytes(msg.ToString());
        sslStream.Write(headerAsBytes);
        sslStream.Write(contentAsBytes);

        StreamReader reader = new StreamReader(sslStream);
        bool success = false;
        string albumID = "";
        while (reader.Peek() > 0)
        {  
            string line = reader.ReadLine();
            if (line.Contains("HTTP/1.1 201 Created")) { success = true; }
            if (line.Contains("Location: https") && string.IsNullOrWhiteSpace(albumID))
            {
                var aiIndex = line.LastIndexOf("/");
                albumID = line.Substring(aiIndex + 1);
            }
            System.Diagnostics.Debug.WriteLine(line);
            if (line == null) break;
        }
        return success;
    }

/// <summary>
/// User Info Data String for Authorization on TCP requests
/// [Authorization: OAuth {0}"]
/// </summary>
/// <returns></returns>

private string GetUserInfoDataString()
{
    return "Authorization: OAuth {0}";
}

Sorry, I should add that I created an object that returns the feed string for the album entry xml as you had above. The feed xml matches the documentation. I leave the timestamp blank as the default stamp is when you create it, and I've not figured out what if anything can be put in category so I leave that blank too.

<entry xmlns='http://www.w3.org/2005/Atom' xmlns:media='http://search.yahoo.com/mrss/' xmlns:gphoto='http://schemas.google.com/photos/2007'>
    <title type='text'>Created from code</title>
    <summary type='text'>Code created this album</summary>     
    <gphoto:location>somewhere</gphoto:location>
    <gphoto:access>public</gphoto:access>
    <gphoto:timestamp></gphoto:timestamp>
    <media:group>
        <media:keywords>test, album, fun</media:keywords>
    </media:group>
    <category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/photos/2007#album'>
    </category>
</entry>

One other edit: The IGoogleOauth2AccessToken is another class I created to house the token details. What you really need passed in is the access_token string that you get when you refresh the OAuth2 token. My token housing code just has the access_code, token_type, and expires as part of the object. You just need the access token string for the authorization.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文