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);

                         }
                     }
                 });
             }
         });
     },

image

原文地址:https://www.cnblogs.com/LiangSW/p/6236444.html