• 微小黑开发笔记


    一.说明

      用c#基于.net 平台的MVC框架开发的微网站。

    二.对象实体映射框架

      1.Entity Framework:https://msdn.microsoft.com/en-us/library/jj592674(v=vs.113).aspx  CodeFirst技术

        1.1常用的数据库操作  

    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.创建数据库    

        [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;
            }
    封装DbContext

        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:      

    modelBuilder.Entity<BlogUser>().HasKey(user => user.UserId);
    modelBuilder.Entity<BlogUser>().Property(user => user.BlogName).IsRequired();
    View Code

     三.使用面向对象操作数据库

      1.Sql  LinqSql LinqEntity

       例如:查询Score表中至少有5名学生选修的并以3开头的课程的平均分数。  

    select avg(degree) from score where cno like '3%' group by Cno having count(*)>=5
    Sql
            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)
    LinqSql
     Scores.Where( s => s.CNO.StartsWith("3") )
                .GroupBy( s => s.CNO )
                  .Where( cc => ( cc.Count() >= 5) )
                    .Select( cc => cc.Average( c => c.DEGREE) )
    LinqEntity

     四.路由

            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  

      从controller获取客户端传值的方式

      1. 从context object 直接提取

      2. 通过参数传进来(由基类controller完成解析)

      3. 通过model binding

      

      context object常用的对象

    Request.QueryString

    从Get 请求的url中取

    Request.Form

    从Post请求的表单取

    Request.Cookies

    把值放在请求的cookie里带过来

    RouteData.Route

    从路由表里取注册的路由名

    RouteData.Values

    从路由表获取路由配置的匿名对象

    HttpContext.Cache

    应用程序缓存

    HttpContext.Items

    存储一些值,只在同一请求中使用(可以在httppipeline过程的不同module,handler,以及页面传递值)

    HttpContext.Session

    当前用户的session

      

      常用的result:

    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=" 35px; " value="11" />
                    </div>
                </div>
            }
        </div>
    视图层CSHTML

     七.接入微信第三方

      微信公众平台: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;
            }
    View Code

        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);
            }
    View Code

          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);
            }
    View Code

          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);
            }
    View Code

        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;
            }
    View Code

          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;
            }
    View Code

          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;
            }
    View Code

          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>
    View Code

         7.微信支付 https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=11_1

        

      

  • 相关阅读:
    [BZOJ1934][Shoi2007]Vote 善意的投票[最小割]
    [BZOJ1066][SCOI2007]蜥蜴[最大流]
    [BZOJ2818][P2568]Gcd[欧拉函数]
    [BZOJ2208][P4306][JSOI2010]连通数[bitset优化floyd]
    [BZOJ1877][SDOI2009]晨跑[最大流+费用流]
    [BZOJ1040][P2607][ZJOI2008]骑士[树形DP+基环树]
    [BZOJ5347]冒泡排序[思维]
    [BZOJ2875][Noi2012]随机数生成器[等比数列求和+取模]
    [bzoj2809] 派遣
    [bzoj1965] 洗牌
  • 原文地址:https://www.cnblogs.com/liandy0906/p/8276656.html
Copyright © 2020-2023  润新知