微小黑开发笔记

一.说明

  用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=" width: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

    

  

posted @ 2018-01-12 16:52  连先森  阅读(412)  评论(0编辑  收藏  举报