在"ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积01, 在控制台实现"中,在控制台应用程序中实现了属性值的笛卡尔乘积。本篇在界面中实现。需要实现的大致如下:

在界面中勾选CheckBoxList中属性值选项:

把勾选的属性值进行笛卡尔乘积,每行需要填写价格:

我们暂且不考虑这些CheckBoxList是如何显示出来的(在后续有关商品模块的文章中会实现),还需考虑的方面包括:

1、从CheckBoxList中获取到什么再往控制器传?

对于每行的CheckBoxList来说,可以从选项中拿到属性值的编号,还可以拿到属性的编号,最后我们拿到类似{ propId: 1, propOptionId: 1 },{ propId: 1, propOptionId: 2 }的数组或集合。

2、前台数组和集合如何传递才能确保被控制器接收?

通过jQuery.ajax方法可以实现,待会实现。

3、在呈现属性值和价格组合的界面是如何呈现的?

其实是通过部分视图来实现的,而且在一个主部分视图中嵌套了子部分视图。

4、如何对呈现的价格验证呢?

由于价格是被异步、动态加载到页面的,所以,这里还涉及到如何对异步加载的动态内容进行验证的问题。

关于属性的Model:

  1.     public class Prop
  2.  
  3.     {
  4.  
  5.         public int Id { get; set; }
  6.  
  7.         public string Name { get; set; }
  8.  
  9.     }

关于属性值的Model:

  1.     public class PropOption
  2.  
  3.     {
  4.  
  5.         public int Id { get; set; }
  6.  
  7.         public string RealValue { get; set; }
  8.  
  9.         public int PropId { get; set; }
  10.  
  11.     }

把从前台获取的属性和属性值编号封装到PropAndOption类中,前台向控制器传的就是这个类的集合。

  1.     public class PropAndOption
  2.  
  3.     {
  4.  
  5.         public int PropId { get; set; }
  6.  
  7.         public int propOptionId { get; set; }
  8.  
  9.     }   

模拟一个数据库存储层,无非就是获取数据等,可忽略。

  1. 展开 public static class Database
  2. {
  3. public static List<Prop> GetProps()
  4. {
  5. return new List<Prop>()
  6. {
  7. new Prop(){Id = 1, Name = "颜色"},
  8. new Prop(){Id = 2, Name = "尺寸"},
  9. };
  10. }
  11.  
  12. public static List<PropOption> GetPropOptions()
  13. {
  14. return new List<PropOption>()
  15. {
  16. new PropOption(){Id = 1, PropId = 1, RealValue = "红色"},
  17. new PropOption(){Id = 2, PropId = 1, RealValue = "蓝色"},
  18. new PropOption(){Id = 3, PropId = 1, RealValue = "黑色"},
  19. new PropOption(){Id = 4, PropId = 2, RealValue = "5.5英寸"},
  20. new PropOption(){Id = 5, PropId = 2, RealValue = "8.5英寸"},
  21. };
  22. }
  23.  
  24. //根据属性项的Id获取属性值
  25. public static string GetOptionValueById(int optionId)
  26. {
  27. return (GetPropOptions().Where(p => p.Id == optionId).FirstOrDefault()).RealValue;
  28. }
  29.  
  30. public static List<PropOption> GEtPropOptionsByPropId(int propId)
  31. {
  32. return GetPropOptions().Where(p => p.PropId == propId).ToList();
  33. }
  34. }
  35.  
  36. Home控制器的Index方法渲染Home/Index.cshtml视图,在这个页面中暂时属性值及价格的笛卡尔乘积。
  37.  
  38. public class HomeController : Controller
  39. {
  40. public ActionResult Index()
  41. {
  42. return View();
  43. }
  44.  
  45. ......
  46. }

在Home/Index.cshtml视图,把通过$.ajax异步动态加载的、有关属性值及价格笛卡尔乘积的部分视图,追加到页面上的一块区域。大致如下:

1、发出异步请求,把类似{ propId: 1, propOptionId: 1 }的数组传给控制器
2、控制器根据接收到的{ propId: 1, propOptionId: 1 }的数组,得到类似"红色 5英寸"的一个IEnumerable<string>类型的集合,通过ViewData传给_DisplaySKUs.cshtml部分视图
3、在_DisplaySKUs.cshtml,遍历类似"红色 5英寸"的一个IEnumerable<string>类型的集合,每遍历一次,再加载有关价格的一个强类型部分视图_SKUDetail.cshtml

