在"MVC批量添加,增加一条记录的同时添加N条集合属性所对应的个体"中,有2个问题待解决:

1、由jquery动态生成了表单元素,但不能实施验证。
2、一旦集合元素不连续,控制器就无法接收到完整的数据。

批量添加或更新,控制器能接收的方式,大致有2种:
Category.Name
Category.Products[0].Name
Category.Products[3].Name  
Category.Products[6].Name 

<input type="hidden" name="CgdModel.Ubis.Index" value="0" />
<input type="text" name="CgdModel.Ubis[0].Fdt"...
<input type="text" name="CgdModel.Ubis[0].Memo...

<input type="hidden" name="CgdModel.Ubis.Index" value="1" />
<input type="text" name="CgdModel.Ubis[1].Fdt"...
<input type="text" name="CgdModel.Ubis[1].Memo...

 

本篇使用第二种方式,并解决上文提到的2个问题。

批量更新的界面为:

 

□ Model

一个用户,可以有任意多喜欢看的电影。

    public class User
    {
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
        public IList<Movie> FavouriteMovies { get; set; }
    }
 
    public class Movie
    {
        [Required]
        public string Title { get; set; }
        public int Rating { get; set; }
    } 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

   
□ HomeController

显示更新界面,接收更新数据,并相应视图添加按钮,通过部分视图添加新行。

    public class HomeController : Controller
    {
        private static User _currentUser;
 
        private static User CurrentUser
        {
            get
            {
                if (_currentUser == null)
                {
                    _currentUser = GetFakeUser();
                }
                return _currentUser;
            }
            set { _currentUser = value; }
        }
 
        private static User GetFakeUser()
        {
            return new User()
            {
                Id = 1,
                Name = "darren",
                FavouriteMovies = new List<Movie>()
                {
                    new Movie(){Title = "movie1"},
                    new Movie(){Title = "movie2"},
                    new Movie(){Title = "movie3"}
                }
            };
        }
 
        public ActionResult EditUser()
        {
            return View(CurrentUser);
        }
 
        [HttpPost]
        public ActionResult EditUser(User user)
        {
            if (!ModelState.IsValid)
            {
                return View(user);
            }
            CurrentUser = user;
            return View(CurrentUser);
        }
 
        //响应视图添加按钮,通过部分视图生成一行
        public ActionResult MovieEntryRow()
        {
            return PartialView("MovieEntryEditor");
        }     
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

□ Home/EditUser.cshtml

其中,每组集合元素,即用户喜欢的电影通过部分视图MovieEntryEditor.cshtml渲染出来。

@using VariableCollection.Models
@model VariableCollection.Models.User
 
@{
    ViewBag.Title = "EditUser";
    Layout = "~/Views/Shared/_Layout.cshtml";
}
 
@using (Html.BeginForm())
{
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>用户及喜欢电影</legend>
        @Html.HiddenFor(model => model.Id)
        
        <div class="editor-label">
            @Html.LabelFor(model => model.Name)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Name)
            @Html.ValidationMessageFor(model => model.Name)
        </div>
    </fieldset>
    
    <fieldset>
        <legend>我最喜欢的电影</legend>
        @if (Model.FavouriteMovies == null || Model.FavouriteMovies.Count == 0)
        {
            <p>没有喜欢的电影~~</p>
        }
        else
        {
            <ul id="movieEditor" style="list-style-type: none">
                @foreach (Movie movie in Model.FavouriteMovies)
                {
                    Html.RenderPartial("MovieEntryEditor", movie);
                }
            </ul>
            <a id="addAnother" href="#">添加行</a>
        }
    </fieldset>
    
    <p>
        <input type="submit" value="提交"/>
    </p>
}
 
@section scripts
{
    <script type="text/javascript">
        $(function() {
            $('#movieEditor').sortable();
 
            $("#addAnother").click(function () {
                $.get('/Home/MovieEntryRow', function (template) {
                    $("#movieEditor").append(template);
                });
            });
        });
    </script>
}
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

□ Layout.cshtml中把jquery ui和验证相关js引进来

    @Scripts.Render("~/bundles/jquery")

    @Scripts.Render("~/bundles/jqueryui")

    @Scripts.Render("~/bundles/jqueryval")

 

□ 写一个帮助方法,目的是生成如下格式:

