【C#】AtomPubでライブドアブログに記事と画像を投稿するサンプル
C#でライブドアブログに記事と画像を投稿するサンプルコードです。
実際にこのコードで投稿してるブログはアダルトなので紹介できないですけどw
ちなみに使ってるVSのバージョンと.NET Frameworkのバージョンは以下です。
Microsoft Visual Studio Express 2013 for Windows Desktop
.NET Framework 4.5
プロジェクトの種類はコンソールアプリケーション。
プロジェクトの参照設定に「System.Web」「System.Drawing」を追加する必要があります。
エラーハンドリングとかは適当で動作確認もしてませんwww
動かなくても惜しいところまではいけるはずw
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Drawing; using System.IO; using System.Net; using System.Web; using System.Xml; using System.Security.Cryptography; namespace ConsoleApplication1 { class Program { const string ENTRY_COLLECTION_URI = "http://livedoor.blogcms.jp/atom/blog/{0}/article"; const string MEDIA_COLLECTION_URI = "http://livedoor.blogcms.jp/atom/blog/{0}/image"; static void Main(string[] args) { try { // 引数のチェックは省略 // 第一引数:username、正確にはルートエンドポイントの最後の部分やけどまぁログインIDと同じになると思われ // 第二引数:ブログ管理画面のAPIKEY画面で発行したパスワード // 第三引数:ローカルの画像ファイルのパス string userName = args[0]; string apiKey = args[1]; string filePath = args[2]; string title = "記事タイトル"; string cat = "カテゴリ名"; string body = "記事本文"; string more = "記事追記"; string imgUrl = MediaUp(userName, apiKey, filePath); body += "<img src=\"" + imgUrl + "\">"; BlogAdd(userName, apiKey, title, cat, body, more); } catch (Exception ex) { // 例外時にメッセージとスタックトレースを表示 if (ex.InnerException != null) Console.WriteLine(ex.InnerException.Message); else Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } } /// <summary> /// 記事投稿 /// </summary> /// <param name="username"></param> /// <param name="apikey"></param> /// <param name="title"></param> /// <param name="cat"></param> /// <param name="body"></param> /// <param name="more"></param> /// <returns></returns> static bool BlogAdd(string username, string apikey, string title, string cat, string body, string more) { string reqStr = "<?xml version=\"1.0\" encoding=\"utf-8\"?>"; reqStr += "<entry xmlns=\"http://www.w3.org/2005/Atom\""; reqStr += " xmlns:app=\"http://www.w3.org/2007/app\""; reqStr += " xmlns:blogcms=\"http://blogcms.jp/-/spec/atompub/1.0/\">"; reqStr += " <title>{0}</title>"; reqStr += " <category term=\"{1}\" />"; reqStr += " <blogcms:source>"; reqStr += " <blogcms:body><![CDATA[<p>{2}</p>]]></blogcms:body>"; reqStr += " <blogcms:more><![CDATA[<p>{3}</p>]]></blogcms:more>"; reqStr += " </blogcms:source>"; reqStr += " <app:control>"; reqStr += " <app:draft>no</app:draft>"; reqStr += " </app:control>"; reqStr += "</entry>"; reqStr = HttpUtility.HtmlDecode(string.Format(reqStr, title, cat, body, more)); byte[] byteData = Encoding.UTF8.GetBytes(reqStr); HttpWebRequest req = (HttpWebRequest)WebRequest.Create(string.Format(ENTRY_COLLECTION_URI, username)); req.Headers.Add("X-WSSE", WsseCreate(username, apikey)); req.Method = "POST"; req.ContentType = "text/xml"; req.ServicePoint.Expect100Continue = false; req.ContentLength = byteData.Length; Stream reqStream = req.GetRequestStream(); reqStream.Write(byteData, 0, byteData.Length); reqStream.Close(); // 送信のレスポンスを受け取る WebResponse webRes = req.GetResponse(); using (XmlTextReader XmlReader = new XmlTextReader(webRes.GetResponseStream())) { XmlReader.WhitespaceHandling = WhitespaceHandling.None; while (XmlReader.Read()) { if (XmlReader.NodeType == XmlNodeType.Element) { if (XmlReader.Name == "fault") { return false; } } } } return true; } /// <summary> /// 画像アップロード /// </summary> /// <param name="username"></param> /// <param name="apikey"></param> /// <param name="filePath"></param> /// <returns></returns> static string MediaUp(string username, string apikey, string filePath) { string ret = ""; byte[] imgBytes; using (FileStream fs = new FileStream(filePath, FileMode.Open)) using (Bitmap bmpData = new Bitmap(Image.FromStream(fs))) using (MemoryStream memStm = new MemoryStream()) { // 保存フォーマットは任意 bmpData.Save(memStm, System.Drawing.Imaging.ImageFormat.Jpeg); imgBytes = memStm.ToArray(); memStm.Close(); fs.Close(); } string resText = ""; using (WebClient wc = new WebClient()) { var uri = new Uri(string.Format(MEDIA_COLLECTION_URI, username)); var servicePoint = ServicePointManager.FindServicePoint(uri); servicePoint.Expect100Continue = false; wc.Headers.Add("X-WSSE", WsseCreate(username, apikey)); //ヘッダにContent-Typeを加える wc.Headers.Add("Content-Type", "image/jpeg"); //データを送信し、また受信する byte[] resData = wc.UploadData(uri, imgBytes); //受信したデータを表示する resText = Encoding.UTF8.GetString(resData); } XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(new StringReader(resText)); XmlNode entry = xmldoc.LastChild; if (entry != null) { foreach (XmlNode entChild in entry.ChildNodes) { if (entChild.Name == "content") { ret = entChild.Attributes["src"].Value; break; } } } return ret; } /// <summary> /// WSSE認証用の文字列作成 /// </summary> /// <param name="username"></param> /// <param name="apikey"></param> /// <returns></returns> static string WsseCreate(string username, string apikey) { // nonce security token byte[] nonce = MakeRandomBytes(40); // created ISO-8601 formatting string created = DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssZ"); // password sha1 digest (nonce+created+password) List<Byte> lstByte = new List<byte>(); lstByte.AddRange(nonce); lstByte.AddRange(System.Text.Encoding.UTF8.GetBytes(created)); lstByte.AddRange(System.Text.Encoding.UTF8.GetBytes(apikey)); SHA1Managed sha1 = new SHA1Managed(); byte[] passwordDigest = sha1.ComputeHash(lstByte.ToArray()); // Build WSSE Header string format = "UsernameToken Username=\"{0}\", PasswordDigest=\"{1}\", Nonce=\"{2}\", Created=\"{3}\""; return String.Format(format, username, Convert.ToBase64String(passwordDigest), Convert.ToBase64String(nonce), created); } /// <summary> /// ランダムなバイト配列作成(WSSE認証用) /// </summary> /// <param name="makebytes"></param> /// <returns></returns> static byte[] MakeRandomBytes(int makebytes) { RNGCryptoServiceProvider rnd = new RNGCryptoServiceProvider(); Byte[] rndBuffer = new Byte[makebytes]; rnd.GetBytes(rndBuffer); return rndBuffer; } } }
WSSE認証の部分は以下の記事を参考にしました、ありがとうございます。
tekkの日記 C#,VB.NET