4、最后把_DisplaySKUs.cshtml部分视图动态加载到Home/Index.cshtml视图的某块区域中

Home/Index.cshtml视图。

  1. @{
  2.  
  3.     ViewBag.Title = "Index";
  4.  
  5.     Layout = "~/Views/Shared/_Layout.cshtml";
  6.  
  7. }
  8.  
  9. <form id="fm">
  10.  
  11.     <ul id="skus">
  12.  
  13.     </ul>
  14.  
  15.     <input type="submit" value="提交"/>
  16.  
  17. </form>
  18.  
  19. @section scripts
  20.  
  21. {
  22.  
  23.     <script src="~/Scripts/jquery.validate.min.js"></script>
  24.  
  25.     <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
  26.  
  27.     <script src="~/Scripts/dynamicvalidation.js"></script>
  28.  
  29.     <script type="text/javascript">
  30.  
  31.         $(function () {
  32.  
  33.             var propAndOptions = [];
  34.  
  35.             propAndOptions.push({ propId: 1, propOptionId: 1 });
  36.  
  37.             propAndOptions.push({ propId: 1, propOptionId: 2 });
  38.  
  39.             propAndOptions.push({ propId: 1, propOptionId: 3 });
  40.  
  41.             propAndOptions.push({ propId: 2, propOptionId: 4 });
  42.  
  43.             propAndOptions.push({ propId: 2, propOptionId: 5 });
  44.  
  45.             $.ajax({
  46.  
  47.                 cache: false,
  48.  
  49.                 url: '@Url.Action("DisplaySKUs", "Home")',
  50.  
  51.                 contentType: 'application/json; charset=utf-8',
  52.  
  53.                 dataType: "html",
  54.  
  55.                 type: "POST",
  56.  
  57.                 data: JSON.stringify({ 'propAndOptions': propAndOptions }),
  58.  
  59.                 success: function (data) {
  60.  
  61.                     $('#skus').html(data);
  62.  
  63.                 },
  64.  
  65.                 error: function (jqXhr, textStatus, errorThrown) {
  66.  
  67.                     alert("出错了 '" + jqXhr.status + "' (状态: '" + textStatus + "', 错误为: '" + errorThrown + "')");
  68.  
  69.                 }
  70.  
  71.             });
  72.  
  73.         });
  74.  
  75.     </script>
  76.  
  77. }
  78.  

以上,
{ propId: 1, propOptionId: 1 }这个匿名对象的propIdpropOptionId键必须和PropAndOption类的属性对应
$.ajax方法中,contentType表示传递给控制器的数据类型
$.ajax方法中,dataType表示返回的数据类型,由于返回的是部分视图,所以这里的类型是html
○ 通过JSON.stringify方法把{ propId: 1, propOptionId: 1 }类型数组转换成json格式
$('#skus').html(data)把_DisplaySKUs.cshtml部分视图动态加载到id为skus的区域

