一.說明javascript
用c#基於.net 平臺的MVC框架開發的微網站。php
二.對象實體映射框架html
1.Entity Framework:https://msdn.microsoft.com/en-us/library/jj592674(v=vs.113).aspx CodeFirst技術java
1.1經常使用的數據庫操做 git
using (var context = new BloggingContext()) { var blog = new Blog { Name = "ADO.NET Blog" }; context.Entry(blog).State = EntityState.Added; context.SaveChanges(); }
var existingBlog = new Blog { BlogId = 1, Name = "ADO.NET Blog" }; using (var context = new BloggingContext()) { context.Blogs.Attach(existingBlog); // Do some more work... context.SaveChanges(); }
1.2.建立數據庫 github
[Serializable] [DataContract] [Table("WxStoreTB")] public class WxStoreTB : ModelBase { public WxStoreTB() { StoreBackground = "/Content/Images/adminbanner.jpg"; } [DataMember] public string DistributorSlogan { get; set; } [DataMember] public string StoreLogo { get; set; } [DataMember] public string StoreBackground { get; set; } [DataMember] public string IndexBackgroundMusic { get; set; } [DataMember] public string EnglishName { get; set; } [DataMember] public string QRCodeImage { get; set; } [DataMember] /// <summary> /// 店鋪ID /// </summary> public int StoreTBID { get; set; } }
public class DbContextBase : DbContext, IDataRepository, IDisposable { public DbContextBase(string connectionString) { this.Database.Connection.ConnectionString = connectionString; this.Configuration.LazyLoadingEnabled = false; this.Configuration.ProxyCreationEnabled = false; } public DbContextBase(string connectionString, IAuditable auditLogger) : this(connectionString) { this.AuditLogger = auditLogger; } public IAuditable AuditLogger { get; set; } public T Update<T>(T entity, bool isSave = true) where T : ModelBase { var set = this.Set<T>(); set.Attach(entity); this.Entry<T>(entity).State = EntityState.Modified; if (isSave) { this.SaveChanges(); } return entity; }
1.3對象關係映射:算法
1.3.1Data Annotations:缺點是污染域模型 數據庫
[DataContract] [Table("PageTB")] public class PageTB : ModelBase { /// <summary> ///店鋪ID /// </summary> [DataMember] [ForeignKey("StoreTB")] public int StoreTBID { get; set; } /// <summary> ///頁面類別 0:首頁 1:其餘 /// </summary> [DataMember] public int PageType { get; set; } /// <summary> ///頁面名稱 /// </summary> [DataMember] public string GuidNumber { get; set; } /// <summary> ///頁面路徑(站點根目錄爲起始的相對路徑) /// </summary> [DataMember] public string PagePath { get; set; } /// <summary> ///標題 /// </summary> [DataMember] public string Title { get; set; } /// <summary> /// 是否已上架 /// </summary> [DataMember] public bool IsOnShelf { get; set; } /// <summary> /// 版本號 空則放在商戶目錄下 /// </summary> [DataMember] public string Version { get; set; } }
1.3.2Fluent API: json
modelBuilder.Entity<BlogUser>().HasKey(user => user.UserId);
modelBuilder.Entity<BlogUser>().Property(user => user.BlogName).IsRequired();
三.使用面向對象操做數據庫c#
1.Sql LinqSql LinqEntity
例如:查詢Score表中至少有5名學生選修的並以3開頭的課程的平均分數。
select avg(degree) from score where cno like '3%' group by Cno having count(*)>=5
from s in Scores where s.CNO.StartsWith("3") group s by s.CNO into cc where cc.Count() >= 5 select cc.Average( c => c.DEGREE)
Scores.Where( s => s.CNO.StartsWith("3") ) .GroupBy( s => s.CNO ) .Where( cc => ( cc.Count() >= 5) ) .Select( cc => cc.Average( c => c.DEGREE) )
四.路由
protected void Application_Start() { AreaRegistration.RegisterAllAreas(); WebApiConfig.Register(GlobalConfiguration.Configuration); RegisterGlobalFilters(GlobalFilters.Filters); RegisterRoutes(RouteTable.Routes); //定時任務 JobManager.Initialize(new MyRegistry()); }
public class MobileAreaRegistration : AreaRegistration { public override string AreaName { get { return "Mobile"; } } public override void RegisterArea(AreaRegistrationContext context) { context.MapRoute( "Mobile_default", "Mobile/{controller}/{action}/{id}", new { action = "Index", id = UrlParameter.Optional }, namespaces: new[] { "MiLai.Web.Admin.Areas.Mobile.Controllers" } ); } }
五.控制器 Controller
1. 從context object 直接提取
2. 經過參數傳進來(由基類controller完成解析)
3. 經過model binding
Request.QueryString |
從Get 請求的url中取 |
Request.Form |
從Post請求的表單取 |
Request.Cookies |
把值放在請求的cookie裏帶過來 |
RouteData.Route |
從路由表裏取註冊的路由名 |
RouteData.Values |
從路由表獲取路由配置的匿名對象 |
HttpContext.Cache |
應用程序緩存 |
HttpContext.Items |
存儲一些值,只在同一請求中使用(能夠在httppipeline過程的不一樣module,handler,以及頁面傳遞值) |
HttpContext.Session |
當前用戶的session |
ViewResult |
返回一個view,能夠指定不一樣的controller |
ParcialViewResult |
返回部分view |
RedirectToActionResult |
轉到另外一個action |
RedirectResult |
返回301或者302(permanent) |
JsonResult |
返回js最喜歡的json,經常使用,尤爲當前段打算採用純js template,或者single page application |
FileResult |
文件result |
ContentResult |
字符串 |
HttpUnauthorizedResult |
401,一般,會自動跳轉到登錄頁面 |
HttpNotFoundResult |
404 |
六.Razor模板引擎(CSHTML)
@{ ViewBag.Title = "Index"; Layout = "~/Views/Shared/_Layout.cshtml"; var request = ViewData["request"] as CourseRequest; var categoryList = ViewData["categoryList"] as List<int>; } @using Qxun.Framework.Contract @using Qxun.Framework.Utility @using Qxun.Framework.Web.Controls @using MiLai.Shop.Contract.Model @model PagedList<CourseTB> <div class="row picListBox" id="albumContainer"> @foreach (var item in Model) { <!--圖片組件的邊框--> <div class="picModuleBox" id="picbox_1"> <a data-fancybox-group="gallery" href="javascript:void 0;" onclick="videoplay('@item.MasterImage','@item.VedioPath')" title="a"> <img src="@item.MasterImage" /> </a> <div class="overLay"></div> <h1> <span class="info" style=""><a id="remark_1">@item.Remark</a></span></h1> <div class="checkBox"> <input type="checkbox" name='ids' value='@item.ID' /><span id="title_1" class="itemName">@item.Title</span> </div> <div class="functionBox"> <a class="" href="@Url.Action("Edit", new { id = item.ID })">編輯</a> <input id="1" type="text" class="InpSort" style=" width:35px; " value="11" /> </div> </div> } </div>
七.接入微信第三方
微信公衆平臺:https://mp.weixin.qq.com/advanced/selfmenu?action=index&t=advanced/menu-setting&token=2122708442&lang=zh_CN
微信測試公衆平臺:https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login
開發文檔:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1445241432
1.基本配置
設置的服務器地址url要能正確的響應微信服務器發送過來的請求,參考:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1434696670
public ActionResult Index(string signature, string timestamp, string nonce, string echostr,string encrypt_type, string msg_signature) { try { var token = CachedConfigContext.Current.WeixinConfig.Token; if (string.IsNullOrEmpty(token)) return Content("請先設置Token!"); var ent = ""; if (!BasicAPI.CheckSignature(signature, timestamp, nonce, token, out ent)) { LogHelper.WCInfo("CheckSignature:" + "CheckSignatureError"); return Content("參數錯誤!"); } LogHelper.WCInfo("驗證經過"); var streamReader = new StreamReader(Request.InputStream); var msg = streamReader.ReadToEnd(); streamReader.Dispose(); LogHelper.WCInfo("msg:" + msg); var decryptMsg = string.Empty; SortedDictionary<string, object> result = new SortedDictionary<string, object>(); var wxBizMsgCrypt = new WXBizMsgCrypt( CachedConfigContext.Current.WeixinConfig.Token, CachedConfigContext.Current.WeixinConfig.EncodingAESKey, CachedConfigContext.Current.WeixinConfig.AppID); var ret = wxBizMsgCrypt.DecryptMsg(msg_signature, timestamp, nonce, msg, ref decryptMsg); LogHelper.WCInfo("ret:" + ret); if (ret == 0) { result = DataConvertHelper.FromXml(decryptMsg); foreach (var item in result) { LogHelper.WCInfo(string.Format("微信預受權方面的推送信息:key={0} => value={1}", item.Key, item.Value)); } string openID = (string)result["FromUserName"]; WxUserTB fromWxUser = ServiceContext.Current.HuiXianUserService.GetWxUser(u => u.OpenId == openID); if (result.ContainsKey("EventKey") && fromWxUser != null) { int menuID = 0; try { menuID = Convert.ToInt32(result["EventKey"]); } catch (Exception e) { LogHelper.WCInfo(e.Message); } if (menuID > 0) { var setting = ServiceContext.Current.HuiXianCmsService.GetWxSetting(); WeixinMenuTB weixinMenu = ServiceContext.Current.WeixinService.GetWeixinMenu(menuID); if (weixinMenu != null) { if (weixinMenu.MaterialID > 0) { WeixinMaterialTB weixinMaterial = ServiceContext.Current.WeixinMaterialService.GetMaterial(weixinMenu.MaterialID); if (weixinMaterial != null) { if (!string.IsNullOrEmpty(weixinMaterial.MediaId)) { WeixinMaterialSubTB weixinMaterialSub = ServiceContext.Current.WeixinMaterialService.GetFirstMaterialSub(weixinMaterial.ID); if (weixinMenu.Type == "click") { //微信菜單點擊後被動回覆圖文消息 WeixinNews news = new WeixinNews { picurl =CachedConfigContext.Current.WeixinConfig.Domain+ weixinMaterialSub.ImageUrl, title = weixinMaterialSub.Title, description = weixinMaterialSub.Content, url = weixinMaterialSub.Url }; string repayResult = ReplayPassiveMessageAPI.RepayNews(fromWxUser.OpenId, "gh_117ef9c5cdee", news); LogHelper.WCInfo("repayResult:" + repayResult); return Content(repayResult); } } else { LogHelper.WCInfo("微信素材還沒有上傳至微信服務器"); } } else { LogHelper.WCInfo("微信素材不存在"); } } else { //若是菜單未關聯素材 默認就發微信二維碼 if (string.IsNullOrEmpty(fromWxUser.media_id)) { fromWxUser.QRCode= ServiceContext.Current.HuiXianUserService.GetWxUserQRCode(fromWxUser); LogHelper.WCInfo("QRCode:" + fromWxUser.QRCode); } string imgurl = CachedConfigContext.Current.WeixinConfig.Domain + fromWxUser.QRCode; WebRequest request = HttpWebRequest.Create(imgurl); var response = request.GetResponse(); Stream stream = response.GetResponseStream(); int pos = imgurl.LastIndexOf("/"); string fileName = imgurl.Substring(pos + 1); LogHelper.WCInfo("fileName:" + fileName); ResultData ResultData = MaterialAPI.AddMaterial(setting.AccessToken, "image", fileName, stream); LogHelper.WCInfo("ResultData:" + JsonConvert.SerializeObject(ResultData)); string media_id = (string)ResultData.media_id; LogHelper.WCInfo("media_id:" + media_id); if (!string.IsNullOrEmpty(media_id)) { fromWxUser.media_id = media_id; ServiceContext.Current.HuiXianUserService.UpdateWxUser(fromWxUser); string repayResult = ReplayPassiveMessageAPI.ReplayImage(fromWxUser.OpenId, "gh_117ef9c5cdee", media_id); return Content(repayResult); } } } else { LogHelper.WCInfo("微信菜單不存在"); } } else { LogHelper.WCInfo("菜單不存在"); } } } LogHelper.WCInfo("END"); } catch (Exception e) { LogHelper.WCInfo(e.Message); } return Content(echostr); //返回隨機字符串則表示驗證經過 }
1.獲取access_token(調用接口的令牌) https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140183
1.1 第三方程序集 定時任務執行器 FluentScheduler :https://github.com/fluentscheduler/FluentScheduler
1.2調用接口獲取access_token
public static dynamic GetAccessToken(string appid, string secrect) { var url = string.Format("https://api.weixin.qq.com/cgi-bin/token?grant_type={0}&appid={1}&secret={2}", "client_credential", appid, secrect); var client = new HttpClient(); var result = client.GetAsync(url).Result; if (!result.IsSuccessStatusCode) return string.Empty; var token = DynamicJson.Parse(result.Content.ReadAsStringAsync().Result); return token; }
2.用戶自定義菜單 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013
3.新增素材 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1494572718_WzHIY
public static ResultData AddNews(string access_token, List<WeixinArtcle> articles) { var url = string.Format("https://api.weixin.qq.com/cgi-bin/material/add_news?access_token={0}", access_token); var client = new HttpClient(); var atrticle = DynamicJson.Serialize(articles); var builder = new StringBuilder(); builder .Append("{") .Append('"' + "articles" + '"' + ":").Append(atrticle) .Append("}"); var result = client.PostAsync(url, new StringContent(builder.ToString())).Result; if (!result.IsSuccessStatusCode) return null; else { return DynamicJson.Parse(result.Content.ReadAsStringAsync().Result); } }
4.模板消息 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751277
5.網頁受權 https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140842
public ActionResult OAuth(string state) { this.WxUserCookie = ""; var domain = CachedConfigContext.Current.WeixinConfig.Domain; var appId = CachedConfigContext.Current.WeixinConfig.AppID; var redirect_uri = System.Web.HttpUtility.UrlEncode(string.Format("{0}/Mobile/WCUser/Callback", domain)); LogHelper.WCInfo(string.Format("微信受權redirect_uri:{0}/Mobile/WCUser/Callback", domain)); var weixinOAuth2Url = string.Format( "https://open.weixin.qq.com/connect/oauth2/authorize?appid={0}&redirect_uri={1}&response_type=code&scope={2}&state={3}#wechat_redirect", appId, redirect_uri, "snsapi_userinfo", state); LogHelper.WCInfo("微信受權weixinOAuth2Url:" + weixinOAuth2Url); return Redirect(weixinOAuth2Url); }
5.1網頁受權回調
用戶贊成受權後頁面將跳轉至 redirect_uri/?code=CODE&state=STATE
5.2獲取網頁受權access_token
public static dynamic GetAccessToken(string code, string appId, string appSecret) { var client = new HttpClient(); var result = client.GetAsync(string.Format("https://api.weixin.qq.com/sns/oauth2/access_token?appid={0}&secret={1}&code={2}&grant_type=authorization_code", appId, appSecret, code)).Result; if (!result.IsSuccessStatusCode) return null; return DynamicJson.Parse(result.Content.ReadAsStringAsync().Result); }
5.3拉取用戶信息
public static dynamic GetUserInfo(string accessToekn, string openId, string lang = "zh_CN") { var client = new HttpClient(); var result = client.GetAsync(string.Format("https://api.weixin.qq.com/sns/userinfo?access_token={0}&openid={1}&lang={2}", accessToekn, openId, lang)).Result; if (!result.IsSuccessStatusCode) return null; return DynamicJson.Parse(result.Content.ReadAsStringAsync().Result); }
6.JS-SDK https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141115
6.1獲取jsapi_ticket
public static dynamic GetTickect(string access_token) { var url = string.Format("https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token={0}&type=jsapi", access_token); var client = new HttpClient(); var result = client.GetAsync(url).Result; if (!result.IsSuccessStatusCode) return string.Empty; var jsTicket = DynamicJson.Parse(result.Content.ReadAsStringAsync().Result); return jsTicket; }
6.2簽名算法
public static string GetSignature(string jsapi_ticket, string noncestr, long timestamp, string url, out string string1)
{
var string1Builder = new StringBuilder();
string1Builder.Append("jsapi_ticket=").Append(jsapi_ticket).Append("&")
.Append("noncestr=").Append(noncestr).Append("&")
.Append("timestamp=").Append(timestamp).Append("&")
.Append("url=").Append(url.IndexOf("#") >= 0 ? url.Substring(0, url.IndexOf("#")) : url);
string1 = string1Builder.ToString();
return Util.Sha1(string1);
public static string Sha1(string orgStr, string encode = "UTF-8")
{
var sha1 = new SHA1Managed();
var sha1bytes = System.Text.Encoding.GetEncoding(encode).GetBytes(orgStr);
byte[] resultHash = sha1.ComputeHash(sha1bytes);
string sha1String = BitConverter.ToString(resultHash).ToLower();
sha1String = sha1String.Replace("-", "");
return sha1String;
}
6.3建立JSSDK對象
public static JSSDKModel GetJsSdk(string ticket,string appID,string requestUrl,string shareUrl,string shareImg,string title,string shareDesc)
{
var nonceStr = Guid.NewGuid().ToString("N");
string message = "";
var timeStamp = DateTimeHelper.DateTimeToUnixTimestamp(DateTime.Now);
var signature = JSAPI.GetSignature(ticket, nonceStr, timeStamp, requestUrl, out message);
var model = new JSSDKModel()
{
appId = appID,
nonceStr = nonceStr,
signature = signature,
timestamp = timeStamp,
jsapiTicket = ticket,
shareUrl =shareUrl,
shareImg = shareImg,
title = title,
desc = shareDesc
};
return model;
}
6.4嵌入js腳本
<script src="http://res.wx.qq.com/open/js/jweixin-1.0.0.js" type="text/javascript"></script> <script> (function(){ wx.config({ debug: true, // 開啓調試模式,調用的全部api的返回值會在客戶端alert出來,若要查看傳入的參數,能夠在pc端打開,參數信息會經過log打出,僅在pc端時纔會打印。 appId: '', // 必填,公衆號的惟一標識 timestamp: , // 必填,生成簽名的時間戳 nonceStr: '', // 必填,生成簽名的隨機串 signature: '',// 必填,簽名,見附錄1 jsApiList: [] // 必填,須要使用的JS接口列表,全部JS接口列表見附錄2 }); wx.ready(function(){ execute(); // config信息驗證後會執行ready方法,全部接口調用都必須在config接口得到結果以後,config是一個客戶端的異步操做,因此若是須要在頁面加載時就調用相關接口,則須把相關接口放在ready函數中調用來確保正確執行。對於用戶觸發時才調用的接口,則能夠直接調用,不須要放在ready函數中。 }); })() function execute() { var title = "@ViewBag.JSSDK.title"; // 分享標題 var link = '@Server.UrlDecode(ViewBag.JSSDK.shareUrl)'; // 分享連接 var imgUrl = '@ViewBag.JSSDK.shareImg'; // 分享圖標 var desc = "@ViewBag.JSSDK.desc"; // 分享描述 wxJs.showmenu(); //朋友圈 wxJs.onMenuShareAppMessage({ title: title, link: link, imgUrl: imgUrl, desc: desc, ok: function () { //分享成功後,增長分享記錄 jsprint("分享成功", "", "success"); }, cancel: function () { jsprint("分享取消", "", "error"); } }); //轉發給朋友的 wxJs.onMenuShareTimeline({ title: title, link: link, imgUrl: imgUrl, ok: function () { jsprint("分享成功", "", "success"); }, cancel: function () { jsprint("分享取消", "", "error"); } }); //var latitude = 0; //var longitude = 0; //wx.getLocation({ // success: function (res) { // //獲取經緯度數值 按照,分割字符串 取出前兩位 解析成浮點數 // latitude=res.latitude; // longitude=res.longitude; // }, // cancel: function (res) { // alert('用戶拒絕受權獲取地理位置'); // } //}); //wx.openLocation({ // latitude: latitude, // longitude: longitude, // name: '測試地址', // address: '廣州市海珠區新港中路 397 號', // scale: 14, // infoUrl: 'http://weixin.qq.com' //}); }) </script>
7.微信支付 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1