Enterprise development-issuing enterprise red envelopes (C #),
I. Enterprise APIs
Address: http://work.weixin.qq.com/api/doc#11543
Ii. parameter description 1. Sending enterprise Red Packets
Request Method: POST (HTTPS)
Request address: https://api.mch.weixin.qq.com/mmpaymkttransfers/sendworkwxredpack
Required certificate: Yes
Data format: xml
For more information about the parameters, see API documentation.
2. Specific implementation code
WxPayData data = new WxPayData (); data. setValue ("nonce_str", WxPayApi. generateNonceStr (); // random string data. setValue ("mch_billno", WxPayApi. generateOutTradeNo (); // Merchant Order Number data. setValue ("mch_id", WxPayConfig. MCHID); // merchant ID data. setValue ("wxappid", WxPayConfig. APPID); // public account ID data. setValue ("sender_name", "ly"); // The sender name data. setValue ("sender_header_media_id", "1G6nrLmr5EC3MMb _-zK1dDdzmd0p7cNliYu9V5w7o8K0 "); // The sender's profile picture. This id is the default profile picture (for more information, see section 3) string openid = ConvertToOpenidByUserId (_ accessToken, "13212345678 "); var openInfo = JsonConvert. deserializeObject <U_OpenInfo> (openid); data. setValue ("re_openid", openInfo. openid); // user openid data. setValue ("total_amount", 100); // payment amount, unit: the lowest dollar data. setValue ("wishing", "Happy Valentine's Day! "); // Red envelope greetings data. setValue ("act_name", "XX activity"); // activity name data. setValue ("remark", "come and grab"); // remarks data. setValue ("scene_id", "PRODUCT_4"); // scenario (required if the amount is greater than 200 RMB) data. setValue ("workwx_sign", data. makeWorkWxSign ("redPacket"); // enterprise signature data. setValue ("sign", data. makeSign (); // payment signature string xml = data. toXml (); const string postUrl = "https://api.mch.weixin.qq.com/mmpaymkttransfers/sendworkwxredpack"; // send enterprise red envelope interface address string response = PostWebRequest (postUrl, xml, Encoding. UTF8, true); // call the HTTP Communication Interface to submit data to the API WxPayData result = new WxPayData (); result. fromXml (response );
Public class WxPayData {// the advantage of ranking the Dictionary is that it is convenient to sign the data packet, and you do not need to sort the private SortedDictionary again before signing. <string, object> m_values = new SortedDictionary <string, object> (); /// <summary> /// set the value of a field /// </summary> /// <param name = "key"> Field name </param> /// <param name = "value"> field value </param> public void SetValue (string key, object value) {m_values [key] = value ;}/// <summary> /// obtain the value of a field based on the field name /// </summary> // <Param name = "key"> Field name </param> // <returns> field value </returns> public object GetValue (string key) {object o = null; m_values.TryGetValue (key, out o); return o ;} /// <summary> /// determine whether a field has been set /// </summary> /// <param name = "key"> Field name </param> // /<returns> If the field key has been set, true is returned. Otherwise, false </returns> public bool IsSet (string key) {object o = null; m_values.TryGetValue (key, out o); if (null! = O) return true; else return false ;} /// <summary> /// convert Dictionary to xml /// </summary> /// <returns> the converted xml string </returns> public string ToXml () {// when the data is null, it cannot be converted to the xml format if (0 = m_values.Count) {LogManager. writeLog (LogFile. error, "WxPayData is empty! "); Throw new WxPayException (" WxPayData is empty! ");} String xml =" <xml> "; foreach (KeyValuePair <string, object> pair in m_values) {// The field value cannot be null, will affect the subsequent process if (pair. value = null) {throw new WxPayException ("WxPayData contains a field with a null Value! ");} If (pair. value is int) {xml + = "<" + pair. key + ">" + pair. value + "</" + pair. key + ">";} else if (pair. value is string) {xml + = "<" + pair. key + ">" + "<! [CDATA ["+ pair. value + "]> </" + pair. key + ">";} else // except the string and int types, other data types cannot be included. {throw new WxPayException ("WxPayData Field Data Type Error! ") ;}} Xml + =" </xml> "; return xml ;} /// <summary> /// convert xml into a WxPayData object and return the internal data of the object /// </summary> /// <param name = "xml"> to be converted </param> /// <returns> converted Dictionary </returns> public SortedDictionary <string, object> FromXml (string xml) {if (string. isNullOrEmpty (xml) {throw new WxPayException ("it is invalid to convert an empty xml string to WxPayData! ");} XmlDocument xmlDoc = new XmlDocument (); xmlDoc. loadXml (xml); XmlNode xmlNode = xmlDoc. firstChild; // get the root node <xml> XmlNodeList nodes = xmlNode. childNodes; foreach (XmlNode xn in nodes) {XmlElement xe = (XmlElement) xn; m_values [xe. name] = xe. innerText; // get the xml Key-value pair to the data in WxPayData} try {if (m_values ["return_code"]. toString ()! = "SUCCESS") {return m_values;} // CheckSign (); // verify the signature. If the signature fails, an exception is thrown.} catch (WxPayException ex) {throw new WxPayException (ex. message);} return m_values ;} /// <summary> /// the Dictionary format is converted to the url parameter format // </summary> /// <returns> url format string, this string does not contain the sign field value </returns> public string ToUrl () {string buff = ""; foreach (KeyValuePair <string, object> pair in m_values) {if (pair. value = null) {LogManager. writeLog (Lo GFile. Error, "WxPayData contains a null field! "); Throw new WxPayException (" WxPayData contains a field with a null value! ");} If (pair. Key! = "Sign" & pair. Value. ToString ()! = "") {Buff + = pair. key + "=" + pair. value + "&" ;}} buff = buff. trim ('&'); return buff ;} /// <summary> /// the Dictionary format is converted to the url parameter format // </summary> /// <returns> url format string, this string does not contain the sign field value </returns> public string ToWorkWxUrl (string type) {string buff = ""; foreach (KeyValuePair <string, object> pair in m_values) {if (pair. value = null) {throw new WxPayException ("WxPayData contains a field with a null Value! ");} Var paras = new List <string> (); switch (type) {case" redPacket ": paras = new [] {" act_name "," mch_billno ", "mch_id", "nonce_str", "re_openid", "total_amount", "wxappid "}. toList (); break; case "payment": paras = new [] {"amount", "desc", "mch_id", "nonce_str", "openid ", "partner_trade_no", "appid", "ww_msg_type "}. toList (); break;} if (paras. contains (pair. key) {buff + = pair. key + "=" + pa Ir. value + "&" ;}} buff = buff. trim ('&'); return buff;} // <summary> // generate a signature, for details, see the signature generation algorithm // </summary> // <returns> signature. The sign field does not participate in the signature. </returns> public string MakeSign () {// convert the url Format string str = ToUrl (); // Add the api key str + = "& key =" + WxPayConfig. KEY; // MD5 encryption var md5 = MD5.Create (); var bs = md5.ComputeHash (Encoding. UTF8.GetBytes (str); var sb = new StringBuilder (); foreach (byte B in bs) {sb. Append (B. toString ("x2");} // convert all characters to uppercase return sb. toString (). toUpper ();} /// <summary> /// generate the enterprise signature /// </summary> /// <returns> </returns> public string MakeWorkWxSign (string type) {// convert the url Format string str = ToWorkWxUrl (type); // Add secret str + = "& secret =" + WxPayConfig to the string. PAYMENTSECRET; // MD5 encrypted var md5 = MD5.Create (); var bs = md5.ComputeHash (Encoding. UTF8.GetBytes (str); var sb = new StringBuild Er (); foreach (byte B in bs) {sb. append (B. toString ("x2");} // convert all characters to uppercase return sb. toString (). toUpper () ;}//< summary> /// check whether the signature is correct /// </summary> /// <returns> returns true, error throw exception </returns> public bool CheckSign () {// skip if (! IsSet ("sign") {LogManager. WriteLog (LogFile. Error, "WxPayData signature exists but is invalid! "); Throw new WxPayException (" WxPayData signature exists but is invalid! ");} // If the signature is set but the signature is empty, an exception else if (GetValue (" sign ") = null | GetValue (" sign ") is thrown "). toString () = "") {LogManager. writeLog (LogFile. error, "WxPayData signature exists but is invalid! "); Throw new WxPayException (" WxPayData signature exists but is invalid! ");} // Obtain the Received Signature string return_sign = GetValue (" sign "). toString (); // calculate the new signature locally string cal_sign = MakeSign (); if (cal_sign = return_sign) {return true;} LogManager. writeLog (LogFile. error, "WxPayData signature verification Error! "); Throw new WxPayException (" WxPayData signature verification error! ") ;}/// <Summary> /// obtain a Dictionary /// </summary> /// <returns> </returns> public SortedDictionary <string, object> GetValues () {return m_values ;}}
public class WxPayException : Exception { public WxPayException(string msg) : base(msg) { } }
Public class WxPayApi {protected Hashtable Parameters = new Hashtable (); /// <summary> /// generate an order number based on the current system time plus a random sequence // </summary> /// <returns> @ return order number </returns> public static string GenerateOutTradeNo () {var ran = new Random (); return string. format ("{0} {1: yyyyMMddHHmmss} {2}", WxPayConfig. MCHID, DateTime. now, ran. next (999); }/// <summary> // generate a timestamp, standard Beijing Time, time zone: UTC + 8, number of seconds since 00:00:00, January 1, January 1, 1970 /// </summ Ary >/// <returns> @ return timestamp </returns> public static string GenerateTimeStamp () {TimeSpan ts = DateTime. utcNow-new DateTime (1970, 1, 1, 0, 0, 0); return Convert. toInt64 (ts. totalSeconds ). toString () ;}/// <summary> // generates a random string, random string contains letters or numbers // </summary> // <returns> @ return random string </returns> public static string GenerateNonceStr () {// Random random = new Random (); // return GetMD5 (random. next (0, 1000). ToString (), "GBK"); return Guid. newGuid (). toString (). replace ("-","");} /// <summary> /// obtain the md5 encrypted string /// </summary> /// <param name = "enpolicstr"> </param> // <param name = "charset"> </param> // <returns> </returns> protected static string GetMD5 (string encystr, string charset) {byte [] bytes; // create an md5 object MD5CryptoServiceProvider provider = new MD5CryptoServiceProvider (); // convert the string to a byte array using GB2312 encoding. tr Y {bytes = Encoding. getEncoding (charset ). getBytes (enpolicstr);} catch (Exception) {bytes = Encoding. getEncoding ("GB2312 "). getBytes (enpolicstr);} return BitConverter. toString (provider. computeHash (bytes )). replace ("-",""). toUpper ();} protected void SetParameter (string parameter, string parameterValue) {if (! String. isNullOrEmpty (parameter) {if (this. parameters. contains (parameter) {this. parameters. remove (parameter);} this. parameters. add (parameter, parameterValue );}}}
Public class WxPayConfig {// ======= [basic information settings] ========================== ===================/* Public Account information configuration * APPID: bound to the payment APPID (required) * MCHID: merchant ID (required) * KEY: merchant payment KEY, refer to account email settings (required) * APPSECRET: public Account secert (required only when JSAPI is used for payment) */public static readonly string APPID = "111111111111 "; // write all your own public static readonly string APPSECRET = "111111"; public static readonly string PAYMENTSECRET = "111111"; public static readonly string MCHID = "111111 "; // merchant ID public static readonly string KEY = "111111111111 "; // ======= [certificate path settings] =================================== =============/* certificate path, be sure to enter the absolute path (only required for refund and order revocation) */public static readonly string SSLCERT_PATH = "cert/apiclient_cert.p12"; public static readonly string SSLCERT_PASSWORD = MCHID ;}3. Notes
(1) Calculate the enterprise Signature
The final secret of the string is the secret on the Enterprise Management Terminal payment application page (SEE)
Not the secret of the enterprise. (For example)Remember !!!
(2) Calculate the enterprise Signature
There are only the following fields involved in the signature of the ap for sending a red packet (this code is reflected in ):
Act_name
Mch_billno
Mch_id
Nonce_str
Re_openid
Total_amount
Wxappid
Do not add all parameters to the signature calculation. Otherwise, a signature error is returned!
3. Upload temporary materials
1. There is a parameter "sender_header_media_id" in the red packet sending API interface, which can be obtained through the Enterprise open upload Material Interface.
Request Method: POST (HTTPS)
Request address: https://qyapi.weixin.qq.com/cgi-bin/media/upload? Access_token = ACCESS_TOKEN & type = TYPE
Use http multipart/form-data to upload a file. The file ID is "media ".
Parameter description:
| Parameters |
Required |
Description |
| Access_token |
Yes |
Interface call credential |
| Type |
Yes |
Media file types, including image, voice, video, and file) |
| Media |
Yes |
The ID of a media file in form-data, including filename, filelength, and content-type. |
Permission description:
It is completely public and media_id can be shared among applications in the same enterprise.
Returned data:
{ "errcode": 0, "errmsg": "", "type": "image", "media_id": "1G6nrLmr5EC3MMb_-zK1dDdzmd0p7cNliYu9V5w7o8K0", "created_at": "1380000000"}
2. Specific implementation
/// <Summary> /// upload temporary materials /// </summary> /// <param name = "filePath"> </param> /// <returns> </returns> public string UploadTempResource (string filePath) {const string url = "https://qyapi.weixin.qq.com/cgi-bin/media/upload? Access_token = {0} & type = image "; var uploadUrl = string. format (url, _ accessToken); var mediaId = "1G6nrLmr5EC3MMb _-Timeout"; using (var client = new WebClient () {byte [] resource = client. uploadFile (new Uri (uploadUrl), filePath); string retdata = Encoding. UTF8.GetString (resource); var data = JsonConvert. deserializeObject (retdata) as JObject; if (data! = Null) {mediaId = data ["media_id"]. ToString () ;}} return mediaId ;}}IV. Implementation results