
When I wrote the project
crafthunters.com , I noticed that customers use social networks for promotion. We used widgets and likes, but for good it was necessary to get into the news feed. In addition, the popular VKontakte brought the news to the main page in September. Those. to distribute content, it was necessary to adapt the standalone blog for presentation on social networks, using a simple truth: get into the news feed of popular social networks. Initially, this was done manually and brought more than half of the traffic. Then the idea came to automate it all.
We used popular social networks:
- facebook
- in contact with
- livejournal
- twitter
It was necessary to set up automatic cross-posting to each of the social networks, which had previously been manually led. It is also necessary to clarify that it was necessary to post entries in social networks not on the wall / blog, but in the group / community.
Next, I want to present the implementation of crossposting for these four social networks for asp.net mvc.
0. Basic principles.
')
First of all, you need to get the rights and save them in a database for later use. The second step was to install content in which group / community (the task is essentially only for VK). The third step was to create an entry in the group / community with an active link to the original post.
For Twitter, Facebook and VKontakte, the OAuth-based API is used and to work with them it was necessary to register the application in each social network for these purposes.
In order not to repeat myself, I will immediately tell you how OAuth works (for twitter xAuth). First we pass the application id and the list of rights we want to get. The list of permissions is what resources we allow access to for our application. It looks like this:

After permission, we get the code by which we get the access token. For each request to the server, we transfer this token and thus the service provider (VKontakte, facebook and twitter) know that we can be trusted and are allowed to perform the action (in our case, crossposting).
1. Livejournal
LJ has long been used for cross-posting and it does this through an XML-RPC command.
After reading the documentation (
http://www.livejournal.com/doc/server/ljp.csp.xml-rpc.protocol.html ) using the library for .net xml-rpc (
http://www.xml-rpc.net/ ) I started to implement.
Create an interaction interface:
public interface ILj : IXmlRpcProxy { [XmlRpcMethod("LJ.XMLRPC.login")] LjUserInfo Login(UserPassword user); XmlRpcMethod("LJ.XMLRPC.postevent")] PostLjAnswer Post(PostLj post); }
Getting access
Login and password are transmitted in the clear and transmitted via the web service protocol. Create a class to get rights.
public class UserPassword { [JsonProperty("username")] public string username { get; set; } [JsonProperty("password")] public string password { get; set; } public int ver { get { return 1; } } }
With each publication, the login and password are also transmitted, so the Login method only essentially checks the correctness of the login / password pair.
Access check.
public LjUserInfo Auth(UserPassword username) { ILj proxy = XmlRpcProxyGen.Create<ILj>(); var ans = proxy.Login(username); return ans; }
Answer ans we analyze a positive response otherwise we give an error.
Adding an entry is just as trivial:
public void Publish(UserPassword username, Post message, string ljgroup = null) { ILj proxy = XmlRpcProxyGen.Create<ILj>(); var post = new PostLj(); post.username = username.username; post.password = username.password; post.ver = 1; post.@event = message.Content; post.subject = message.Title; post.lineendings = "pc"; post.year = DateTime.Now.Year; post.mon = DateTime.Now.Month; post.day = DateTime.Now.Day; post.hour = DateTime.Now.Hour; post.min = DateTime.Now.Minute; if (!string.IsNullOrWhiteSpace(ljgroup)) { post.usejournal = ljgroup; } else { post.usejournal = username.username; } var ans = proxy.Post(post); }
Actually everything is very simple. Of course, there are so many additional options and the library is quite extensive, but the task - to add our post in LJ - is easily solved.
What did not like - the transfer of the password in clear text or in md5 over an unprotected channel.
2. Twitter
For Twitter, I used the popular
www.twitterizer.net library, but first I had to register the application at:
dev.twitter.com/apps .
The rights that the application will request - both for reading and for writing. Among other things, the application receives a token that is infinite in expiration to use. This token must be saved in the database. (Table Social.JsonResource)
Obtaining rights occurs in the following scenario:
public string Authorize(string redirectTo) { OAuthTokenResponse requestToken = OAuthUtility.GetRequestToken(Config.twitterConsumerKey, Config.twitterConsumerSecret, redirectTo);
We transfer two keys (application key and secret key), and go to the twitter page to confirm the rights. Twitter asks for rights and returns us to the address redirectTo where it additionally sends the code. This code gives us an access token. Next, we update the status (create a short message) through the application:
public void Publish(Post post) { var tokens = new OAuthTokens(); tokens.ConsumerKey = Config.twitterConsumerKey; tokens.ConsumerSecret = Config.twitterConsumerSecret; tokens.AccessToken = twitterAccessToken.Token; tokens.AccessTokenSecret = twitterAccessToken.TokenSecret; TwitterStatus.Update(tokens, post.TwitterText); }
3. Facebook
Register the application at:
developers.facebook.com/appsWe receive access token. First, we send to obtain permission rights:
public string Authorize(string redirectTo) { return string.Format(AuthorizeUri, Config.AppId, redirectTo); } public ActionResult GetFbCode() { var fbSocial = currentUser.Socials.Where(p => p.Provider == "facebook").FirstOrDefault(); if (fbSocial != null) { return RedirectToAction("Index"); } else { return Redirect(fbProvider.Authorize("http://" + HostName + "/Social/SaveFbCode")); } }
We process the code to get the access token:
public ActionResult SaveFbCode() { if (Request.Params.AllKeys.Contains("code")) { var code = Request.Params["code"]; if (ProcessFbCode(code)) { return RedirectToAction("Index"); } } return View("CantInitialize"); } protected bool ProcessFbCode(string code) { if (fbProvider.GetAccessToken(code, "http://" + HostName + "/Social/SaveFbCode")) { var jObj = fbProvider.GetUserInfo(); var fbUserInfo = JsonConvert.DeserializeObject<FbUserInfo>(jObj.ToString()); var fbAccess = new FbAccessToken() { AccessToken = fbProvider.AccessToken }; var jsonFbAccess = JsonConvert.SerializeObject(fbAccess); var fbSocial = currentUser.Socials.Where(p => p.Provider == "facebook").FirstOrDefault(); if (fbSocial == null) { fbSocial = new Models.Social() { UserID = currentUser.ID, JsonResource = jsonFbAccess.ToString(), Provider = "facebook", UserInfo = jObj.ToString() }; repository.CreateSocial(fbSocial); } else { fbSocial.UserInfo = jObj.ToString(); repository.UpdateSocial(fbSocial); } return true; } return false; }
Here, when receiving the perpetual access token, we need to request & scope = ..., offline in the parameter request parameter, thereby saving ourselves to request this token all the time, but for greater secrecy, this fragment can also be redone to use a token with expiration date.
Post creation
public ActionResult CrossPostFb(int id) { var post = repository.Posts.Where(p => p.ID == id).FirstOrDefault(); var fbSocial = currentUser.SocialGetByProvider("facebook"); if (post != null && post.UserID == currentUser.ID && fbSocial != null) { var postSocial = new Social.Post(); if (!string.IsNullOrWhiteSpace(post.PreviewUrl)) {
Depending on the parameters set, a record will be created. When you install the active link, facebook will independently select the image it needs.
4. Vkontakte
Vkontakte offers the most complex interaction algorithm.
Let's start in order: create posts both on the wall and on the group wall can only Standalone application (and not the web), so register the application (
http://vkontakte.ru/editapp?act=create&site=1 ) you need to specify [x ] Standalone application.
Second: to add pictures to the recording, you need to download it beforehand.
Third: to upload a picture, you need to request the address of the server that will be downloaded.
Fourth: the link to the original post is placed in the attachments parameter and adding a link does not guarantee adding a note.
Actually the rest is still the same, so let's get down and get the rights:
public ActionResult GetVkCode() { var vkSocial = currentUser.Socials.Where(p => p.Provider == "vkontakte").FirstOrDefault(); if (vkSocial != null) { return RedirectToAction("Index"); } else { return Redirect(vkProvider.Authorize("http://" + HostName + "/Social/SaveVkCode")); } } public string Authorize(string redirectTo) { return string.Format(AuthorizeUri, Config.AppKey, redirectTo); }
For our crossposting, we request the following access levels: photos, groups, wall, offline.
Those. we can upload photos in groups on the wall at any time.
Publication
Before posting to a group wall, we need to find out the number of this group by name (groups.getById). Surprisingly, groups (as well as personal pages) are numbered in the negative direction. Those.
after getting the result, the gid value should be multiplied by -1.
Then we request the server to upload photos: photos.getWallUploadServer, not photos.getUploadServer - although they are almost identical.
Next, we will send a photo to the server on VKontakte via the post url request received. I used the UploadHelper library (
http://aspnetupload.com/ ).
After uploading to the server, you need to send a command to save this image: photos.saveWallPhoto - to which we get the photo id. If you used photos.getUploadServer instead of photos.getWallUploadServer, then the photo will not be saved.
And the next step is to add a photo to the wall of the group / or personal page (wall.post).
Actually everything.
5. Buns
You can try here:
http://cocosanka.ru (after registering, you can write something meaningless to the blog, and then ask for it).
Download the source here:
https://bitbucket.org/chernikov/cocosanka2To work with the data, I used the Json.net library (
http://json.codeplex.com/ ) translating the automatically obtained strings into objects.
Application keys are stored in Web.config, but you will need to register your own.