/// <summary> /// Uploads a file by making an HTTP POST request to the specified MediaWiki API endpoint. /// </summary> /// <param name="wiki">The <see cref="Wiki"/> to contact.</param> /// <param name="query">A dictionary of key-value pairs that represent the request parameters.</param> /// <param name="file">The file to upload, as a byte array of binary data.</param> /// <param name="fileName">The name of the file to upload.</param> /// <param name="fileParamName">The name (key) of the POST parameter whose value is the file data.</param> /// <param name="onSuccess">A function that will be called when the request is successful. /// The function is passed the XML response as its only parameter.</param> /// <param name="onError">A function that will be called when the request fails. /// The function is passed the error message string as its only parameter.</param> public static void UploadFile(Wiki wiki, StringDictionary query, byte[] file, string fileName, //string fileMimeType, string fileParamName, MorebitsDotNetPostSuccess onSuccess, MorebitsDotNetError onError) { // thanks to http://www.paraesthesia.com/archive/2009/12/16/posting-multipartform-data-using-.net-webrequest.aspx query.Add("format", "xml"); WebRequest req = HttpWebRequest.Create(GetApiUri(wiki)); ((HttpWebRequest)req).UserAgent = UserAgent; req.Method = "POST"; LoginInfo session = LoginSessions[wiki]; if (session.CookieJar == null) { session.CookieJar = new CookieContainer(); } ((HttpWebRequest)req).CookieContainer = session.CookieJar; string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture); req.ContentType = "multipart/form-data; boundary=" + boundary; req.BeginGetRequestStream(delegate(IAsyncResult innerResult) { Stream stream = req.EndGetRequestStream(innerResult); foreach (DictionaryEntry e in query) { string item = String.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\nContent-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\n{2}\r\n", boundary, e.Key.ToString(), e.Value.ToString()); byte[] bytes = Encoding.UTF8.GetBytes(item); stream.Write(bytes, 0, bytes.Length); } if (file != null) { string header = String.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n", boundary, fileParamName, fileName, "text/plain; charset=UTF-8"); // last param was |fileMimeType| byte[] headerbytes = Encoding.UTF8.GetBytes(header); stream.Write(headerbytes, 0, headerbytes.Length); stream.Write(file, 0, file.Length); byte[] newline = Encoding.UTF8.GetBytes("\r\n"); stream.Write(newline, 0, newline.Length); } byte[] endBytes = Encoding.UTF8.GetBytes("--" + boundary + "--"); stream.Write(endBytes, 0, endBytes.Length); stream.Close(); }, null); IAsyncResult result = (IAsyncResult)req.BeginGetResponse(new AsyncCallback(delegate(IAsyncResult innerResult) { WebResponse resp = null; try { resp = req.EndGetResponse(innerResult); } catch (WebException e) { onError(Localization.GetString("MorebitsDotNet_NetRequestFailure") + "\n\n" + e.Message); return; } XmlDocument doc = new XmlDocument(); doc.Load(resp.GetResponseStream()); #if REQUEST_LOG // simple request logging; doesn't include request body, so it should be used in conjunction with a debug session System.IO.File.AppendAllText("RequestLog.txt", "====\r\n\r\n" + req.RequestUri + "\r\n\r\nREQUEST HEADERS:\r\n" + req.Headers + "\r\n\r\nRESPONSE HEADERS:\r\n" + resp.Headers); #endif XmlNodeList list = doc.GetElementsByTagName("error"); if (list.Count == 0) { onSuccess(doc); } else { onError(Localization.GetString("MorebitsDotNet_ApiError") + "\n\n" + list[0].Attributes["info"].Value); } }), null); ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), req, UploadTimeout, true); }
private static void PostApi(Wiki wiki, StringDictionary query, MorebitsDotNetPostSuccess onSuccess, MorebitsDotNetError onError, bool loggingIn, string method) { string requestContent = "format=xml&"; foreach (DictionaryEntry i in query) { requestContent += Uri.EscapeDataString((string)i.Key) + "=" + Uri.EscapeDataString((string)i.Value ?? "") + "&"; } requestContent = requestContent.TrimEnd('&'); WebRequest req; if (method == WebRequestMethods.Http.Get) { req = HttpWebRequest.Create(GetApiUri(wiki) + "?" + requestContent); } else { req = HttpWebRequest.Create(GetApiUri(wiki)); } ((HttpWebRequest)req).UserAgent = UserAgent; req.Method = method; req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; LoginInfo session = LoginSessions[wiki]; if (session.CookieJar == null) { session.CookieJar = new CookieContainer(); } ((HttpWebRequest)req).CookieContainer = session.CookieJar; // login doesn't seem to work properly when done asynchronously if (loggingIn) { byte[] bytes = Encoding.UTF8.GetBytes(requestContent); req.ContentLength = bytes.Length; Stream s = req.GetRequestStream(); s.Write(bytes, 0, bytes.Length); s.Close(); } else if (method != WebRequestMethods.Http.Get) { byte[] bytes = Encoding.UTF8.GetBytes(requestContent); req.ContentLength = bytes.Length; req.BeginGetRequestStream(delegate(IAsyncResult innerResult) { try { using (Stream s = req.EndGetRequestStream(innerResult)) { s.Write(bytes, 0, bytes.Length); s.Close(); } } catch (WebException e) { onError(Localization.GetString("MorebitsDotNet_NetRequestFailure") + "\n\n" + e.Message); return; } }, null); } IAsyncResult result = (IAsyncResult)req.BeginGetResponse(delegate(IAsyncResult innerResult) { WebResponse resp = null; try { resp = req.EndGetResponse(innerResult); } catch (WebException e) { onError(Localization.GetString("MorebitsDotNet_NetRequestFailure") + "\n\n" + e.Message); return; } XmlDocument doc = new XmlDocument(); doc.Load(resp.GetResponseStream()); if (loggingIn) { // have to handle login errors (wrong password, etc.) before cookies are read try { XmlNode login = doc.SelectSingleNode("/api/login"); if (login.Attributes["result"].Value != "Success") { onError(Localization.GetString("MorebitsDotNet_LoginFailure", login.Attributes["result"].Value)); return; } // copy over the cookies for ".commons.wikimedia.org" (hack, not sure why it's needed...) CookieCollection jar = session.CookieJar.GetCookies(new Uri(GetProtocol() + "://a." + GetDomain(Wiki.Commons))); session.CookieJar.Add(jar); } catch (Exception x) { onError(Localization.GetString("MorebitsDotNet_UnknownLoginFailure") + "\n\n" + x.Message + "\n\nHere is some debugging info:\n" + doc.OuterXml); } } #if REQUEST_LOG // simple request logging; doesn't include request body, so it should be used in conjunction with a debug session System.IO.File.AppendAllText("RequestLog.txt", "====\r\n\r\n" + req.RequestUri + "\r\n\r\nREQUEST HEADERS:\r\n" + req.Headers + "\r\n\r\nRESPONSE HEADERS:\r\n" + resp.Headers); #endif XmlNodeList list = doc.GetElementsByTagName("error"); if (list.Count == 0) { onSuccess(doc); } else { onError(Localization.GetString("MorebitsDotNet_ApiError") + "\n\n" + list[0].Attributes["info"].Value); } }, null); ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), req, DefaultTimeout, true); }
public static void UploadFile(Wiki wiki, StringDictionary query, byte[] file, string fileName, //string fileMimeType, string fileParamName, MorebitsDotNetPostSuccess onSuccess) { UploadFile(wiki, query, file, fileName, fileParamName, onSuccess, DefaultErrorHandler); }
public static void PostApi(Wiki wiki, StringDictionary query, MorebitsDotNetPostSuccess onSuccess, MorebitsDotNetError onError) { PostApi(wiki, query, onSuccess, onError, false, WebRequestMethods.Http.Post); }
/// <summary> /// Makes an HTTP request to the specified MediaWiki API endpoint. /// </summary> /// <param name="wiki">The <see cref="Wiki"/> to contact.</param> /// <param name="query">A dictionary of key-value pairs that represent the request parameters.</param> /// <param name="onSuccess">A function that will be called when the request is successful. /// The function is passed the XML response as its only parameter.</param> /// <param name="onError">A function that will be called when the request fails. /// The function is passed the error message string as its only parameter.</param> /// <param name="method">The HTTP method to use. Use one of the constants in <see cref="System.Net.WebRequestMethods.Http"/>.</param> public static void PostApi(Wiki wiki, StringDictionary query, MorebitsDotNetPostSuccess onSuccess, MorebitsDotNetError onError, string method) { PostApi(wiki, query, onSuccess, onError, false, method); }
private static void PostApi(Wiki wiki, StringDictionary query, MorebitsDotNetPostSuccess onSuccess, MorebitsDotNetError onError, bool loggingIn, string method) { string requestContent = "format=xml&"; foreach (DictionaryEntry i in query) requestContent += Uri.EscapeDataString((string) i.Key) + "=" + Uri.EscapeDataString((string) i.Value ?? "") + "&"; requestContent = requestContent.TrimEnd('&'); WebRequest req; if (method == WebRequestMethods.Http.Get) req = HttpWebRequest.Create(GetApiUri(wiki) + "?" + requestContent); else req = HttpWebRequest.Create(GetApiUri(wiki)); ((HttpWebRequest) req).UserAgent = UserAgent; req.Method = method; req.ContentType = "application/x-www-form-urlencoded; charset=UTF-8"; LoginInfo session = LoginSessions[wiki]; if (session.CookieJar == null) session.CookieJar = new CookieContainer(); ((HttpWebRequest) req).CookieContainer = session.CookieJar; // login doesn't seem to work properly when done asynchronously if (loggingIn) { byte[] bytes = Encoding.UTF8.GetBytes(requestContent); req.ContentLength = bytes.Length; Stream s = req.GetRequestStream(); s.Write(bytes, 0, bytes.Length); s.Close(); } else if (method != WebRequestMethods.Http.Get) { byte[] bytes = Encoding.UTF8.GetBytes(requestContent); req.ContentLength = bytes.Length; req.BeginGetRequestStream(delegate(IAsyncResult innerResult) { try { using (Stream s = req.EndGetRequestStream(innerResult)) { s.Write(bytes, 0, bytes.Length); s.Close(); } } catch (WebException e) { onError(Localization.GetString("MorebitsDotNet_NetRequestFailure") + "\n\n" + e.Message); return; } }, null); } IAsyncResult result = (IAsyncResult) req.BeginGetResponse(delegate(IAsyncResult innerResult) { WebResponse resp = null; try { resp = req.EndGetResponse(innerResult); } catch (WebException e) { onError(Localization.GetString("MorebitsDotNet_NetRequestFailure") + "\n\n" + e.Message); return; } XmlDocument doc = new XmlDocument(); doc.Load(resp.GetResponseStream()); if (loggingIn) { // have to handle login errors (wrong password, etc.) before cookies are read try { XmlNode login = doc.SelectSingleNode("/api/login"); if (login.Attributes["result"].Value != "Success") { onError(Localization.GetString("MorebitsDotNet_LoginFailure", login.Attributes["result"].Value)); return; } // copy over the cookies for ".commons.wikimedia.org" (hack, not sure why it's needed...) CookieCollection jar = session.CookieJar.GetCookies(new Uri(GetProtocol() + "://a." + GetDomain(Wiki.Commons))); session.CookieJar.Add(jar); } catch (Exception x) { onError(Localization.GetString("MorebitsDotNet_UnknownLoginFailure") + "\n\n" + x.Message + "\n\nHere is some debugging info:\n" + doc.OuterXml); } } #if REQUEST_LOG // simple request logging; doesn't include request body, so it should be used in conjunction with a debug session System.IO.File.AppendAllText("RequestLog.txt", "====\r\n\r\n" + req.RequestUri + "\r\n\r\nREQUEST HEADERS:\r\n" + req.Headers + "\r\n\r\nRESPONSE HEADERS:\r\n" + resp.Headers); #endif XmlNodeList list = doc.GetElementsByTagName("error"); if (list.Count == 0) onSuccess(doc); else onError(Localization.GetString("MorebitsDotNet_ApiError") + "\n\n" + list[0].Attributes["info"].Value); }, null); ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), req, DefaultTimeout, true); }
/// <summary> /// Uploads a file by making an HTTP POST request to the specified MediaWiki API endpoint. /// </summary> /// <param name="wiki">The <see cref="Wiki"/> to contact.</param> /// <param name="query">A dictionary of key-value pairs that represent the request parameters.</param> /// <param name="file">The file to upload, as a byte array of binary data.</param> /// <param name="fileName">The name of the file to upload.</param> /// <param name="fileParamName">The name (key) of the POST parameter whose value is the file data.</param> /// <param name="onSuccess">A function that will be called when the request is successful. /// The function is passed the XML response as its only parameter.</param> /// <param name="onError">A function that will be called when the request fails. /// The function is passed the error message string as its only parameter.</param> public static void UploadFile(Wiki wiki, StringDictionary query, byte[] file, string fileName, //string fileMimeType, string fileParamName, MorebitsDotNetPostSuccess onSuccess, MorebitsDotNetError onError) { // thanks to http://www.paraesthesia.com/archive/2009/12/16/posting-multipartform-data-using-.net-webrequest.aspx query.Add("format", "xml"); WebRequest req = HttpWebRequest.Create(GetApiUri(wiki)); ((HttpWebRequest) req).UserAgent = UserAgent; req.Method = "POST"; LoginInfo session = LoginSessions[wiki]; if (session.CookieJar == null) session.CookieJar = new CookieContainer(); ((HttpWebRequest) req).CookieContainer = session.CookieJar; string boundary = "---------------------------" + DateTime.Now.Ticks.ToString("x", CultureInfo.InvariantCulture); req.ContentType = "multipart/form-data; boundary=" + boundary; req.BeginGetRequestStream(delegate(IAsyncResult innerResult) { Stream stream = req.EndGetRequestStream(innerResult); foreach (DictionaryEntry e in query) { string item = String.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\nContent-Type: text/plain; charset=UTF-8\r\nContent-Transfer-Encoding: 8bit\r\n\r\n{2}\r\n", boundary, e.Key.ToString(), e.Value.ToString()); byte[] bytes = Encoding.UTF8.GetBytes(item); stream.Write(bytes, 0, bytes.Length); } if (file != null) { string header = String.Format(CultureInfo.InvariantCulture, "--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n", boundary, fileParamName, fileName, "text/plain; charset=UTF-8"); // last param was |fileMimeType| byte[] headerbytes = Encoding.UTF8.GetBytes(header); stream.Write(headerbytes, 0, headerbytes.Length); stream.Write(file, 0, file.Length); byte[] newline = Encoding.UTF8.GetBytes("\r\n"); stream.Write(newline, 0, newline.Length); } byte[] endBytes = Encoding.UTF8.GetBytes("--" + boundary + "--"); stream.Write(endBytes, 0, endBytes.Length); stream.Close(); }, null); IAsyncResult result = (IAsyncResult) req.BeginGetResponse(new AsyncCallback(delegate(IAsyncResult innerResult) { WebResponse resp = null; try { resp = req.EndGetResponse(innerResult); } catch (WebException e) { onError(Localization.GetString("MorebitsDotNet_NetRequestFailure") + "\n\n" + e.Message); return; } XmlDocument doc = new XmlDocument(); doc.Load(resp.GetResponseStream()); #if REQUEST_LOG // simple request logging; doesn't include request body, so it should be used in conjunction with a debug session System.IO.File.AppendAllText("RequestLog.txt", "====\r\n\r\n" + req.RequestUri + "\r\n\r\nREQUEST HEADERS:\r\n" + req.Headers + "\r\n\r\nRESPONSE HEADERS:\r\n" + resp.Headers); #endif XmlNodeList list = doc.GetElementsByTagName("error"); if (list.Count == 0) onSuccess(doc); else onError(Localization.GetString("MorebitsDotNet_ApiError") + "\n\n" + list[0].Attributes["info"].Value); }), null); ThreadPool.RegisterWaitForSingleObject(result.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), req, UploadTimeout, true); }