net core WebApi——嘗試企業(yè)微信來開發(fā)企業(yè)內(nèi)部應(yīng)用

前言

這幾天忙活著別的東西敬辣,耽誤了很長時間膘滨,從文件操作完了之后就在考慮著下一步鼓搗點兒啥,因為最開始的業(yè)務(wù)開發(fā)就是企業(yè)微信相關(guān)的赴魁,這剛好來做個內(nèi)部應(yīng)用的小例子玩玩赡鲜。

企業(yè)微信

前身是企業(yè)號空厌,當時微信主推的還是公眾號與服務(wù)號,后續(xù)戰(zhàn)略考慮到企業(yè)的OA了(當然還是跟某個搶市場)银酬,企業(yè)號應(yīng)該是在16年還是具體啥時候出的嘲更,剛出的時候也是問題不斷一直在修復(fù)更新,最近這兩年基本上沒咋關(guān)注企業(yè)微信了揩瞪,也都是偶爾上去看看有沒有新東西啊什么的赋朦,不過不得不說,在這幾年的成長中已經(jīng)修復(fù)逐漸成為一個不錯的產(chǎn)品了(大廠的效率還是有的)李破,相對于公眾號的開發(fā)宠哄,為什么我選這個作為例子呢,因為企業(yè)微信我可以通過個人來使用(注冊的早嗤攻,現(xiàn)在不清楚注冊流程琳拨,主要看是否需要企業(yè)認證),個人開發(fā)者在不論啥時候啥平臺都或多或少有些不友好(當然屯曹,認證了說明你是個好人狱庇,為了信息安全惊畏,都懂)。

開始

注冊企業(yè)微信的流程我就不多說了密任,直接說注冊完成之后颜启,我們來看下這個界面,標注的就是我們需要的關(guān)鍵參數(shù)浪讳。

企業(yè)微信

記好這個東西之后缰盏,我們轉(zhuǎn)到應(yīng)用管理
企業(yè)微信

這個創(chuàng)建就是你添張圖片打個名字而已淹遵,不多說口猜,創(chuàng)建完成之后我們來看下圖的標記。
企業(yè)微信

記好這兩個參數(shù)透揣,OK济炎,下來我們就來看API吧,這里我只是介紹下消息推送辐真。
微信等相關(guān)的第三方開發(fā)大致流程都類似须尚,如下:

  1. 注冊賬號(這不廢話么)
  2. 賬號認證(為了權(quán)限,當然企業(yè)微信內(nèi)部應(yīng)用不需要)
  3. 服務(wù)域名確定好
  4. AppID侍咱、Secret等等的配置(為了accesstoken)
  5. 幾乎所有的接口都是先獲取accesstoken耐床,相當于你在微信的登錄
  6. 根據(jù)接口文檔來傳參啊獲取回調(diào)啊獲取事件等等
  7. 根據(jù)返回值來看看錯誤信息

我這里不做服務(wù)端,只是寫個示例楔脯,需要服務(wù)端什么的開發(fā)之類的可以給我聯(lián)系撩轰,互相學(xué)習。

首先昧廷,在我們的Util新建一個類QyThirdUtil(名字感覺起的好沒水平钧敞,玩游戲止于起名字,別人都10級了麸粮,我還在想名字)溉苛,先把我們需要的配置信息搞了。

        private static string _CorpID = string.Empty;
        private static string _Secret = string.Empty;
        private static string _AgentID = string.Empty;
        /// <summary>
        /// 企業(yè)微信id
        /// </summary>
        public static string CorpID
        {
            get
            {
                if (string.IsNullOrEmpty(_CorpID))
                {
                    _CorpID = AprilConfig.Configuration["QyThird:CorpID"];
                }
                return _CorpID;
            }
        }
        /// <summary>
        /// 企業(yè)微信應(yīng)用秘鑰
        /// </summary>
        public static string Secret
        {
            get
            {
                if (string.IsNullOrEmpty(_Secret))
                {
                    _Secret = AprilConfig.Configuration["QyThird:Secret"];
                }
                return _Secret;
            }
        }
        /// <summary>
        /// 企業(yè)微信應(yīng)用id
        /// </summary>
        public static string AgentID
        {
            get
            {
                if (string.IsNullOrEmpty(_Secret))
                {
                    _AgentID = AprilConfig.Configuration["QyThird:AgentID"];
                }
                return _AgentID;
            }
        }

