• 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

  • 相关阅读:
    eclipse优化与标准化记录
    eclipse easyexplorer openexplorer
    java获取class所在jar
    ajax提交复杂对象数据
    bootstrap dialog自行控制窗口的关闭
    jquery重置html form
    html button自动提交表单问题
    jquery TypeError: 'undefined' is not a function (evaluating 'elem.nodeName.toLowerCase()') [jquery.js:1904]错误原因
    推荐两个很好用的javascript模板引擎
    API的非向后兼容性无论如何通常代表着一种比较差的设计
  • 原文地址:https://www.cnblogs.com/LiangSW/p/6236444.html
Copyright © 2020-2023  润新知