开发者

Creating new album in picasa in .NET

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


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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