然后我們來劃分下方法弄诲,我們需要獲取accesstoken愚战,需要執(zhí)行發(fā)送消息的方法。

        /// <summary>
        /// 獲取AccessToken
        /// </summary>
        /// <returns></returns>
        public static string GetAccessToken()
        {
            QyAccessToken accessToken = null;
            bool isGet = false;
            if (CacheUtil.Exists("QyAccessToken"))
            {
                accessToken = CacheUtil.Get<QyAccessToken>("QyAccessToken");
                if (accessToken.Expire_Time >= DateTime.Now.AddMinutes(1))
                {
                    isGet = true;
                }
            }
            if (!isGet)
            {
                string url = $"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={CorpID}&corpsecret={Secret}";
                //請求獲取
                string res = RequestUtil.HttpGet(url);
                accessToken = JsonConvert.DeserializeObject<QyAccessToken>(res);
                if (accessToken != null && accessToken.ErrCode == 0)
                {
                    accessToken.Expire_Time = DateTime.Now.AddSeconds(accessToken.Expires_In);
                    CacheUtil.Set("QyAccessToken", accessToken, new TimeSpan(2, 0, 0));
                }
                else
                {
                    LogUtil.Error($"獲取accesstoken失敗——{accessToken.ErrCode},{accessToken.ErrMsg}");
                }
            }

            return accessToken.Access_Token;
        }

這里用到了兩個地方齐遵,一個是微信端回調(diào)的對象實例QyAccessToken寂玲,需要的朋友可以在源碼里cv,我這里就不貼出來了梗摇。

另一個是HttpClient的簡單封裝請求方法RequestUtil拓哟,看了有些博客說HttpClient的生命周期之類的,有推薦直接實例化一個私有靜態(tài)的伶授,也有做工廠模式創(chuàng)建的断序,沒細究流纹,這塊兒要多注意下。

    public class RequestUtil
    {

        /// <summary>
        /// 發(fā)起POST同步請求
        /// </summary>
        /// <param name="url">請求地址</param>
        /// <param name="postData">請求數(shù)據(jù)</param>
        /// <param name="contentType">數(shù)據(jù)類型</param>  
        /// <param name="timeOut">超時時間</param>  
        /// <returns></returns>
        public static string HttpPost(string url, string postData = null, string contentType = null, int timeOut = 30)
        {
            if (string.IsNullOrEmpty(postData))
            {
                postData = "";
            }
            using (HttpClient client = new HttpClient())
            {
                client.Timeout = new TimeSpan(0, 0, timeOut);
                using (HttpContent httpContent = new StringContent(postData, Encoding.UTF8))
                {
                    if (contentType != null)
                        httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);

                    HttpResponseMessage response = client.PostAsync(url, httpContent).Result;
                    return response.Content.ReadAsStringAsync().Result;
                }
            }
        }


        /// <summary>
        /// 發(fā)起POST異步請求
        /// </summary>
        /// <param name="url">請求地址</param>
        /// <param name="postData">請求數(shù)據(jù)</param>
        /// <param name="contentType">數(shù)據(jù)類型</param>
        /// <param name="timeOut">超時時間</param>      
        /// <returns></returns>
        public static async Task<string> HttpPostAsync(string url, string postData = null, string contentType = null, int timeOut = 30)
        {
            if (string.IsNullOrEmpty(postData))
            {
                postData = "";
            }
            using (HttpClient client = new HttpClient())
            {
                client.Timeout = new TimeSpan(0, 0, timeOut);
                using (HttpContent httpContent = new StringContent(postData, Encoding.UTF8))
                {
                    if (contentType != null)
                        httpContent.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue(contentType);

                    HttpResponseMessage response = await client.PostAsync(url, httpContent);
                    return await response.Content.ReadAsStringAsync();
                }
            }
        }

        /// <summary>
        /// 發(fā)起GET同步請求
        /// </summary>
        /// <param name="url">請求地址</param>
        /// <returns></returns>
        public static string HttpGet(string url)
        {
            using (HttpClient client = new HttpClient())
            {
                return client.GetStringAsync(url).Result;
            }
        }

        /// <summary>
        /// 發(fā)起GET異步請求
        /// </summary>
        /// <param name="url">請求地址</param>
        /// <returns></returns>
        public static async Task<string> HttpGetAsync(string url)
        {
            using (HttpClient client = new HttpClient())
            {
                HttpResponseMessage response = await client.GetAsync(url);
                return await response.Content.ReadAsStringAsync();
            }
        }
    }

