2016项目经验总结

经验总结

一年多也做了不少项目,遇到不少坑,也遇到很多的麻烦,有苦恼也有喜悦。这里就记载一些较为实用的项目经验

文件上传进度条

上传大文件时,客户端到服务器也是需要时间的,所以也要有一个这样的进度条。使用jquery的ajax,可以利用 xhr方法,创建一个新的xhr对象,然后使用xhr.upload.addEventListener绑定progress事件, e.loaded/e.total*100 得到的值就是我们想要的进度

关于EF

EF用的差,会感觉满是坑。用的好会感觉轻松愉快。EF可以尝试使用CodeFirst模式使用面向对象思维来建立良好的表结构,并且在web项目中的global的application_strat方法中进行EF预热。尝试使用乐观锁控制并发。

Mvc的扩展

  • mvc有好用的模型验证,也可以继承ValidationAttribute自定义attribute验证注解,有其它的需求也可以直接继承IValidatableObject接口实现Validate方法来实现更定制化的验证。封装model.isvalid方法到attribute中,去除重复代码

  • 用好filter,对于异常处理,日志记录等使用filter来进行处理会显的干净利索。
  • 自己实现审计日志时想要拿到方法上的注册,可以在项目属性中选择生成xml文档,但是需要注册的是在发布后不会有xml文件,所以选择把xml文件生成到app_data文件夹下是不错的选择。对于多个项目xml文件名称不一致的的情况通常有两种选择

把名称换成一致的

在config文件中加上节点,value写成项目名称,然后再拿到项目名称。加载xml文件

var proejctName = ConfigurationManager.AppSettings["ProjectName"] as string;
  • 封装上下文对象,继承controller类重写Initialize方法。在上下文对象中添加我们的常用信息,比如当前登陆人或是否是ajax请求等,对于cshtml想要使用@上下文对象的方式进行使用,可以创建一个类去继承WebViewPage类重写InitHelpers方法,替换ViewContext.Controller,并在webconfig中进行修改pages节点
<pages pageBaseType="WebWorkContextWebViewPage">

AutoMapper

AutoMapper是个好东西,简单且高效,但是其实大部分使用者都是使用Mapper.Map方法来进行转换,用过EF的人一般都知道,EF生成的语句一般都是select [xxx],[xxx] from xxx,也就是说把所有的字段都查询出来的,但是一般情况下是使用不了这么多字段,就会造成性能浪费。使用AutoMapper针对IQueryable的扩展ProjectTo,可以针对我们的dto里的字段来生成相应的sql语句。

总之就是尽量打造扁平化的Dto

其它

  • 对于逻辑问题,避免使用if else、switch case进行判断,并且尝试使用设计模式

比如查询订单是否支付时,一般会有支付宝、银联、微信等支付方式,对于某个项目具有什么支付方式可以提前进行配置,比如使用attribute,使用策略模式进行封装算法来写出良好的代码。使用委托来进行回调

再比如不同项目下的订单可能会分为不同的来源,一般可能在表中使用orderSouceId来进行区分,但是进行获取订单的时候使用if判断来源获得sourceId是不好的行为,三四个项目就会让if else变的无比恶心,可以在项目的枚举使用attribute进行注解,然后再拿到attribute中的sourceId,可以轻松解决这类问题

  • 一般的三层架构中,逻辑层因为需求越来越多,类会变的越来越大超过几千行代码都是经常有的事,这就会带来困惑。对象.出的大量方法找起来比较困难不说类也会变的很臃肿,这时可以使用扩展方法来扩展类,并且针对某个类的不同扩展分出不同的命名空间,比如注册的扩展,命名空间可以写成 Bll.UserRole.Register。我们在展现层里只需要引用 Bll.UserRole.Register,点出来的方法简单清爽

  • 多写注解

WebApi

写接口的时候,会因为写文档更感到头疼。不同的项目用到相同的接口,还要再写一份相同的文档是件非常恶心的事情 ,而且人工去写还可能会因为一些疏忽而带来麻烦。

使用Swagger来生成在线文档不错的选择, Swagger也为我们留出了大量的扩展、对于请求header中的参数,可以通过继承IOperationFilter来进行实现

/// <summary>
        /// 设置请求参数,放到header中
        /// </summary>
        public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
        {
            if (operation.parameters == null) operation.parameters = new List<Parameter>();

            operation.parameters.Add(new Parameter
            {
                name = "Source",
                @in = "header",
                description = "来源",
                required = true,
                type = "string"
            });
        }
    }

对于某个接口用到上传功能,但是swagger没有给我们提供这样的参数(因为它不知道),我们也可以通过配置来实现,这里有一个契约,也就是如果方法名中带有Upload就提供一个file的参数,也是同样继承 IOperationFilter

//如果方法名里包含upload,则提供一个参数名为file类型为file的参数
            if (apiDescription.ActionDescriptor.ActionName.Contains("Upload"))
            {
                operation.consumes.Add("application/form-data");
                operation.parameters.Add(new Parameter
                {
                    name = "file",
                    @in = "formData",
                    required = true,
                    type = "file"
                });
            }

swagger生成的文档中只是有资源的名称,并没有controller的注释。一个不太熟悉的人看起来也是会有点懵比,网上有相关资料,大家可以针对性的去搜索一下,但是我看到的一些,注释在文档中不是很容易观察到,所以就对js进行了一些修改,让注解更容易看到

//设置控制器注释
     _setControllerSummary = function () {
         $.ajax({
             type: "get",
             async: true,
             url: $("#input_baseUrl").val(),
             dataType: "json",
             success: function (data) {
                 var summaryDict = data.ControllerDesc;
                 var id, controllerName, strSummary;
                 $("#resources_container .resource").each(function (i, item) {
                     id = $(item).attr("id");
                     if (id) {
                         controllerName = id.substring(9);
                         strSummary = summaryDict[controllerName];
                         if (strSummary) {

                             var value = $(item).children(".heading").find("h2").find("a").text();
                             $(item).children(".heading").find("h2").find("a").text(value + " " + strSummary);

                         }
                     }
                 });
             }
         });
     },