HomeController

  1.    public class HomeController : Controller
  2.  
  3.     {
  4.  
  5.         public ActionResult Index()
  6.  
  7.         {
  8.  
  9.             return View();
  10.  
  11.         }
  12.  
  13.         [HttpPost]
  14.  
  15.         public ActionResult DisplaySKUs(List<PropAndOption> propAndOptions)
  16.  
  17.         {
  18.  
  19.             try
  20.  
  21.             {
  22.  
  23.                 //属性值分组
  24.  
  25.                 var groupValues = (from v in propAndOptions
  26.  
  27.                                    group v by v.PropId
  28.  
  29.                                        into grp
  30.  
  31.                                        select grp.Select(t => Database.GetOptionValueById(t.propOptionId))).ToList();
  32.  
  33.                 //属性值Id分组
  34.  
  35.                 var groupIds = (from i in propAndOptions
  36.  
  37.                                 group i by i.PropId
  38.  
  39.                                     into grep
  40.  
  41.                                     select grep.Select(t => t.propOptionId.ToString())).ToList();
  42.  
  43.                 //属性值分组后进行笛卡尔乘积
  44.  
  45.                 IEnumerable<string> values;
  46.  
  47.                 values = groupValues.First();
  48.  
  49.                 groupValues.RemoveAt(0);
  50.  
  51.                 groupValues.ForEach(delegate(IEnumerable<string> ele)
  52.  
  53.                 {
  54.  
  55.                     values = (from v in values
  56.  
  57.                               from e in ele
  58.  
  59.                               select v + " " + e).ToList();
  60.  
  61.                 });
  62.  
  63.                 //属性值Id分组后进行笛卡尔乘积
  64.  
  65.                 IEnumerable<string> ids;
  66.  
  67.                 ids = groupIds.First();
  68.  
  69.                 groupIds.RemoveAt(0);
  70.  
  71.                 groupIds.ForEach(delegate(IEnumerable<string> ele)
  72.  
  73.                 {
  74.  
  75.                     ids = (from i in ids
  76.  
  77.                            from e in ele
  78.  
  79.                            select i + "," + e).ToList();
  80.  
  81.                 });
  82.  
  83.                 //把笛卡尔积后的集合传递给前台
  84.  
  85.                 ViewData["v"] = values;
  86.  
  87.                 ViewData["i"] = ids;
  88.  
  89.             }
  90.  
  91.             catch (Exception)
  92.  
  93.             {
  94.  
  95.                 throw;
  96.  
  97.             }
  98.  
  99.             return PartialView("_DisplaySKUs");
  100.  
  101.         }
  102.  
  103.     }
  104.  

以上,部分视图_DisplaySKUs将会收到2种类型为IEnumerable<string>的集合,一种有关类似"红色 5英寸"属性值集合,一种是类似"1, 2"属性值ID集合,前者用来显示,后者需要被传递到有关价格的Model中,以便随同价格保存到数据库。和价格有关的Model是:

  1.     public class SKUVm
  2.  
  3.     {
  4.  
  5.         [Display(Name = "价格")]
  6.  
  7.         [Required(ErrorMessage = "必填")]
  8.  
  9.         [Range(typeof(Decimal), "0", "9999", ErrorMessage = "{0} 必须是数字介于 {1} 和 {2}之间.")]
  10.  
  11.         public decimal Price { get; set; }
  12.  
  13.         public string OptionIds { get; set; }
  14.  
  15.     }
  16.  

其中,OptionIds属性用来保存类似"1, 2"属性值ID,随同价格被保存到数据库。具体如何保存,这里略去,将在后续有关商品模块的文章中实现。

_DisplaySKUs.cshtml部分视图

  1. @{
  2.  
  3.     string[] values = (ViewData["v"] as IEnumerable<string>).ToArray();
  4.  
  5.     string[] ids = (ViewData["i"] as IEnumerable<string>).ToArray();
  6.  
  7. }
  8.  
  9. @for (int i = 0; i <values.Count(); i++)
  10.  
  11. {
  12.  
  13.     <li>
  14.  
  15.         <span>
  16.  
  17.             @values[@i]
  18.  
  19.         </span>
  20.  
  21.         <span class="s">
  22.  
  23.             @{
  24.  
  25.                 SKUVm skuVm = new SKUVm();
  26.  
  27.                 skuVm.OptionIds = ids[@i];
  28.  
  29.                 Html.RenderPartial("_SKUDetail", skuVm);
  30.  
  31.             }
  32.  
  33.         </span>
  34.  
  35.     </li>
  36.  
  37. }
  38.  

以上,遍历所有类似"红色 5英寸"属性值集合,用于显示,由于类似"1, 2"属性值ID集合与类似"红色 5英寸"属性值集合采用同样的算法、逻辑获取到的,所以两者有一一对应关系。在遍历类似"红色 5英寸"属性值集合的同时,把每一个类似"1, 2"属性值传给有关价格的强类型部分视图。

_SKUDetail.cshtml强类型部分视图。

  1. @model MvcApplication3.Models.SKUVm
  2.  
  3.     @Html.TextBoxFor(m => m.Price)
  4.  
  5.     @Html.ValidationMessageFor(m => m.Price)
  6.  
  7.     @Html.HiddenFor(m => m.OptionIds)
  8.  