然后我們來寫個發(fā)送消息的方法SendMessage违诗,這里我只寫了下普通文本推送漱凝。

        /// <summary>
        /// 消息推送
        /// </summary>
        /// <param name="content">文本內(nèi)容</param>
        /// <param name="range">推送范圍</param>
        /// <param name="messageType">消息類型</param>
        /// <returns></returns>
        public static bool SendMessage(string content, MessageRange range, AprilEnums.MessageType messageType)
        {
            bool isSend = false;
            if (string.IsNullOrEmpty(content) || content.Length > 2048 || range==null)
            {
                return false;
            }
            string accessToken = GetAccessToken();
            if (string.IsNullOrEmpty(accessToken))
            {
                return false;
            }
            string url = $"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={accessToken}";
            StringBuilder data = new StringBuilder();
            bool isVaildRange = false;
            if (range.IsAll)
            {
                data.Append($"\"touser\":\"@all\"");
                isVaildRange = true;
            }
            else
            {
                if (range.Users != null && range.Users.Count > 0)
                {
                    data.AppendFormat("\"touser\" : {0}", GetRangeValue(range.Users));
                    isVaildRange = true;
                }

                if (range.Tags != null && range.Tags.Count > 0)
                {
                    if (data.Length > 0)
                    {
                        data.Append(",");
                    }
                    data.AppendFormat("\"totag\" : {0}", GetRangeValue(range.Tags));
                    isVaildRange = true;
                }

                if (range.Departments != null && range.Departments.Count > 0)
                {
                    if (data.Length > 0)
                    {
                        data.Append(",");
                    }
                    data.AppendFormat("\"totag\" : {0}", GetRangeValue(range.Departments));
                    isVaildRange = true;
                }
            }
            if (!isVaildRange)
            {
                //沒有發(fā)送范圍
                return false;
            }
            data.AppendFormat(",\"msgtype\":\"{0}\"", GetMessageType(messageType));
            data.AppendFormat(",\"agentid\":\"{0}\"", AgentID);
            data.Append(",\"text\": {");
            data.AppendFormat("\"content\":\"{0}\"", content);
            data.Insert(0, "{");
            data.Append("}}");
            LogUtil.Debug($"獲取到發(fā)送消息請求:{data.ToString()}");
            string res = RequestUtil.HttpPost(url, data.ToString(), "application/json");
            LogUtil.Debug($"獲取到發(fā)送消息回調(diào):{res}");

            return false;
        }

簡單說下消息推送,第一個就是你的推送類型诸迟,是普通文本還是啥(文檔都有茸炒,我這凈扯淡),然后就是你的范圍阵苇,再然后就是你的推送內(nèi)容了壁公,當然根據(jù)不同的推送類型你的內(nèi)容參數(shù)也不同,需要進一步封裝的朋友可以去看下API绅项。