时间: 2024-10-10 00:42:44

2016项目经验总结的相关文章

Lync 项目经验-14-为某客户用Exchange 2016 UM作为总机的问题

值得高兴的事: 在中国! 在我的客户中! 有使用Exchange Server 2016 UM作为总机的客户! 传说中:都只有老外用UM来干活! 问题: 当手机拔总机,再拔#,再拔分机号! 如果客户端设置的在20秒内转语音邮箱!结果:不到20秒,如果不接,自动挂断! 如果客户端设置的在15秒内转语音邮箱!结果:不到15秒,如果不接,自动转语音邮箱! 测试过程: 微软统一沟通企业应用之语音邮箱当IVR使用: 1. 手机 136xxxxxxxx 2. 企业总机: 010-88xxxx88-AA-38

Lync 项目经验-13-为某上市企业仅安装Skype for Business 2016(图解)

****************************************************************************** <Skype for Business Server 2015-项目实战>(免费系列规划.部署博文) http://dynamic.blog.51cto.com/711418/1655481 **************************************************************************

Lync 项目经验-08-Polycom CX700-4.0.X-能登录SFB 2015-能更新为中文

本系列博文: Lync 项目经验-01-共存迁移-Lync2013-TO-SFB 2015-规划01http://dynamic.blog.51cto.com/711418/1858520 Lync 项目经验-02-共存迁移-Lync2013-TO-SFB 2015-规划02http://dynamic.blog.51cto.com/711418/1859143 Lync 项目经验-03-共存迁移-Lync2013-TO-SFB 2015-完成 http://dynamic.blog.51cto

Lync 项目经验-01-共存迁移-Lync 2013-TO-SFB 2015-规划01

项目环境: A. 产品 Lync Server 2013. B. 服务器角色 后端服务器.前端服务器.持久聊天服务器.边缘服务器.公网证书(非角色,但重要). C. 服务器角色(未利用) 监控服务器.存档服务器.中介服务器.语音网关.Office Web Apps Server. D. 功能 内部外部手机登录.音频.视频.共享(应用程序.白板.桌面等).文件传输. Lync Server 2013与公共IM联盟MSN.Skype. Lync Server 2013与公共IM企业联盟Lync Se

Lync 项目经验-02-共存迁移-Lync 2013-TO-SFB 2015-规划02

本系列博文: Lync 项目经验-01-共存迁移-Lync 2013-TO-SFB 2015-规划01http://dynamic.blog.51cto.com/711418/1858520 Lync 项目经验-02-共存迁移-Lync 2013-TO-SFB 2015-规划02http://dynamic.blog.51cto.com/711418/1859143 项目规划: 1. 为了后续的高可用,后面所做的所有规划,都是参照这个原则来做. 2. 所有操作系统使用Windows Server

Lync 项目经验-12-为某上市企业Skype for Business购买Godday证书

<要想看Lync 2013升级SFB 2015真实项目经验:请看Lync 项目经验-01-到-Lync 项目经验-10> 本系列博文: Lync 项目经验-01-共存迁移-Lync2013-TO-SFB 2015-规划01http://dynamic.blog.51cto.com/711418/1858520 Lync 项目经验-02-共存迁移-Lync2013-TO-SFB 2015-规划02http://dynamic.blog.51cto.com/711418/1859143 Lync

佩特来项目经验小集合(2)___组合查询存储过程,报错 &amp;quot;varchar JBID=&amp;#39;&amp;#39; 转换成数据类型 int 时失败&amp;quot;

今天写一个组合查询的存储过程遇到这样一个问题:在将 varchar 值 'SELECT * FROM View_DLS_WXJD_Customer WHERE 1=1 and JBID ='' 转换成数据类型 int 时失败.错误详情如图所看到的: 经百度:字符串变量和整型变量连接不能用+连接. 于是我採用cast()函数将DLSJB这个整型变量转换成字符串,这样问题就攻克了. 正确代码例如以下所看到的: ALTER PROCEDURE [dbo].[Proc_SH_WXJDList] @DH

java程序员面试----交流项目经验(摘自百度)

1:请你介绍一下你自己这是面试官常问的问题. 2:说说你的家庭面试时询问家庭问题不是非要知道求职者家庭情况,探究隐私,而是要了解家庭背景对求职者的塑造和影响.面试官希望听到的重点也在于家庭对求职者的积极影响. 3:说说你的最大优缺点这个问题的概率很大,面试官喜欢求职者从自己的优点说起,中间加一些小缺点,最后再把问题转回到优点上,突出优点的部分. 4:就你申请的这个职位,你认为你还缺什么?面试官喜欢问求职者的弱点,但精明的求职者一般不直接回答.他们希望看到这样的求职者:继续重复自己的优势,然后说:

佩特来项目经验小集合(2)___组合查询存储过程,报错 &quot;varchar JBID=&#39;&#39; 转换成数据类型 int 时失败&quot;

今天写一个组合查询的存储过程遇到这样一个问题:在将 varchar 值 'SELECT * FROM View_DLS_WXJD_Customer WHERE 1=1 and JBID ='' 转换成数据类型 int 时失败.错误详情如图所示: 经百度:字符串变量和整型变量连接不能用+连接.于是我采用cast()函数将DLSJB这个整型变量转换成字符串,这样问题就解决了.正确代码如下所示: ALTER PROCEDURE [dbo].[Proc_SH_WXJDList] @DH varchar(