<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="6d85a95b-1dee-4175-bfae-73fad6a3763b" />

<input class="text-box single-line" name="FavouriteMovies[6d85a95b-1dee-4175-bfae-73fad6a3763b].Title" type="text" value="Movie 1" />

...

 

帮助方法除了要生成目标格式,还要考虑:

● 为了保证隐藏域value值的唯一性,每次渲染部分视图MovieEntryEditor.cshtml,让这里的value有一个唯一的GUID字符串。

● 还需要替换ViewData.TemplateInfo的HtmlFieldPrefix属性值为FavouriteMovies[6d85a95b-1dee-4175-bfae-73fad6a3763b]。

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
 
namespace VariableCollection.Extension
{
    public static class CollectionEditingHtmlExtensions
    {
        /// <summary>
        /// 目标是生成如下格式
        ///<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="6d85a95b-1dee-4175-bfae-73fad6a3763b" />
        ///<label>Title</label>
        ///<input class="text-box single-line" name="FavouriteMovies[6d85a95b-1dee-4175-bfae-73fad6a3763b].Title" type="text" value="Movie 1" />
        ///<span class="field-validation-valid"></span>
        /// </summary>
        /// <typeparam name="TModel"></typeparam>
        /// <param name="html"></param>
        /// <param name="collectionName">集合属性的名称</param>
        /// <returns></returns>
        public static IDisposable BeginCollectionItem<TModel>(this HtmlHelper<TModel> html, string collectionName)
        {
            string itemIndex = Guid.NewGuid().ToString();
 
            //比如,FavouriteMovies[6d85a95b-1dee-4175-bfae-73fad6a3763b]
            string collectionItemName = string.Format("{0}[{1}]", collectionName, itemIndex);
 
            TagBuilder indexField = new TagBuilder("input");
            indexField.MergeAttributes(new Dictionary<string, string>() {
                { "name", String.Format("{0}.Index", collectionName) }, //name="FavouriteMovies.Index"
                { "value", itemIndex },//value="6d85a95b-1dee-4175-bfae-73fad6a3763b"
                { "type", "hidden" },
                { "autocomplete", "off" }
            });
            html.ViewContext.Writer.WriteLine(indexField.ToString(TagRenderMode.SelfClosing));
 
            return new CollectionItemNamePrefixScope(html.ViewData.TemplateInfo, collectionItemName);
        }
 
         private class CollectionItemNamePrefixScope : IDisposable
         {
             private readonly TemplateInfo _templateInfo;
             private readonly string _previousPrefix;
 
             public CollectionItemNamePrefixScope(TemplateInfo templateInfo, string collectionItemName)
             {
                 this._templateInfo = templateInfo;
                 _previousPrefix = templateInfo.HtmlFieldPrefix;
                 templateInfo.HtmlFieldPrefix = collectionItemName;
             }
 
             public void Dispose()
             {
                 _templateInfo.HtmlFieldPrefix = _previousPrefix;
             }
         }
    }
}
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

由于BeginCollectionItem()方法返回的类型是实现了IDisposable接口的CollectionItemNamePrefixScope类,所以,我们在部分视图MovieEntryEditor.cshtml中可以使用using语句。

@using VariableCollection.Extension
@model VariableCollection.Models.Movie
 
<li style="padding-bottom: 15px;">
    @using (Html.BeginCollectionItem("FavouriteMovies"))
    {
        <img src="@Url.Content("~/Content/images/draggable-icon.png")" style="cursor: move" alt=""/>
 
        @Html.LabelFor(model => model.Title)
        @Html.EditorFor(model => model.Title)
        @Html.ValidationMessageFor(model => model.Title)
 
        @Html.LabelFor(model => model.Rating)
        @Html.EditorFor(model => model.Rating)
        @Html.ValidationMessageFor(model => model.Rating)
 
        <a href="#" onclick=" $(this).parent().remove(); ">删除行</a>
    }
</li>

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

运行,如果不符合验证要求,会报错,似乎看上去不错:

但,如果把_Layout.cshtml中有关客户端异步验证的js引用去掉,即把@Scripts.Render("~/bundles/jqueryval")注释掉,再次运行,居然服务端不再报错:

为什么?这是由User的ModelState状态不一致引起的。先来看下ModelState类:

public class ModelState

{

    public ModelErrorCollection Errors{get;}

