你的位置:首页 > ASP.net教程

[ASP.net教程]通过实例学习Fireasy开发(补充)


      本文目录

      通过实例学习Fireasy开发(上篇)

      通过实例学习Fireasy开发(中篇)

      通过实例学习Fireasy开发(下篇)

      通过实例学习Fireasy开发(补充)

 

 

      前面的功能已经开发完成了,但是这里专门用一章来进行补充。

 

      一、EasyUI验证

      不知道你有没有发现,我们虽然在EmployeeMetada里加了验证特性RequiredAttribute、StringLengthAttribute,但是页面并没有在data-options里生成validType。这是由于少了Fireasy.Portal组件造成了。我们只需要把ValidateBoxSettingBinder和NumberBoxSettingBinder这两个类拷贝过来就行了。

      ValidateBoxSettingBinder主要负责将基本的验证绑定到ValidateBoxSettings对象的ValidType属性中。

  /// <summary>  /// <see cref="ValidateBoxSettings"/> 的绑定者。  /// </summary>  public class ValidateBoxSettingBinder : ISettingsBinder  {    public bool CanBind(ISettingsBindable settings)    {      return typeof(ValidateBoxSettings).IsAssignableFrom(settings.GetType());    }    public void Bind(Type modelType, string propertyName, ISettingsBindable settings)    {      //模型类型必须实现自 IEntity      if (!typeof(IEntity).IsAssignableFrom(modelType))      {        return;      }      //获取对应的依赖属性      var property = PropertyUnity.GetProperty(modelType, propertyName);      if (property == null)      {        return;      }      var vsettings = settings as ValidateBoxSettings;      //获取依赖属性所指定的验证特性      var validTypes = new List<string>();      foreach (var validation in ValidationUnity.GetValidations(property))      {        ParseValidation(vsettings, validation, validTypes);      }      vsettings.ValidType = validTypes.ToArray();    }    /// <summary>    /// 解析 <see cref="ValidationAttribute"/> 对象。    /// </summary>    /// <param name="settings"></param>    /// <param name="validation">要解析的 <see cref="ValidationAttribute"/> 对象。</param>    /// <param name="validTypes">如果 <paramref name="validation"/> 能与 EasyUI 的客户端验证所对应,则添加到 validType 属性中。</param>    private void ParseValidation(ValidateBoxSettings settings, ValidationAttribute validation, List<string> validTypes)    {      //必填验证特性      var required = validation as RequiredAttribute;      if (required != null)      {        settings.Required = true;        return;      }      //长度验证特性      var stringLength = validation as StringLengthAttribute;      if (stringLength != null)      {        validTypes.Add(string.Format("length[{0},{1}]", stringLength.MinimumLength, stringLength.MaximumLength));        return;      }      //电话验证特性      var telphone = validation as TelphoneAttribute;      if (telphone != null)      {        validTypes.Add("phone");        return;      }      //手机验证特性      var mobile = validation as MobileAttribute;      if (mobile != null)      {        validTypes.Add("mobile");        return;      }      //手机或电话验证特性      var telOrMobile = validation as TelphoneOrMobileAttribute;      if (telOrMobile != null)      {        validTypes.Add("phoneOrMobile");        return;      }      //邮箱验证特性      var email = validation as EmailAttribute;      if (email != null)      {        validTypes.Add("email");        return;      }      var ascii = validation as AsciiCodingAttribute;      if (ascii != null)      {        validTypes.Add("ascii");        return;      }      var un = validation as UserNameAttribute;      if (un != null)      {        validTypes.Add("username");        return;      }      var chinese = validation as ChineseCodingAttribute;      if (chinese != null)      {        validTypes.Add("chinese");      }    }  }

      NumberBoxSettingBinder主要负责把小数位、最大值、最小值绑定到NumberBoxSettings对象中。

  /// <summary>  /// <see cref="NumberBoxSettings"/> 的绑定者。  /// </summary>  public class NumberBoxSettingBinder : ISettingsBinder  {    public bool CanBind(ISettingsBindable settings)    {      return typeof(NumberBoxSettings).IsAssignableFrom(settings.GetType());    }    public void Bind(Type modelType, string propertyName, ISettingsBindable settings)    {      var nsettings = settings as NumberBoxSettings;      if (!typeof(IEntity).IsAssignableFrom(modelType))      {        return;      }      //获取对应的依赖属性      var property = PropertyUnity.GetProperty(modelType, propertyName);      if (property == null)      {        return;      }      nsettings.Precision = property.Info.Scale;      //找 RangeAttribute 特性      var range = ValidationUnity.GetValidations(property).Where(s => s is RangeAttribute).Cast<RangeAttribute>().FirstOrDefault();      if (range != null)      {        nsettings.Min = range.Minimum.To<decimal?>();        nsettings.Max = range.Maximum.To<decimal?>();      }    }  }

      最后,在global.asax的Application_Start方法里,加入以下的代码:

    protected void Application_Start(object sender, EventArgs e)    {      //资源打包配置      BundleHelper.Config();      //默认是使用MEF导出服务的,改成使用aspx对应的类文件作为服务      HttpConfiguration.Default.ServiceFactory = new AspPageServiceFactory();      //配置http服务的路由,依子目录的级数而定      HttpConfiguration.MapHttpRoute("{service}.ajx/{action}");      HttpConfiguration.MapHttpRoute("{p1}/{service}.ajx/{action}");      HttpConfiguration.MapHttpRoute("{p1}/{p2}/{service}.ajx/{action}");      HttpConfiguration.MapHttpRoute("{p1}/{p2}/{p3}/{service}.ajx/{action}");      SettingsBindManager.RegisterBinder("validatebox", new ValidateBoxSettingBinder());      SettingsBindManager.RegisterBinder("numberbox", new NumberBoxSettingBinder());    }

      为了达到效果,我们修改一下WebApplication1.Data项目下的EmployeeMetadata类(在Employee_Ex.cs文件内),为Mobile加上手机验证,为Name、Post、Sex和Birthday加上必填验证。

  public class EmployeeMetadata  {        /// <summary>    /// 属性 Id 的验证特性。    /// </summary>        [Required]    [StringLength(36)]    public object Id { get; set; }    /// <summary>    /// 属性 DeptId 的验证特性。    /// </summary>        [Required]    [StringLength(36)]    public object DeptId { get; set; }    /// <summary>    /// 属性 No 的验证特性。    /// </summary>        [StringLength(20)]    public object No { get; set; }    /// <summary>    /// 属性 Sex 的验证特性。    /// </summary>    
[Required] public object Sex { get; set; } /// <summary> /// 属性 Name 的验证特性。 /// </summary> [Required] [StringLength(20)] public object Name { get; set; } /// <summary> /// 属性 Birthday 的验证特性。 /// </summary> [Required] public object Birthday { get; set; } /// <summary> /// 属性 Post 的验证特性。 /// </summary> [Required] public object Post { get; set; } /// <summary> /// 属性 Mobile 的验证特性。 /// </summary> [Fireasy.Data.Validation.Mobile] [StringLength(20)] public object Mobile { get; set; } /// <summary> /// 属性 Address 的验证特性。 /// </summary> [StringLength(100)] public object Address { get; set; } /// <summary> /// 属性 Description 的验证特性。 /// </summary> [StringLength(500)] public object Description { get; set; } /// <summary> /// 属性 State 的验证特性。 /// </summary> public object State { get; set; } /// <summary> /// 属性 DelFlag 的验证特性。 /// </summary> public object DelFlag { get; set; } /// <summary> /// 属性 Photo 的验证特性。 /// </summary> [StringLength(200)] public object Photo { get; set; } }

      好了,我们现在来看看EmployeeEdit.aspx有表单有没有加上数据验证:

 

 

      二、数据列表的排序

      datagrid的columns中,我们默认生成了sortable属性,但是后台代码中并没有使用排序。其实代码是生成了的,只需将注释行Order(sorting)取消就要以了。

    /// <summary>    /// 根据查询条件获取员工。    /// </summary>    /// <param name="deptNo">部门编码。</param>    /// <param name="startTime">开始日期。</param>    /// <param name="endTime">结束时间。</param>    /// <param name="post">岗位类别。</param>    /// <param name="keyword">关键字</param>    /// <returns></returns>    [ExceptionBehavior(true)]    public object GetEmployees(string deptNo, DateTime? startTime, DateTime? endTime, PostKinds? post, string keyword)    {      var pager = EasyUIHelper.GetDataPager();      var sorting = EasyUIHelper.GetSorting();      using (var context = new DbContext())      {        var list = context.Employees          .Segment(pager)          .OrderBy(sorting)          .AssertWhere(!string.IsNullOrEmpty(deptNo), s => s.Dept.No.StartsWith(deptNo))          .AssertWhere(startTime != null, s => s.Birthday >= startTime.Value.StartOfDay())          .AssertWhere(endTime != null, s => s.Birthday <= endTime.Value.EndOfDay())          .AssertWhere(post != null, s => s.Post == post)          .AssertWhere(!string.IsNullOrEmpty(keyword), s => s.Name.Contains(keyword))          .Select(s => new            {              s.Id,              s.No,              s.Name,              Sex = ((Sex)s.Sex).GetDescription(),              Post = s.Post.GetDescription(),              s.Birthday,              s.Mobile,              s.Address,              s.Description            })          .ToList();        return EasyUIHelper.Transfer(pager, list);      }    }

      但有一种情况,即没有单击列头的情况下,默认使用某一属性排序,比如按编码降序排列,这时,Order方法可以这样写:

    /// <summary>    /// 根据查询条件获取员工。    /// </summary>    /// <param name="deptNo">部门编码。</param>    /// <param name="startTime">开始日期。</param>    /// <param name="endTime">结束时间。</param>    /// <param name="post">岗位类别。</param>    /// <param name="keyword">关键字</param>    /// <returns></returns>    [ExceptionBehavior(true)]    public object GetEmployees(string deptNo, DateTime? startTime, DateTime? endTime, PostKinds? post, string keyword)    {      var pager = EasyUIHelper.GetDataPager();      var sorting = EasyUIHelper.GetSorting();      using (var context = new DbContext())      {        var list = context.Employees          .Segment(pager)          .OrderBy(sorting, u => u.OrderByDescending(t => t.No))          .AssertWhere(!string.IsNullOrEmpty(deptNo), s => s.Dept.No.StartsWith(deptNo))          .AssertWhere(startTime != null, s => s.Birthday >= startTime.Value.StartOfDay())          .AssertWhere(endTime != null, s => s.Birthday <= endTime.Value.EndOfDay())          .AssertWhere(post != null, s => s.Post == post)          .AssertWhere(!string.IsNullOrEmpty(keyword), s => s.Name.Contains(keyword))          .Select(s => new            {              s.Id,              s.No,              s.Name,              Sex = ((Sex)s.Sex).GetDescription(),              Post = s.Post.GetDescription(),              s.Birthday,              s.Mobile,              s.Address,              s.Description            })          .ToList();        return EasyUIHelper.Transfer(pager, list);      }    }

 

      三、图片上传

      员工表设计了一个照片的字段,但是之前我们并没有用到它,现在我们就把照片上传给加上。

      首先,要引入上传所需的js,只需要在 BundleHelper.Render 后面再加上 upload 就可以了。

  <%= BundleHelper.Render("base", "upload") %>

    接下来修改一下表单的table,加一个图片和上传图片的链接:

    <table class="form-body">      <tr>        <td class="addon">部门</td>        <td><%= Html.ComboBox(s => s.DeptId).MarkDelayedSet().MarkNoClear()%></td>        <td rowspan="4" style="text-align:center">          <img id="img" src="../Images/nopic1.png" style="width: 161px; height: 110px" /><br />          <a target="#img" class="uploader">上传图片</a>        </td>      </tr>      <tr>        <td class="addon">编号</td>        <td><%= Html.TextBox(s => s.No) %></td>      </tr>      <tr>        <td class="addon">性别</td>        <td><%= Html.ComboBox(s => s.Sex, typeof(WebApplication.Data.Model.Sex), new ComboBoxSettings { PanelHeight = 0 }).MarkNoClear() %></td>      </tr>      <tr>        <td class="addon">姓名</td>        <td><%= Html.TextBox(s => s.Name) %></td>      </tr>      <tr>        <td class="addon">出生日期</td>        <td><%= Html.DateBox(s => s.Birthday) %></td>      </tr>      <tr>        <td class="addon">职务</td>        <td><%= Html.ComboBox(s => s.Post, typeof(WebApplication.Data.Model.PostKinds), new ComboBoxSettings { PanelHeight = 0 }).MarkNoClear() %></td>      </tr>      <tr>        <td class="addon">手机号码</td>        <td><%= Html.TextBox(s => s.Mobile) %></td>      </tr>      <tr>        <td class="addon">家庭住址</td>        <td><%= Html.TextBox(s => s.Address) %></td>      </tr>      <tr>        <td class="addon">个人说明</td>        <td colspan="3"><%= Html.TextMultiBox(s => s.Description) %></td>      </tr>      <tr>        <td class="addon">可用</td>        <td><%= Html.CheckBox(s => s.State, true) %></td>      </tr>    </table>

      增加一个initUploader函数,用于添加“上传图片”的事件初始化,并在页面加载完成后调用initUploader函数:

    $(function () {      loadInfo();      initUploader();    });    //初始化上传插件    function initUploader() {      $('.uploader').upload({        extFilter: 'png;jpg;jpeg;gif',        action: 'EmployeeEdit.ajx/UploadPhoto?id=' + id,        useHttpModule: false,        onFileExtError: function () {          common.alert('只允许上传png、jpg、jpeg、gif类型的文件。')        },        onComplete: function (result, index, ele) {          $(ele.attr('target')).attr('src', '../' + result.fileName);          $(ele.attr('target')).attr('file', result.fileName);          if (id != '') {            var data = { id: id, url: encodeURI(result.fileName) };            $.post('EmployeeEdit.ajx/UpdatePhoto', data);          }        }      });    }

      upload是一个jquery插件,可以为.uploader标签添加上传文件的事件。上传的处理请求是UploadPhoto方法,上传完后,更新员工的照片,即不需要点击保存按钮,也能生效。在EmployeeEdit.aspx.cs里增加UploadPhoto方法:

    /// <summary>    /// 上传照片。    /// </summary>    /// <returns></returns>    public object UploadPhoto()    {      ServiceContext.Current.ResultWriter = new FileUploadResultWriter();      var request = HttpContext.Current.Request;      if (request.Files.Count == 0)      {        return null;      }      var file = request.Files[0];      var virtualPath = "upfiles\\photos";      var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, virtualPath);      if (!Directory.Exists(path))      {        Directory.CreateDirectory(path);      }      var fileId = Guid.NewGuid().ToString();      var fileExt = file.FileName.Substring(file.FileName.LastIndexOf("."));      var fileName = Path.Combine(path, fileId + fileExt);      var virtualFile = Path.Combine(virtualPath, fileId + fileExt).Replace("\\", "/");      file.SaveAs(fileName);      return Result.Success("上传成功。", new { fileId, fileName = virtualFile });    }

      DefaultResultWriter用于改变content-type,因为默认是使用application/json的,但是此时它会提示下载json,因此把content-type改成text/json即可。

  /// <summary>  /// 针对文件上传的结果写入器。  /// </summary>  public class FileUploadResultWriter : DefaultResultWriter  {    protected override void WriteJson(ServiceContext serviceContext, HttpResponseBase response, object value)    {      response.ContentType = "text/json";      response.Write(JsonSerialize(serviceContext, value));    }  }

      再增加一个UpdatePhoto方法,只用更新实体的Photo属性就可以了:

    /// <summary>    /// 更新照片路径。    /// </summary>    /// <param name="id"></param>    /// <param name="url"></param>    public void UpdatePhoto(string id, string url)    {      using (var context = new DbContext())      {        context.Employees.Update(new Employee { Photo = url }, s => s.Id == id);      }    }

      最后,在EmployeeEdit.aspx中修改loadInfo函数的saveInfo函数如下:

    //加载信息    function loadInfo() {      if (id != '') {        $.getJSON('EmployeeEdit.ajx/GetEmployee?id=' + id, function (data) {          common.processResult(data, function () {            $('#form1').form('load', data);            deptId = data.DeptId;            loadDepts();            if (data.Photo) {              $('#img').attr('file', data.Photo);              $('#img').attr('src', data.Photo);            }          });        });        $('#btnSaveAndNew').remove();      }      else {        loadDepts();      }    }    //保存信息    function saveInfo(isNew) {      if (!$('#form1').form('validate')) {        return;      }      var postData = new Object();      //将表单填充的内容序列化为json      var data = $('#form1').form('save');      data.DeptId = $('#cboDeptId').combotree('getValue');      data.Photo = $('#img').attr('file');      postData["info"] = JSON.stringify(data);      common.showProcess();      $.post('EmployeeEdit.ajx/SaveEmployee?id=' + id, postData, function (result) {        common.processResult(result, function () {          if (isNew) {            $('#form1').form('clear');          }          id = isNew ? '' : result.data;          common.setReturnValue(true);        });      });    }

      照片上传至此结束。

 

 

      非常感谢你的支持,在此附上示例的源代码:

      ★★★源代码下载★★★