大功告成!试着运行一下。wow......真如所愿!

再试下异步验证功能,居然没有?!

why?要知道,所有的异步验证与表单元素中以data-*开头的属性及其值有关。看来,还是有必要查看当前的表单元素。

可是,表单元素中明明已经有了以data-*开头的属性及其值啊?难道jquery.validate.unobtrusive在调用jquery.validatevalidate方法的时候,写法有问题?

  1. validate: function( options ) {
  2.  
  3. ......
  4.  
  5. // check if a validator for this form was already created
  6.  
  7. var validator = $.data(this[0], 'validator');
  8.  
  9. if ( validator ) {
  10.  
  11.   return validator;
  12.  
  13. }
  14.  
  15. ......

发现问题了:当调用validate方法的时候,jquery.validate.unobtrusive发现存在data-val="true"的表单元素,就会返回当前的validator对象而不做其它任何事。而实际上,对于动态加载的部分视图,它还没有自己的validator对象。所以,有必要专门针对动态加载的内容写一个$.validator.unobtrusive的扩展。

创建dynamicvalidation.js文件。

  1. //对动态生成内容客户端验证
  2.  
  3. (function ($) {
  4.  
  5.     $.validator.unobtrusive.parseDynamicContent = function (selector, formSelector) {
  6.  
  7.         $.validator.unobtrusive.parse(selector);
  8.  
  9.         var form = $(formSelector);
  10.  
  11.         var unobtrusiveValidation = form.data('unobtrusiveValidation');
  12.  
  13.         var validator = form.validate();
  14.  
  15.         $.each(unobtrusiveValidation.options.rules, function (elname, elrules) {
  16.  
  17.             if (validator.settings.rules[elname] == undefined) {
  18.  
  19.                 var args = {};
  20.  
  21.                 $.extend(args, elrules);
  22.  
  23.                 args.messages = unobtrusiveValidation.options.messages[elname];
  24.  
  25.                 //edit:use quoted strings for the name selector
  26.  
  27.                 $("[name='" + elname + "']").rules("add", args);
  28.  
  29.             } else {
  30.  
  31.                 $.each(elrules, function (rulename, data) {
  32.  
  33.                     if (validator.settings.rules[elname][rulename] == undefined) {
  34.  
  35.                         var args = {};
  36.  
  37.                         args[rulename] = data;
  38.  
  39.                         args.messages = unobtrusiveValidation.options.messages[elname][rulename];
  40.  
  41.                         //edit:use quoted strings for the name selector
  42.  
  43.                         $("[name='" + elname + "']").rules("add", args);
  44.  
  45.                     }
  46.  
  47.                 });
  48.  
  49.             }
  50.  
  51.         });
  52.  
  53.     };
  54.  
  55. })(jQuery);
  56.  

dynamicvalidation.js文件引入Home/Index.cshtml视图页,修改如下:

  1. ……
  2.  
  3. @section scripts
  4.  
  5. {
  6.  
  7.     <script src="~/Scripts/jquery.validate.min.js"></script>
  8.  
  9.     <script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
  10.  
  11.     <script src="~/Scripts/dynamicvalidation.js"></script>
  12.  
  13.     <script type="text/javascript">
  14.  
  15.         $(function () {
  16.  
  17.             var propAndOptions = [];
  18.  
  19.             propAndOptions.push({ propId: 1, propOptionId: 1 });
  20.  
  21.             propAndOptions.push({ propId: 1, propOptionId: 2 });
  22.  
  23.             propAndOptions.push({ propId: 1, propOptionId: 3 });
  24.  
  25.             propAndOptions.push({ propId: 2, propOptionId: 4 });
  26.  
  27.             propAndOptions.push({ propId: 2, propOptionId: 5 });
  28.  
  29.             $.ajax({
  30.  
  31.                 cache: false,
  32.  
  33.                 url: '@Url.Action("DisplaySKUs", "Home")',
  34.  
  35.                 contentType: 'application/json; charset=utf-8',
  36.  
  37.                 dataType: "html",
  38.  
  39.                 type: "POST",
  40.  
  41.                 data: JSON.stringify({ 'propAndOptions': propAndOptions }),
  42.  
  43.                 success: function (data) {
  44.  
  45.                     $('#skus').html(data);
  46.  
  47.                     $.each($('.s'), function(index) {
  48.  
  49.                         $.validator.unobtrusive.parseDynamicContent(this, "#fm");
  50.  
  51.                     });
  52.  
  53.                 },
  54.  
  55.                 error: function (jqXhr, textStatus, errorThrown) {
  56.  
  57.                     alert("出错了 '" + jqXhr.status + "' (状态: '" + textStatus + "', 错误为: '" + errorThrown + "')");
  58.  
  59.                 }
  60.  
  61.             });
  62.  
  63.         });
  64.  
  65.     </script>
  66.  
  67. }
  68.  

以上,当异步加载成功,遍历的类名为s的span,即有关价格强类型视图生成的地方,运用扩展方法。

再次运行,并测试异步验证。

亦喜亦忧,喜的是有了异步验证,忧的是虽然只有一个价格验证不通过,所有的价格都验证不通过!

再次查看表单元素:

我们发现:所有有关价格的强类型视图页中,name属性都是price,而以上的$.validator.unobtrusive.parseDynamicContent扩展方法是以name属性为依据的。所以,有必要为每一个有关价格的强类型视图生成不一样的name值。

写一个针对HtmlHelper的扩展方法,目标是生成如下格式:

  1.         //目标生成如下格式
  2.  
  3.         <input autocomplete="off" name="SomePropertion.Index" type="hidden" value="6d85a95b-1dee-4175-bfae-73fad6a3763b" />
  4.  
  5.         <label>Title</label>
  6.  
  7.         <input class="text-box single-line" name="SomePropertion[6d85a95b-1dee-4175-bfae-73fad6a3763b].Title" type="text" value="Movie 1" />
  8.  
  9.         <span class="field-validation-valid"></span>

以上的目的是让每一个有关价格的input元素的name属性值都不一样。

  1.     public static class CollectionEditingHtmlExtensions
  2.  
  3.     {
  4.  
  5.         //目标生成如下格式
  6.  
  7.         //<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="6d85a95b-1dee-4175-bfae-73fad6a3763b" />
  8.  
  9.         //<label>Title</label>
  10.  
  11.         //<input class="text-box single-line" name="FavouriteMovies[6d85a95b-1dee-4175-bfae-73fad6a3763b].Title" type="text" value="Movie 1" />
  12.  
  13.         //<span class="field-validation-valid"></span>
  14.  
  15.         public static IDisposable BeginCollectionItem<TModel>(this HtmlHelper<TModel> html, string collectionName)
  16.  
  17.         {
  18.  
  19.             //构建name="FavouriteMovies.Index"
  20.  
  21.             string collectionIndexFieldName = string.Format("{0}.Index", collectionName);
  22.  
  23.             //构建Guid字符串
  24.  
  25.             string itemIndex = GetCollectionItemIndex(collectionIndexFieldName);
  26.  
  27.             //构建带上集合属性+Guid字符串的前缀
  28.  
  29.             string collectionItemName = string.Format("{0}[{1}]", collectionName, itemIndex);
  30.  
  31.             TagBuilder indexField = new TagBuilder("input");
  32.  
  33.             indexField.MergeAttributes(new Dictionary<string, string>()
  34.  
  35.             {
  36.  
  37.                 {"name", string.Format("{0}.Index", collectionName)},
  38.  
  39.                 {"value", itemIndex},
  40.  
  41.                 {"type", "hidden"},
  42.  
  43.                 {"autocomplete", "off"}
  44.  
  45.             });
  46.  
  47.             html.ViewContext.Writer.WriteLine(indexField.ToString(TagRenderMode.SelfClosing));
  48.  
  49.             return new CollectionItemNamePrefixScope(html.ViewData.TemplateInfo, collectionItemName);
  50.  
  51.         }
  52.  
  53.         private class CollectionItemNamePrefixScope : IDisposable
  54.  
  55.         {
  56.  
  57.             private readonly TemplateInfo _templateInfo;
  58.  
  59.             private readonly string _previousPrfix;
  60.  
  61.             //通过构造函数,先把TemplateInfo以及TemplateInfo.HtmlFieldPrefix赋值给私有字段变量,并把集合属性名称赋值给TemplateInfo.HtmlFieldPrefix
  62.  
  63.             public CollectionItemNamePrefixScope(TemplateInfo templateInfo, string collectionItemName)
  64.  
  65.             {
  66.  
  67.                 this._templateInfo = templateInfo;
  68.  
  69.                 this._previousPrfix = templateInfo.HtmlFieldPrefix;
  70.  
  71.                 templateInfo.HtmlFieldPrefix = collectionItemName;
  72.  
  73.             }
  74.  
  75.             public void Dispose()
  76.  
  77.             {
  78.  
  79.                 _templateInfo.HtmlFieldPrefix = _previousPrfix;
  80.  
  81.             }
  82.  
  83.         }
  84.  
  85.         /// <summary>
  86.  
  87.         ///
  88.  
  89.         /// </summary>
  90.  
  91.         /// <param name="collectionIndexFieldName">比如,FavouriteMovies.Index</param>
  92.  
  93.         /// <returns>Guid字符串</returns>
  94.  
  95.         private static string GetCollectionItemIndex(string collectionIndexFieldName)
  96.  
  97.         {
  98.  
  99.             Queue<string> previousIndices = (Queue<string>)HttpContext.Current.Items[collectionIndexFieldName];
  100.  
  101.             if (previousIndices == null)
  102.  
  103.             {
  104.  
  105.                 HttpContext.Current.Items[collectionIndexFieldName] = previousIndices = new Queue<string>();
  106.  
  107.                 string previousIndicesValues = HttpContext.Current.Request[collectionIndexFieldName];
  108.  
  109.                 if (!string.IsNullOrWhiteSpace(previousIndicesValues))
  110.  
  111.                 {
  112.  
  113.                     foreach (string index in previousIndicesValues.Split(','))
  114.  
  115.                     {
  116.  
  117.                         previousIndices.Enqueue(index);
  118.  
  119.                     }
  120.  
  121.                 }
  122.  
  123.             }
  124.  
  125.             return previousIndices.Count > 0 ? previousIndices.Dequeue() : Guid.NewGuid().ToString();
  126.  
  127.         }
  128.  
  129.     }
  130.  

关于,CollectionEditingHtmlExtensions类,在"MVC批量更新,可验证并解决集合元素不连续控制器接收不完全的问题"中有详细说明。

最后,再次修改_SKUDetail.cshtml这个强类型部分视图。

  1. @using MvcApplication3.Extension
  2.  
  3. @model MvcApplication3.Models.SKUVm
  4.  
  5. @using (Html.BeginCollectionItem("ProductSkus"))
  6.  
  7. {
  8.  
  9.     @Html.TextBoxFor(m => m.Price)
  10.  
  11.     @Html.ValidationMessageFor(m => m.Price)
  12.  
  13.     @Html.HiddenFor(m => m.OptionIds)
  14.  
  15. }
  16.  

再次运行并测试异步验证,一切正常!

且在每个有关价格的强类型视图部分,有了一个隐藏域,存放这属性值的Id,这些Id可以随价格一起被保存到数据库。

ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积02, 在界面实现的更多相关文章

  1. ASP.NET MVC中实现属性和属性值的组合,即笛卡尔乘积01, 在控制台实现

    在电商产品模块中必经的一个环节是:当选择某一个产品类别,动态生成该类别下的所有属性和属性项,这些属性项有些是以DropDownList的形式存在,有些是以CheckBoxList的形式存在.接着,把C ...

  2. 关于ASP.NET MVC 中JsonResult返回的日期值问题

    最近开始用MVC做项目,在使用 JsonResult返回数据的时候,日期被反射成了/Date 1233455这种格式,遍查网上都是在客户端使用JS来处理这个问题的,这样的话,就需要在每一个涉及到日期的 ...

  3. ASP.Net MVC 中EF实体的属性取消映射数据库、自定义名称

    例如:数据库中一个字段名称为CompanyId 自定义实体数据名称 [Column("CompanyId")] public int Id{ get; set; } 这样就可以使用 ...

  4. ASP.NET MVC中商品模块小样

    在前面的几篇文章中,已经在控制台和界面实现了属性值的笛卡尔乘积,这是商品模块中的一个难点.本篇就来实现在ASP.NET MVC4下商品模块的一个小样.与本篇相关的文章包括: 1.ASP.NET MVC ...

  5. 在Asp.Net MVC中实现RequiredIf标签对Model中的属性进行验证

    在Asp.Net MVC中可以用继承ValidationAttribute的方式,自定制实现RequiredIf标签对Model中的属性进行验证 具体场景为:某一属性是否允许为null的验证,要根据另 ...

  6. 在Asp.Net MVC中实现CompareValues标签对Model中的属性进行验证

    在Asp.Net MVC中可以用继承ValidationAttribute的方式,自定制实现Model两个中两个属性值的比较验证 具体应用场景为:要对两个属性值的大小进行验证 代码如下所示: /// ...

  7. 如何在 ASP.NET MVC 中集成 AngularJS(3)

    今天来为大家介绍如何在 ASP.NET MVC 中集成 AngularJS 的最后一部分内容. 调试路由表 - HTML 缓存清除 就在我以为示例应用程序完成之后,我意识到,我必须提供两个版本的路由表 ...

  8. 如何在 ASP.NET MVC 中集成 AngularJS(2)

    在如何在 ASP.NET MVC 中集成 AngularJS(1)中,我们介绍了 ASP.NET MVC 捆绑和压缩.应用程序版本自动刷新和工程构建等内容. 下面介绍如何在 ASP.NET MVC 中 ...

  9. 《Entity Framework 6 Recipes》中文翻译系列 (20) -----第四章 ASP.NET MVC中使用实体框架之在MVC中构建一个CRUD示例

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第四章  ASP.NET MVC中使用实体框架 ASP.NET是一个免费的Web框架 ...

随机推荐

  1. linux修改文件打开最大数(ulimit命令)

    解除 Linux 系统的最大进程数和最大文件打开数限制:vi /etc/security/limits.conf# 添加如下的行* soft noproc 65536 * hard noproc 65 ...

  2. vs中如何统计整个项目的代码行数

    在一个大工程中有很多的源文件和头文件,如何快速统计总行数? ------解决方案--------------------b*[^:b#/]+.*$^b*[^:b#/]+.*$ ctrl + shift ...

  3. MVC layout 命名空间引用问题

    虽然用MVC做了很多项目,但是都是在别人搭好的框架上实现 今天碰到一个很简单的命名空间引用问题 如图所示,Scripts和Styles 都没有引用命名空间 解决方法一: 直接使用 System.Web ...

  4. 两种常量类型-readonly和const

    C#中有两种常量类型,分别为readonly(运行时常量)与const(编译时常量),本文将就这两种类型的不同特性进行比较并说明各自的适用场景. 工作原理 readonly 为运行时常量(动态常量), ...

  5. MongoDB存储基础教程

    一.MongoDB简介 1. mangodb是一种基于分布式.文件存储的非关系型数据库 2. C++写的,性能高 3. 为web应用提供可扩展的高性能数据存储解决方案 4. 所支持的格式是json格式 ...

  6. springmvc接收jquery提交的数组数据

    var selectedUsers = $('#users').tagbox('getValues'); if (selectedUsers.length > 0) { $.post(appPa ...

  7. ubuntu12.04安装maven

    step: 1,确认已经安装jdk, java --version 2,下载apache-maven-3.3.9 下载地址:http://maven.apache.org/download.cgi 3 ...

  8. Pandas DataFrame数据的增、删、改、查

    Pandas DataFrame数据的增.删.改.查 https://blog.csdn.net/zhangchuang601/article/details/79583551 #删除列 df_2 = ...

  9. 对象克隆及属性转换-JavaScript

    在某些项目中,需要将一些返回信息进行其他语言的翻译,可以为不同语言用户提供不同的语言版本.下面是一个实现: /** * @class Translate * @description 查询字典,翻译成 ...

  10. Java编程的逻辑 (5) - 小数计算为什么会出错?

    本系列文章经补充和完善,已修订整理成书<Java编程的逻辑>,由机械工业出版社华章分社出版,于2018年1月上市热销,读者好评如潮!各大网店和书店有售,欢迎购买,京东自营链接:http:/ ...