    public ValueProviderResult Value{get;set;}

}

可见,ModelState不仅保存这有关Model的一切错误信息,还保存着有ValueProvider提供的表单数据。

在提交表单之前,界面的input大概是这样的:

<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="111" />

<input class="text-box single-line" name="FavouriteMovies[111].Title" type="text" value="Movie 1" />

<input class="text-box single-line" name="FavouriteMovies[111].Rating" type="text" value="Rating 1" />

<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="222" />

<input class="text-box single-line" name="FavouriteMovies[222].Title" type="text" value="Movie 2" />

<input class="text-box single-line" name="FavouriteMovies[222].Rating" type="text" value="Rating 2" />

<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="333" />

<input class="text-box single-line" name="FavouriteMovies[333].Title" type="text" value="Movie 3" />

<input class="text-box single-line" name="FavouriteMovies[333].Rating" type="text" value="Rating 3" />

 

当提交失败,回到原先视图界面,这时候,所有的集合元素都需要通过MovieEntryEditor.cshtml来渲染,界面的input大概变成这样:

<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="777" />

<input class="text-box single-line" name="FavouriteMovies[777].Title" type="text" value="Movie 1" />

<input class="text-box single-line" name="FavouriteMovies[777].Rating" type="text" value="Rating 1" />

<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="888" />

<input class="text-box single-line" name="FavouriteMovies[888].Title" type="text" value="Movie 2" />

<input class="text-box single-line" name="FavouriteMovies[888].Rating" type="text" value="Rating 2" />

<input autocomplete="off" name="FavouriteMovies.Index" type="hidden" value="999" />

<input class="text-box single-line" name="FavouriteMovies[999].Title" type="text" value="Movie 3" />

<input class="text-box single-line" name="FavouriteMovies[999].Rating" type="text" value="Rating 3" />

 

提交前后,ModelState的状态是不一致的,导致服务端验证失败。

为了保证有关User的ModelState的状态一致,大体上应该这样做:

● 对于通过部分视图MovieEntryEditor.cshtml渲染出来的新的表单元素,我们希望BeginCollectionItem()方法为我们生成新的GUID字符串。

● 对于验证不通过,重新由部分视图MovieEntryEditor.cshtml渲染的表单元素,我们希望还是用原先的GUID字符串,以保证ModelState状态一致。

□ 对帮助类CollectionEditingHtmlExtensions进行改良

把原先生成字符串的代码:

string itemIndex = Guid.NewGuid().ToString();

 

改成:

string collectionIndexFieldName = String.Format("{0}.Index", collectionName);//FavouriteMovies.Index

string itemIndex = GetCollectionItemIndex(collectionIndexFieldName);

 

其中,GetCollectionItemIndex()需要根据某种条件排判断:

1、如果渲染新的表单元素,就产生新的GUID字符串

2、如果不是渲染新的表单元素,就使用原先的GUID字符串

改良后的完整代码如下:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Mvc;
 
namespace VariableCollection.Extension
{
    public static class CollectionEditingHtmlExtensions
    {
        public static IDisposable BeginCollectionItem<TModel>(this HtmlHelper<TModel> html, string collectionName)
        {
            string collectionIndexFieldName = String.Format("{0}.Index", collectionName);//FavouriteMovies.Index
            string itemIndex = GetCollectionItemIndex(collectionIndexFieldName);
 
            //比如,FavouriteMovies[6d85a95b-1dee-4175-bfae-73fad6a3763b]
            string collectionItemName = string.Format("{0}[{1}]", collectionName, itemIndex);
 
            TagBuilder indexField = new TagBuilder("input");
            indexField.MergeAttributes(new Dictionary<string, string>() {
                { "name", String.Format("{0}.Index", collectionName) }, //name="FavouriteMovies.Index"
                { "value", itemIndex },//value="6d85a95b-1dee-4175-bfae-73fad6a3763b"
                { "type", "hidden" },
                { "autocomplete", "off" }
            });
            html.ViewContext.Writer.WriteLine(indexField.ToString(TagRenderMode.SelfClosing));
 
            return new CollectionItemNamePrefixScope(html.ViewData.TemplateInfo, collectionItemName);
        }
 
         private class CollectionItemNamePrefixScope : IDisposable
         {
             private readonly TemplateInfo _templateInfo;
             private readonly string _previousPrefix;
 