測試

我們在控制器中(不再說Values了)加上消息推送的測試紊册,這里的范圍可以在你自己的通訊錄中查看。

        [HttpGet]
        public ActionResult<IEnumerable<string>> Get()
        {
            //…
            MessageRange range = new MessageRange();
            range.Users = new List<string>();
            range.Users.Add("10001");
            QyThridUtil.SendMessage("我就是來測試", range, AprilEnums.MessageType.Text);
            //…
        }
測試
測試

小結(jié)

寫到這里基本上都結(jié)束了趁怔,為什么我特意拿出來企業(yè)微信的內(nèi)部應(yīng)用來寫這篇呢湿硝,其實是做下這個消息推送薪前,以后的自己的工程就可以寫個這個然后做異常警告之類的東西润努,這樣想想這篇就不是廢話了,編程的奇淫技巧(咳咳示括,樂趣铺浇,樂趣)就在于此,代碼自己敲垛膝,東西自己組鳍侣,全在于你自己怎么玩了。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末吼拥,一起剝皮案震驚了整個濱河市倚聚,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌凿可,老刑警劉巖惑折,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異枯跑,居然都是意外死亡惨驶,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進店門敛助,熙熙樓的掌柜王于貴愁眉苦臉地迎上來粗卜,“玉大人,你說我怎么就攤上這事纳击⌒樱” “怎么了攻臀?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長测砂。 經(jīng)常有香客問我茵烈,道長,這世上最難降的妖魔是什么砌些? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任呜投,我火速辦了婚禮,結(jié)果婚禮上存璃,老公的妹妹穿的比我還像新娘仑荐。我一直安慰自己,他們只是感情好纵东,可當我...
    茶點故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布粘招。 她就那樣靜靜地躺著,像睡著了一般偎球。 火紅的嫁衣襯著肌膚如雪洒扎。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天衰絮,我揣著相機與錄音袍冷,去河邊找鬼。 笑死猫牡,一個胖子當著我的面吹牛胡诗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淌友,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼煌恢,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了震庭?” 一聲冷哼從身側(cè)響起瑰抵,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎器联,沒想到半個月后二汛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡主籍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年习贫,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片千元。...
    茶點故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡苫昌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出幸海,到底是詐尸還是另有隱情祟身,我是刑警寧澤奥务,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站袜硫,受9級特大地震影響氯葬,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜婉陷,卻給世界環(huán)境...
    茶點故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一帚称、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧秽澳,春花似錦闯睹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至妄讯,卻和暖如春孩锡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背亥贸。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工躬窜, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人砌函。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓斩披,卻偏偏與公主長得像溜族,于是被迫代替她去往敵國和親讹俊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容

  • 1煌抒、開啟公眾號開發(fā)者模式 公眾平臺的技術(shù)文檔目的為了簡明扼要的交代接口的使用仍劈,語句難免苦澀難懂,甚至對于不同的讀者...
    good7758閱讀 1,521評論 0 1
  • 說明:本文是根據(jù)自己在 LeetCode 中文網(wǎng)站上發(fā)布的題解寫成的寡壮,即自己轉(zhuǎn)載了自己的文章贩疙。原文地址:https...
    李威威閱讀 271評論 0 0
  • 01 一起謀殺案这溅,不!也可能是自殺棒仍。 對于報案人兼嫌疑人的陳旭來說悲靴,簡直就是奇恥大辱。 晚櫻靜靜舒展著花瓣莫其,印在夜...
    花落誰心閱讀 1,091評論 15 4
  • /鐘楚白 我沒有從容地活著 也不能從容地死去 讓我慌張的癞尚,讓我哭泣 如何還有更悲傷耸三,一場兩場雨 你追逐風 我追逐你
    ALei鐘楚白閱讀 235評論 0 0