             public CollectionItemNamePrefixScope(TemplateInfo templateInfo, string collectionItemName)
             {
                 this._templateInfo = templateInfo;
                 _previousPrefix = templateInfo.HtmlFieldPrefix;
                 templateInfo.HtmlFieldPrefix = collectionItemName;
             }
 
             public void Dispose()
             {
                 _templateInfo.HtmlFieldPrefix = _previousPrefix;
             }
         }
 
        /// <summary>
        /// 以FavouriteMovies.Index为键,把Guid字符串存放在上下文中
        /// 如果是添加进入部分视图,就直接生成一个Guid字符串
        /// 如果是更新,为了保持和ModelState的一致,就遍历原先的Guid
        /// </summary>
        /// <param name="collectionIndexFieldName">FavouriteMovies.Index</param>
        /// <returns>返回Guid字符串</returns>
        private static string GetCollectionItemIndex(string collectionIndexFieldName)
        {
            Queue<string> previousIndices = (Queue<string>)HttpContext.Current.Items[collectionIndexFieldName];
            if (previousIndices == null)
            {
                HttpContext.Current.Items[collectionIndexFieldName] = previousIndices = new Queue<string>();
                string previousIndicesValues = HttpContext.Current.Request[collectionIndexFieldName];//HttpContext.Current.Request[FavouriteMovies.Index]
                if (!string.IsNullOrWhiteSpace(previousIndicesValues))
                {
                    foreach (string index in previousIndicesValues.Split(','))
                    {
                        previousIndices.Enqueue(index);
                    }
                }
            }
            return previousIndices.Count > 0 ? previousIndices.Dequeue() : Guid.NewGuid().ToString();
        }
    }
}
 

.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

 

在GetCollectionItemIndex()方法中,首先把隐藏域的name属性值,比如这里的FavouriteMovies.Index作为key,把队列Queue<string>作为value,以键值对的形式保存在上下文的HttpContext.Current.Items中。然后,通过HttpContext.Current.Request[FavouriteMovies.Index]获取所有隐藏域的value值集合赋值给previousIndicesValues变量,并依次存放到队列Queue<string>中。最后,根据previousIndicesValues是否有集合元素,判断MovieEntryEditor.cshtml视图到底是渲染新的表单元素还是原先的表单元素。

如果previousIndicesValues包含集合元素,就说明MovieEntryEditor.cshtml视图需要还原原先的表单元素,每次从队列Queue<string>中"挤出"第一个GUID字符串,直到没有。这样保证了User对应的ModelState状态的一致性。

如果previousIndicesValues中没有集合元素,就说明MovieEntryEditor.cshtml视图需要渲染新的表单元素,就生成一个新的GUID字符串。

把刚才注释掉的客户端异步验证js引用,再注释回来。

验证不通过:

验证通过:

□ 最后

通过本篇的方法:

<input type="hidden" name="FavouriteMovies.Index" value="m"/>

<input name="FavouriteMovies[m].Title" type="text" value="" />

<input name="FavouriteMovies[m].Rating" type="text" value="" />

 

<input type="hidden" name="FavouriteMovies.Index" value="n"/>

<input name="FavouriteMovies[n].Title" type="text" value="" />

<input name="FavouriteMovies[n].Rating" type="text" value="" />

......

即使集合元素不是连续的,控制器也能接收到所有的集合元素,实现批量添加或更新。

通过部分视图渲染每组集合元素,保证了客户端和服务端的验证功能。

□ 参考资料

※  Editing Variable Length Reorderable Collections in ASP.NET MVC – Part 1: ASP.NET MVC Views

MVC批量更新,可验证并解决集合元素不连续控制器接收不完全的问题的更多相关文章

  1. MVC批量更新,使用jQuery Template

    在"MVC批量更新,可验证并解决集合元素不连续控制器接收不完全的问题"中,当点击"添加"按钮的时候,通过部分视图,在界面上添加新行.本篇体验使用jQuery T ...

  2. MVC批量添加,增加一条记录的同时添加N条集合属性所对应的个体

    类别中包含一个产品的集合属性,如何向数据库添加一条类别记录的同时,添加任意多个产品. public class Product { [DisplayName("产品名称")] pu ...

  3. ASP.NET MVC中对Model进行分步验证的解决方法

    原文:ASP.NET MVC中对Model进行分步验证的解决方法 在我之前的文章:ASP.NET MVC2.0结合WF4.0实现用户多步注册流程中将一个用户的注册分成了四步,而这四个步骤都是在完善一个 ...

  4. EF结合SqlBulkCopy实现高效的批量数据插入 |EF插件EntityFramework.Extended实现批量更新和删除

    原文链接:http://blog.csdn.net/fanbin168/article/details/51485969   批量插入 (17597条数据批量插入耗时1.7秒)   using Sys ...

  5. 使用Python批量更新服务器文件【新手必学】

    买了个Linux服务器,Centos系统,装了个宝塔搭建了10个网站,比如有时候要在某个文件上加点代码,就要依次去10个文件改动,虽然宝塔是可视化页面操作,不需要用命令,但是也麻烦,虽然还有git的h ...

  6. MongoDB学习笔记~大叔分享批量添加—批量更新—批量删除

    回到目录 说它是批量操作,就是说将集合对象一次提交到服务器,并对数据进行持久化,如果您的代码是一次一次的提交,那不算是批量操作!在之前的mongodb仓储中并没有对批量更新和批量删除进行实现,而今天在 ...

  7. 前端MVC学习总结——AngularJS验证、过滤器

    前端MVC学习总结--AngularJS验证.过滤器 目录 一.验证 二.过滤器 2.1.内置过滤器 2.1.1.在模板中使用过滤器 2.1.2.在脚本中调用过滤函数 2.2.自定义过滤器 三.指令( ...

  8. mybatis执行批量更新update

    Mybatis的批量插入这里有http://ljhzzyx.blog.163.com/blog/static/38380312201353536375/.目前想批量更新,如果update的值是相同的话 ...

  9. [转]MySQL批量更新死锁案例分析

    文章出处:http://blog.csdn.net/aesop_wubo/article/details/8286215 问题描述 在做项目的过程中,由于写SQL太过随意,一不小心就抛了一个死锁异常, ...

随机推荐

  1. gcc/g++ 命令

    gcc & g++现在是gnu中最主要和最流行的c & c++编译器 .g++是c++的命令,以.cpp为主,对于c语言后缀名一般为.c.这时候命令换做gcc即可.其实是无关紧要的.其 ...

  2. bzoj 4034(DFS序+线段树)

    这个题多了一个操作难度直线上升,看完题解才会写 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a .操作 2 :把某个节点 ...

  3. C语言-删除注释

    C语言中的注释,不嵌套,一律使用/*   */的形式.不过双引号中的/*  */则不能算是注释. 以下是正确的代码 /* * ===================================== ...

  4. **iOS发JSON请求中字符串加转义,返回的JSON去转义

    iOS中使用NSSerialization把对象转为JSON字符串后,多出来反斜杠的问题 http://segmentfault.com/q/1010000000576646 NSDictionary ...

  5. Kubernetes1.6集群上(开启了TLS)安装Dashboard

    本节内容: 配置dashboard 执行所有定义的文件 检查执行结果 访问dashboard 这是接着上一篇<二进制方式部署Kubernetes 1.6.0集群(开启TLS)>写的.Kub ...

  6. Asp.net Vnext 模块化实现

    概述 本文已经同步到<Asp.net Vnext 系列教程 >中] 在程序中实现模块化可以加快开发效率,通过替换模块实现升级. 架构 vnext 没有 Virtualpathprovide ...

  7. centos7 关闭默认firewalld,开启iptables

    编者按: 对于使用了centos6系列系统N年的运维来说,在使用centos7的时候难免会遇到各种不适应.比如防火墙问题.本文主要记录怎么关闭默认的firewalld防火墙,重新启用iptables. ...

  8. USACO 4.2 Job Processing

    Job ProcessingIOI'96 A factory is running a production line that requires two operations to be perfo ...

  9. hdoj2544 最短路(Dijkstra || Floyd || SPFA)

    题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=2544 思路 最短路算法模板题,求解使用的Dijkstra算法.Floyd算法.SPFA算法可以当做求解 ...

  10. 关于ecshop的mobile里user.php登录和注册验证码不显示

    在做ecshop模板的时候由于user.php里的登录和注册是在一个页面里切换的,这就致使这里的登录和注册里的验证码不显示 找到mobile/themesmobile/ecshoptemplate_m ...