JSON.NET 序列化时出现 StackOverflowException

JSON.NET StackOverflowException while serialization

当我尝试序列化具有类似结构的对象时,我的 C# 程序 运行 进入 WhosebugException:

示例代码如下:

class Chacha
{
    public Chacha NextChacha { get; set; }
}    
public static readonly JsonSerializerSettings Settings = new JsonSerializerSettings
{
    TypeNameHandling = TypeNameHandling.All,
    PreserveReferencesHandling = PreserveReferencesHandling.Objects,
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};

static void Main(string[] args)
{
        int count = 15000;

        Chacha[] steps = new Chacha[count];
        steps[0] = new Chacha();

        for (int i = 1; i < count; i++)
        {
            steps[i] = new Chacha();
            steps[i-1].NextChacha = steps[i];
        }

        string serSteps = JsonConvert.SerializeObject(steps, Settings);
}

JSON.NET 版本为:9.0.1
.NET 框架:4.5.2
任何解决方案如何序列化此结构?

欢迎任何帮助或建议。谢谢

你得到 Whosebug 异常的原因是 Json.NET 是一个递归的,single-pass 树或图形序列化器,当 PreserveReferencesHandling.Objects 启用时,总是序列化 first 每个对象出现。您已经构建了包含 15,000 个元素的 Chacha [] 数组,因此第一个条目是包含顺序链接的所有其他项目的链表的头部。 Json.NET 将尝试通过 15,000 层递归将其序列化为 15,000 层深的嵌套 JSON 对象,并在此过程中溢出堆栈。

因此,您需要做的是仅将整个 table 链接写入列表的 head,作为 JSON 数组。然而,不幸的是,Json.NET 也是一个 contract-based 序列化程序,这意味着无论嵌套深度是多少,它都会在遇到给定类型的对象时尝试编写相同的属性。因此,将 Chacha[] NextChachaList 属性 添加到 Chacha 对象并没有帮助,因为它会在每个级别上写入。相反,有必要创建一个相当复杂的 custom JsonConverter 以 thread-safe 方式跟踪序列化深度,并且仅在顶层写入链接列表。以下是诀窍:

class ChachaConverter : LinkedListItemConverter<Chacha>
{
    protected override bool IsNextItemProperty(JsonProperty member)
    {
        return member.UnderlyingName == "NextChacha"; // Use nameof(Chacha.NextChacha) in latest c#
    }
}

public abstract class LinkedListItemConverter<T> : JsonConverter where T : class
{
    const string refProperty = "$ref";
    const string idProperty = "$id";
    const string NextItemListProperty = "nextItemList";

    [ThreadStatic]
    static int level;

    // Increments the nesting level in a thread-safe manner.
    int Level { get { return level; } set { level = value; } }

    public override bool CanConvert(Type objectType)
    {
        return typeof(T).IsAssignableFrom(objectType);
    }

    protected abstract bool IsNextItemProperty(JsonProperty member);

    List<T> GetNextItemList(object value, JsonObjectContract contract)
    {
        var property = contract.Properties.Where(p => IsNextItemProperty(p)).Single();
        List<T> list = null;
        for (var item = (T)property.ValueProvider.GetValue(value); item != null; item = (T)property.ValueProvider.GetValue(item))
        {
            if (list == null)
                list = new List<T>();
            list.Add(item);
        }
        return list;
    }

    void SetNextItemLinks(object value, List<T> list, JsonObjectContract contract)
    {
        var property = contract.Properties.Where(p => IsNextItemProperty(p)).Single();
        if (list == null || list.Count == 0)
            return;
        var previous = value;
        foreach (var next in list)
        {
            if (next == null)
                continue;
            property.ValueProvider.SetValue(previous, next);
            previous = next;
        }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        using (new PushValue<int>(Level + 1, () => Level, (old) => Level = old))
        {
            writer.WriteStartObject();

            if (serializer.ReferenceResolver.IsReferenced(serializer, value))
            {
                writer.WritePropertyName(refProperty);
                writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value));
            }
            else
            {
                writer.WritePropertyName(idProperty);
                writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value));

                var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(value.GetType());

                // Write the data properties (if any).
                foreach (var property in contract.Properties
                    .Where(p => p.Readable && !p.Ignored && (p.ShouldSerialize == null || p.ShouldSerialize(value))))
                {
                    if (IsNextItemProperty(property))
                        continue;
                    var propertyValue = property.ValueProvider.GetValue(value);
                    if (propertyValue == null && serializer.NullValueHandling == NullValueHandling.Ignore)
                        continue;
                    writer.WritePropertyName(property.PropertyName);
                    serializer.Serialize(writer, propertyValue);
                }

                if (Level == 1)
                {
                    // Write the NextItemList ONLY AT THE TOP LEVEL
                    var nextItems = GetNextItemList(value, contract);
                    if (nextItems != null)
                    {
                        writer.WritePropertyName(NextItemListProperty);
                        serializer.Serialize(writer, nextItems);
                    }
                }
            }
            writer.WriteEndObject();
        }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.Null)
            return null;
        var jObject = JObject.Load(reader);

        // Detach and process $ref
        var refValue = (string)jObject[refProperty].RemoveFromLowestPossibleParent();
        if (refValue != null)
        {
            var reference = serializer.ReferenceResolver.ResolveReference(serializer, refValue);
            if (reference != null)
                return reference;
        }

        // Construct the value
        var contract = (JsonObjectContract)serializer.ContractResolver.ResolveContract(existingValue == null ? typeof(T) : existingValue.GetType());
        T value = (existingValue as T ?? (T)contract.DefaultCreator());

        // Detach and process $id
        var idValue = (string)jObject[idProperty].RemoveFromLowestPossibleParent();
        if (idValue != null)
        {
            serializer.ReferenceResolver.AddReference(serializer, idValue, value);
        }

        // Detach the (possibly large) list of next items.
        var nextItemList = jObject[NextItemListProperty].RemoveFromLowestPossibleParent();

        // populate the data properties (if any)
        serializer.Populate(jObject.CreateReader(), value);

        // Set the next item references
        if (nextItemList != null)
        {
            var list = nextItemList.ToObject<List<T>>(serializer);
            SetNextItemLinks(value, list, contract);
        }

        return value;
    }
}

public struct PushValue<T> : IDisposable
{
    Action<T> setValue;
    T oldValue;

    public PushValue(T value, Func<T> getValue, Action<T> setValue)
    {
        if (getValue == null || setValue == null)
            throw new ArgumentNullException();
        this.setValue = setValue;
        this.oldValue = getValue();
        setValue(value);
    }

    #region IDisposable Members

    // By using a disposable struct we avoid the overhead of allocating and freeing an instance of a finalizable class.
    public void Dispose()
    {
        if (setValue != null)
            setValue(oldValue);
    }

    #endregion
}

public static class JsonExtensions
{
    public static JToken RemoveFromLowestPossibleParent(this JToken node)
    {
        if (node == null)
            return null;
        var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
        if (contained != null)
            contained.Remove();
        // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
        if (node.Parent is JProperty)
            ((JProperty)node.Parent).Value = null;
        return node;
    }
}

然后,给出稍微修改的class Chacha:

class Chacha
{
    public Chacha NextChacha { get; set; }

    public long Data { get; set; }
}

为包含 3 个项目的数组生成以下 JSON:

{
  "$type": "Question41828014.Chacha[], Tile",
  "$values": [
    {
      "$id": "1",
      "Data": 0,
      "nextItemList": {
        "$type": "System.Collections.Generic.List`1[[Question41828014.Chacha, Tile]], mscorlib",
        "$values": [
          {
            "$id": "2",
            "Data": 1
          },
          {
            "$id": "3",
            "Data": 2
          }
        ]
      }
    },
    {
      "$ref": "2"
    },
    {
      "$ref": "3"
    }
  ]
}

请注意,JSON 深度现在受到严格限制。示例 fiddle

请注意,一旦您为您的类型指定了自定义转换器,它就需要手动执行所有操作。如果您的类型 Chacha 是多态的并且您需要读写 "$type" 属性,则您需要自己将该逻辑添加到转换器中。

顺便说一句,我推荐TypeNameHandling.Objects而不是TypeNameHandling.All。可以在 JSON 中合理指定对象类型(只要类型正确 ),但应在代码中指定集合类型。这样做可以从数组切换到 List<T>,而无需后读遗留 JSON 文件。

public class Model
 {
    public int Id { get; set; }
    public string Name { get; set; }
    public string SurName { get; set; }
 }
List<Model> list = new List<Model>();
list.Add(new Model { Id = 1, Name = "Jon", SurName = "Snow"});
var stringJson = JsonConvert.SerializeObject(list, new JsonSerializerSettings
  {
    PreserveReferencesHandling = PreserveReferencesHandling.Objects
  });

MVC 与 Jquery:

通过控制台 nuget 包安装 newtonsoft 包: 安装包 Newtonsoft.json - 版本 6.0.1

控制器:

[HttpPost]
    public ActionResult Get_Country()
    {
        string _data = "";
        SqlCommand cmd = new SqlCommand("Get_Country", con);
        cmd.CommandType = CommandType.StoredProcedure;
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        da.Fill(ds);
        if (ds.Tables[0].Rows.Count > 0)
        {
            _data = JsonConvert.SerializeObject(ds.Tables[0]);
        }
        return Json(_data, JsonRequestBehavior.AllowGet);
    }

    [HttpPost]
    public ActionResult Insert(string A,string B,string C,string D)
    {
        con.Open();
        SqlCommand cmd = new SqlCommand("Insert_Employee", con);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@Name", A);
        cmd.Parameters.AddWithValue("@CID", B);
        cmd.Parameters.AddWithValue("@Gender", C);
        cmd.Parameters.AddWithValue("@Hobbies", D);
        int count = cmd.ExecuteNonQuery();
        con.Close();
        return View();
    }

    [HttpPost]
    public ActionResult Get_Employees()
    {
        string _data = "";
        SqlCommand cmd = new SqlCommand("Get_Employees", con);
        cmd.CommandType = CommandType.StoredProcedure;
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        da.Fill(ds);
        if (ds.Tables[0].Rows.Count > 0)
        {
            _data = JsonConvert.SerializeObject(ds.Tables[0]);
        }
        return Json(_data, JsonRequestBehavior.AllowGet);
    }

    [HttpPost]
    public ActionResult EditData(int A)
    {
        string _data = "";
        SqlCommand cmd = new SqlCommand("Get_Employees_Edit", con);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@ID", A);
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        da.Fill(ds);
        if (ds.Tables[0].Rows.Count > 0)
        {
            _data = JsonConvert.SerializeObject(ds.Tables[0]);
        }
        return Json(_data, JsonRequestBehavior.AllowGet);
    }

查看:

脚本:

<script type="text/javascript">

    var IDD = "";
            
    $(document).ready(function () {
        Get_Country();
        GetEmployees();
    });

    function Get_Country() {
        $.ajax({
            url: 'Employee/Get_Country',
            type: 'post',
            data: {},
            success: function (_dt) {
                _dt = JSON.parse(_dt);
                for (var i = 0; i < _dt.length; i++) {
                    $('#ddlCountry').append($('<option/>').attr('value',_dt[i].CID).text(_dt[i].CName));
                }
            },
            error: function () {
                alert('Error in Country Bind');
            }
        })
    }

    function SaveData() {
        debugger    
        var HOB = "";
        if ($("#btnsave").val() == ("Save")) {
            HOB = $('input:checkbox:checked.B').map(function () {
                return this.value;
            }).get().join(',');
            $.ajax({
                url: 'Employee/Insert',
                type: 'post',
                data: { A: $('#txtName').val(), B: $('#ddlCountry').val(), C: $('input:radio[name=A]:checked').val(), D: HOB },
                success: function () {
                    alert('data saved');
                    GetEmployees();
                },
                error: function () {
                    alert('saved error');
                }
            });
        }
    }


    function GetEmployees() {
        debugger
        $.ajax({
            url: 'Employee/Get_Employees',
            type: 'post',
            data: {},
            async: false,
            success: function (_dt) {
                _dt = JSON.parse(_dt);
                $('#tbl').find("tr:gt(0)").remove();
                for (var i = 0; i < _dt.length; i++) {
                    $('#tbl').append('<tr><td>' + _dt[i].ID + '</td><td>' + _dt[i].Name + '</td><td>' + _dt[i].CName + '</td><td>' + (_dt[i].Gender == 1 ? 'Male' : _dt[i].Gender == 2 ? 'Female' : 'Others') + '</td><td>' + _dt[i].Hobbies + '</td><td><input id="btnEdit" type="button" value="Edit" onclick="EditData(' + _dt[i].ID + ')"/></td><td><input id="btnDelete" type="button" value="Delete" onclick="DeleteData(' + _dt[i].ID + ')"/></td></tr>')
                }
            },
            error: function () {
                alert('error in binding');
            }
        });
    }
    


    function EditData(id) {
        debugger;
        $.ajax({
            url: 'Employee/EditData',
            type: 'post',
            data: { A: id },
            success: function (_dt) {
                _dt = JSON.parse(_dt);
                debugger;
                $("#txtName").val(_dt[0].Name);
                $("#ddlCountry").val(_dt[0].CID);
                $("input[name=A][value=" + _dt[0].Gender + "]").prop('checked', true);

                var hbb = _dt[0].Hobbies;
                var arr = hbb.split(',');
                $('input:checkbox:checked.B').prop('checked', false);
                for (var i = 0; i < arr.length; i++) {
                    $('input:checkbox[class=B][value=' + arr[i] + ']').prop('checked', true);
                }

                $("#btnsave").val("Update");
                IDD = id;
            },
            error: function () {
                alert('edit error !!');
            }
        });
    }

正文:

     <table>
        <tr>
            <td>Name :</td>
            <td>
                <input id="txtName" type="text" />
            </td>
        </tr>
        <tr>
            <td>Country :</td>
            <td>
                <select id="ddlCountry">
                    <option value="0"><--Select--></option>
                </select>
            </td>
        </tr>
        <tr>
            <td>Gender :</td>
            <td>
                <input type="radio" name="A" value="1" />Male
                <input type="radio" name="A" value="2" />Female
                <input type="radio" name="A" value="3" />Others
            </td>
        </tr>
        <tr>
            <td>Hobbies :</td>
            <td>
                <input type="checkbox" class="B" value="Cricket" />Cricket
                <input type="checkbox" class="B" value="Coding" />Coding
                <input type="checkbox" class="B" value="Travelling" />Travelling
                <input type="checkbox" class="B" value="Swimming" />Swimming
                <input type="checkbox" class="B" value="Movies" />Movies
                <input type="checkbox" class="B" value="Typing" />Typing
            </td>
        </tr>
        <tr>
            <td></td>
            <td>
                <input type="button" id="btnsave" value="Save" onclick="SaveData()" />
            </td>
        </tr>
    </table>

    <table id="tbl" border="1">
        <tr>
            <td>ID</td>
            <td>Name</td>
            <td>Country</td>
            <td>Gender</td>
            <td>Hobbies</td>
            <td>Edit</td>
            <td>Delete</td>
        </tr>
    </table>
Jquery cs code:

```csharp
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["DBCS"].ConnectionString);

[WebMethod]
public string GetCountry()
{
    string _data = "";
    con.Open();
    SqlCommand cmd = new SqlCommand("usp_country_get",con);
    cmd.CommandType = CommandType.StoredProcedure;
    SqlDataAdapter da = new SqlDataAdapter(cmd);
    DataSet ds = new DataSet();
    da.Fill(ds);
    con.Close();
    if (ds.Tables[0].Rows.Count > 0)
    {
        _data = JsonConvert.SerializeObject(ds.Tables[0]);
    }
    return _data;
}

[WebMethod]
public void Insert(string A, int B, int C, string D)
{
    con.Open();
    SqlCommand cmd = new SqlCommand("usp_emp_insert", con);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@name", A);
    cmd.Parameters.AddWithValue("@cid", B);
    cmd.Parameters.AddWithValue("@gender", C);
    cmd.Parameters.AddWithValue("@hobbies", D);
    cmd.ExecuteNonQuery();
    con.Close();
}


[WebMethod]
public void Delete(int ID)
{
    con.Open();
    SqlCommand cmd = new SqlCommand("usp_emp_delete", con);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@id", ID);
    cmd.ExecuteNonQuery();
    con.Close();
}

[WebMethod]
public string Edit(int ID)
{
    string _data = "";
    con.Open();
    SqlCommand cmd = new SqlCommand("usp_emp_edit", con);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@id", ID);
    SqlDataAdapter da = new SqlDataAdapter(cmd);
    DataSet ds = new DataSet();
    da.Fill(ds);
    con.Close();
    if (ds.Tables[0].Rows.Count > 0)
    {
        _data = JsonConvert.SerializeObject(ds.Tables[0]);
    }
    return _data;
}

[WebMethod]
public void Update(int ID, string A, int B, int C, string D)
{
    con.Open();
    SqlCommand cmd = new SqlCommand("usp_emp_update", con);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.AddWithValue("@id", ID);
    cmd.Parameters.AddWithValue("@name", A);
    cmd.Parameters.AddWithValue("@cid", B);
    cmd.Parameters.AddWithValue("@gender", C);
    cmd.Parameters.AddWithValue("@hobbies", D);
    cmd.ExecuteNonQuery();
    con.Close();
}

[WebMethod]
public string GetEmployee()
{
    string _data = "";
    con.Open();
    SqlCommand cmd = new SqlCommand("usp_emp_get", con);
    cmd.CommandType = CommandType.StoredProcedure;
    SqlDataAdapter da = new SqlDataAdapter(cmd);
    DataSet ds = new DataSet();
    da.Fill(ds);
    con.Close();
    if (ds.Tables[0].Rows.Count > 0)
    {
        _data = JsonConvert.SerializeObject(ds.Tables[0]);
    }
    else
    {
        _data = JsonConvert.SerializeObject(ds.Tables[0]);
    }
    return _data;
}
```







aspx code:

Scripting :

```html
<script src="jquery-3.2.1.js"></script>

<script type="text/javascript">
    var IDD = "";
    $(document).ready(function () {
        CountryBind();
        //EmployeeBind();
    });

    function CountryBind() {
        $.ajax({
            url:'Employee.asmx/GetCountry',
            type:'post',
            contentType:'application/json;charset=utf-8',
            dataType:'json',
            data:'{}',
            async: false,
            success: function (_dt) {
                _dt = JSON.parse(_dt.d);
                for (var i = 0; i < _dt.length; i++) {
                    $("#ddlcountry").append($('<option/>').attr("value", _dt[i].cid).text(_dt[i].cname));
                }
            },
            error: function () {
                alert('CountryBind error');
            }
        });
    }


    function SaveData() {
        var HOB = "";
        HOB = $('input:checkbox:checked.B').map(function () {
            return this.value;
        }).get().join(',');
        if ($("#btnsave").val()==("Save")) {
            $.ajax({
                url: 'Employee.asmx/Insert',
                type: 'post',
                contentType: 'application/json;charset=utf-8',
                dataType: 'json',
                data: "{A:'" + $("#txtname").val() + "',B:'" + $("#ddlcountry").val() + "',C:'" + $('input:radio[name=A]:checked').val() + "',D:'" + HOB + "'}",
                success: function () {
                    alert('insert success !!');
                    EmployeeBind();
                },
                error: function () {
                    alert('insert error !!');
                }
            });
        }
        else {
            $.ajax({
                url: 'Employee.asmx/Update',
                type: 'post',
                contentType: 'application/json;charset=utf-8',
                dataType: 'json',
                data: "{ID:" + IDD + ",A:'" + $("#txtname").val() + "',B:'" + $("#ddlcountry").val() + "',C:'" + $('input:radio[name=A]:checked').val() + "',D:'" + HOB + "'}",
                success: function () {
                    alert('Update Successfully');
                    EmployeeBind();
                },
                error: function () {
                    alert('Update error');
                }
            });
        }
    }

    function EmployeeBind() {
        $.ajax({
            url: 'Employee.asmx/GetEmployee',
            type: 'post',
            contentType: 'application/json;charset=utf-8',
            dataType: 'json',
            data: "{}",
            async: false,
            success: function (_dt) {
                _dt = JSON.parse(_dt.d);
                $("#tbl").find("tr:gt(0)").remove();
                for (var i = 0; i < _dt.length; i++) {
                    $("#tbl").append('<tr><td>' + _dt[i].name + '</td><td>' + _dt[i].cname + '</td><td>' + (_dt[i].gender == "1" ? "Male" : _dt[i].gender == "2" ? "FeMale" : "Others") + '</td><td>' + _dt[i].hobbies + '</td><td><input type="button" id="btnedit" value="Edit" onclick="EditData(' + _dt[i].id + ')" /><td><input type="button" id="btndelete" value="Delete" onclick="DeleteData(' + _dt[i].id + ')" /></td</tr>');
                }
            },
            error: function () {
                alert('EmployeeBind error');
            }
        });
    }

    function DeleteData(id) {
        $.ajax({
            url: 'Employee.asmx/Delete',
            type: 'post',
            contentType: 'application/json;charset=utf-8',
            dataType: 'json',
            data: "{ID:'" + id + "'}",
            success: function () {
                alert('Delete Successfully');
                EmployeeBind();
            },
            error: function () {
                alert('DeleteData error');
            }
        });
    }

    function EditData(id) {
        $.ajax({
            url: 'Employee.asmx/Edit',
            type: 'post',
            contentType: 'application/json;charset=utf-8',
            dataType: 'json',
            async:false,
            data: "{ID:'" + id + "'}",
            success: function (_dt) {
                _dt = JSON.parse(_dt.d);
                $("#txtname").val(_dt[0].name);
                $("#ddlcountry").val(_dt[0].cid);
                $("input[name=A][value=" + _dt[0].gender + "]").prop('checked', true);

                var hbb = _dt[0].hobbies;
                var arr = hbb.split(',');
                $("input:checkbox:checked.B").prop('checked', false);
                for (var i = 0; i < arr.length; i++) {
                    $("input:checkbox[class=B][value=" + arr[i] + ']').prop('checked', true);
                }

                $("#btnsave").val("Update");
                IDD = id;
                EmployeeBind();
            },
            error: function () {
                alert('EditData error');
            }
        });
    }
</script>
```

Body:

```html
<body>
    <table>
        <tr>
            <td>Name :</td>
            <td><input type="text" id="txtname" /></td>
        </tr>
        <tr>
            <td>Country :</td>
            <td><select id="ddlcountry">
                    <option value="0">--Select--</option>
                </select>
            </td>
        </tr>
        <tr>
            <td>Gender :</td>
            <td>
                <input type="radio" name="A" value="1" /> male
                <input type="radio" name="A" value="2" /> female
                <input type="radio" name="A" value="3" /> other
            </td>
        </tr>
        <tr>
            <td>Hobbies :</td>
            <td>
                <input type="checkbox" class="B" value="cricket" /> cricket
                <input type="checkbox" class="B" value="music" /> music
                <input type="checkbox" class="B" value="movies" /> movies
                <input type="checkbox" class="B" value="cooking" /> cooking
                <input type="checkbox" class="B" value="coding" /> coding
            </td>
        </tr>
        <tr>
            <td></td>
            <td><input type="button" id="btnsave" value="Save" onclick="SaveData()" /></td>
        </tr>
    </table>
    
    <table id="tbl" border="1" style="border-color:darkblue;width:100%">
        <tr>
            <th>Name</th>
            <th>Country</th>
            <th>Gender</th>
            <th>Hobbies</th>
            <th>Edit</th>
            <th>Delete</th>
        </tr>
    </table>
</body>
```

Asp.net Gridview 外部:

ASPX:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Employee.aspx.cs" Inherits="Asp_outside_gridview.Employee" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajax" %>
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <script type="text/javascript">
        function Validation() {
            var errors = "";
            errors += checkname();
            errors += dob();
            errors += email();
            errors += password();
            errors += cpassword();
            errors += mobile();
            errors += salary();
            errors += country();
            errors += state();
            errors += city();
            if (errors != "") {
                alert(errors);
                return false;
            }
        }

        function checkname() {
            var TBN=document.getElementById('txtname');
            var exp = "/^[a-zA-Z ]{2,30}$/";
            if (TBN.value="") {
                return 'please enter your NAME!\n'
            }
            else if (exp.test(TBN.value)) {
                return "";
            }
            else {
                'plese enter only alphabets in NAME!\n';
            }
        }
        function dob() {
            var TBdob = document.getElementById('txtdob');
            if (TBdob.value = "") {
                return 'please enter your DATE OF BIRTH!\n'
            }
            else {
                return "";
            }
        }
        function email() {
            var TBemail = document.getElementById('txtemail');
            var exp = "/^(([^<>()[\]\.,;:\s@\"]+(\.[^<>()[\]\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/";
            if (TBemail.value = "") {
                return 'please enter your EMAIL ID!\n'
            }
            else if (exp.test(TBemail.value)) {
                return "";
            }
            else {
                'plese enter valid email id!\n';
            }
        }
        function password() {
            var TBpassword = document.getElementById('txtpassword');
            var exp = "/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[$@$!%*?&])[A-Za-z\d$@$!%*?&]{8,10}$/";
            if (TBpassword.value = "") {
                return 'please enter your PASSWORD!\n'
            }
            else if (exp.test(TBpassword.value)) {
                return "";
            }
            else {
                'password should be of Minimum eight and maximum 10 characters, at least one uppercase letter, one lowercase letter, one number and one special character!\n';
            }
        }
        function cpassword() {
            var TBpassword = document.getElementById('txtpassword');
            var TBcpassword = document.getElementById('txtcpassword');
            if (TBcpassword.value = "") {
                return 'please enter your CONFIRM PASSWORD!\n'
            }
            else if (TBpassword.value== TBcpassword.value) {
                return "";
            }
            else {
                'password do not match!\n';
            }
        }
        function mobile() {
            var TBmobile = document.getElementById('txtmobile');
            var exp = /^\d{10}$/;
            if (TBmobile.value = "") {
                return 'please enter your MOBILE NUMBER!\n'
            }
            else if (exp.test(TBmobile.value)) {
                return "";
            }
            else {
                'plese enter only valid MOBILE NUMBER!\n';
            }
        }
        function salary() {
            var TBsalary = document.getElementById('txtsalary');
            var exp = /^\d{10}$/;
            if (TBsalary.value = "") {
                return 'please enter your SALARY!\n'
            }
            else if (exp.test(TBsalary.value)) {
                return "";
            }
            else {
                'plese enter only numbers in SALARY!\n';
            }
        }
        function country() {
            var TBcountry = document.getElementById('ddlcountry');
            if (TBcountry.value = "0") {
                return 'please Select your Country!\n'
            }
            else  {
                return "";
            }
        }
        function state() {
            var TBstate = document.getElementById('ddlstate');
            if (TBstate.value = "0") {
                return 'please Select your State!\n'
            }
            else {
                return "";
            }
        }
        function city() {
            var TBcity = document.getElementById('ddlcity');
            if (TBcity.value = "0") {
                return 'please Select your City!\n'
            }
            else {
                return "";
            }
        }        
    </script>

    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <ajax:ToolkitScriptManager ID="ajaxcal" runat="server"></ajax:ToolkitScriptManager>
    <div>
        <table>
            <tr>
                <td>Name :</td>
                <td><asp:TextBox ID="txtname" runat="server" /></td>
            </tr>
            <tr>
                <td>Country :</td>
                <td><asp:DropDownList ID="ddlcountry" AutoPostBack="true" runat="server" OnSelectedIndexChanged="ddlcountry_SelectedIndexChanged"></asp:DropDownList></td>
            </tr>
            <tr>
                <td>State :</td>
                <td><asp:DropDownList ID="ddlstate" runat="server" AutoPostBack="true"></asp:DropDownList></td>
            </tr>
            <tr>
                <td>Date of Birth :</td>
                <td><asp:TextBox ID="txtdob" runat="server" />
                    <ajax:CalendarExtender ID="caldob" runat="server" Format="dd/MM/yyyy" PopupButtonID="txtdob" TargetControlID="txtdob" PopupPosition="Right"></ajax:CalendarExtender></td>
            </tr>
            <tr>
                <td>Gender :</td>
                <td>
                    <asp:RadioButtonList ID="rblgender" runat="server" RepeatColumns="3">
                        <asp:ListItem Text="Male" Value="1"/>
                        <asp:ListItem Text="Female" Value="2" />
                        <asp:ListItem Text="Others" Value="3" />
                    </asp:RadioButtonList></td>
            </tr>
            <tr>
                <td>Image :</td>
                <td><asp:FileUpload ID="fuimage" runat="server" /><asp:Label ID="lblmsg" runat="server" ForeColor="Red" Font-Bold="true"></asp:Label></td>
            </tr>
            <tr>
                <td>Hobbies :</td>
                <td>
                    <asp:CheckBoxList ID="chkhobbies" runat="server" RepeatColumns="5">
                        <asp:ListItem Text="Cricket"></asp:ListItem>
                        <asp:ListItem Text="Football" ></asp:ListItem>
                        <asp:ListItem Text="Coding" ></asp:ListItem>
                        <asp:ListItem Text="Reading" ></asp:ListItem>
                        <asp:ListItem Text="Travelling" ></asp:ListItem>
                        <asp:ListItem Text="Gym" ></asp:ListItem>
                        <asp:ListItem Text="Singing" ></asp:ListItem>
                        <asp:ListItem Text="Dancing" ></asp:ListItem>
                        <asp:ListItem Text="Music" ></asp:ListItem>
                        <asp:ListItem Text="Movies" ></asp:ListItem>
                        <asp:ListItem Text="Cooking" ></asp:ListItem>
                    </asp:CheckBoxList></td>
            </tr>
            <tr>
                <td>IsActive :</td>
                <td><asp:CheckBox ID="chkisactive" runat="server" /></td>
            </tr>
            <tr>
                <td></td>
                <td><asp:Button ID="btnsave" Text="Save" runat="server" OnClick="btnsave_Click" /></td>
            </tr>
            <tr>
                <td></td>
                <td>
                    <asp:GridView ID="grd" runat="server" AutoGenerateColumns="false" OnRowCommand="grd_RowCommand">
                         <Columns>
                             <asp:TemplateField HeaderText="ID">
                                <ItemTemplate>
                                    <%#Eval("id") %>
                                </ItemTemplate>
                            </asp:TemplateField>

                            <asp:TemplateField HeaderText="Name">
                                <ItemTemplate>
                                    <%#Eval("name") %>
                                </ItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="country">
                                <ItemTemplate>
                                    <%#Eval("cname") %>
                                </ItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="state">
                                <ItemTemplate>
                                    <%#Eval("sname") %>
                                </ItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="Date of Birth">
                                <ItemTemplate>
                                    <%#Eval("dob") %>
                                </ItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="Gender">
                                <ItemTemplate>
                                    <%#Eval("gender").ToString() == "1" ? "Male" : Eval("gender").ToString() == "2" ? "Female" :"Others" %>
                                </ItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="Images">
                                <ItemTemplate>
                                   <asp:Image ID="img" runat="server" Width="50px" Height="40px" ImageUrl='<%#Eval("image","~/Employee/{0}") %>' />
                                </ItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="Hobbies">
                                <ItemTemplate>
                                   <%#Eval("hobbies") %>
                                </ItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="Status">
                                <ItemTemplate>
                                    <%#Eval("isactive").ToString() == "1" ? "Active" : "Inactive" %>
                                </ItemTemplate>
                            </asp:TemplateField>

                            <asp:TemplateField HeaderText="Delete">
                                <ItemTemplate>
                                   <asp:LinkButton ID="lnkbtndelete" runat="server" Text="Delete" CommandName="DLT" CommandArgument='<%#Eval("id") %>'></asp:LinkButton>
                                </ItemTemplate>
                            </asp:TemplateField>

                            <asp:TemplateField HeaderText="Edit">
                                <ItemTemplate>
                                   <asp:LinkButton ID="lnkbtnedit" runat="server" Text="Edit" CommandName="EDT" CommandArgument='<%#Eval("id") %>'></asp:LinkButton>
                                </ItemTemplate>
                            </asp:TemplateField>
                        </Columns>
                    </asp:GridView>
                </td>
            </tr>
        </table>
    </div>
    </form>
</body>
</html>

C#:

protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            Fill_Country();
            ddlstate.Items.Insert(0, new ListItem("--Select--", "0"));
            Fill_Grid();
        }
    }

    public void Fill_Country()
    {
        con.Open();
        SqlCommand cmd = new SqlCommand("usp_country_get", con);
        cmd.CommandType = CommandType.StoredProcedure;
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        da.Fill(ds);
        con.Close();
        if (ds.Tables[0].Rows.Count > 0)
        {
            ddlcountry.DataValueField = "cid";
            ddlcountry.DataTextField = "cname";
            ddlcountry.DataSource = ds;
            ddlcountry.DataBind();
            ddlcountry.Items.Insert(0, new ListItem("--Select--", "0"));
        }
    }

    public void Fill_State(string cid)
    {
        con.Open();
        SqlCommand cmd = new SqlCommand("usp_state_get", con);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@cid", cid);
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        da.Fill(ds);
        con.Close();
        if (ds.Tables[0].Rows.Count > 0)
        {
            ddlstate.DataValueField = "sid";
            ddlstate.DataTextField = "sname";
            ddlstate.DataSource = ds;
            ddlstate.DataBind();
            ddlstate.Items.Insert(0, new ListItem("--Select--", "0"));
        }
    }

    public void Fill_Grid()
    {
        con.Open();
        SqlCommand cmd = new SqlCommand("usp_emp_get", con);
        cmd.CommandType = CommandType.StoredProcedure;
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        da.Fill(ds);
        con.Close();
        if (ds.Tables[0].Rows.Count > 0)
        {
            grd.DataSource = ds;
            grd.DataBind();
        }
        else
        {
            grd.DataSource = null;
            grd.DataBind();
        }
    }

    protected void ddlcountry_SelectedIndexChanged(object sender, EventArgs e)
    {
        Fill_State(ddlcountry.SelectedValue);
    }

    protected void btnsave_Click(object sender, EventArgs e)
    {
        if (btnsave.Text == "Save")
        {
            string HOB = "";
            string FN = "";
            string Ext = "";
            Ext = Path.GetExtension(fuimage.PostedFile.FileName);
            if (Ext.ToLower() == ".jpg" || Ext.ToLower() == ".jpeg" || Ext.ToLower() == ".png")
            {
                for (int i = 0; i < chkhobbies.Items.Count; i++)
                {
                    if (chkhobbies.Items[i].Selected == true)
                    {
                        HOB += chkhobbies.Items[i].Text + ",";
                    }
                }
                HOB = HOB.TrimEnd(',');
                FN = DateTime.Now.Ticks.ToString() + Path.GetFileName(fuimage.PostedFile.FileName);
                fuimage.SaveAs(Server.MapPath("Employee" + "\" + FN));
                con.Open();
                SqlCommand cmd = new SqlCommand("usp_emp_insert", con);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@name", txtname.Text);
                cmd.Parameters.AddWithValue("@cid", ddlcountry.SelectedValue);
                cmd.Parameters.AddWithValue("@sid", ddlstate.SelectedValue);
                cmd.Parameters.AddWithValue("@dob", txtdob.Text);
                cmd.Parameters.AddWithValue("@gender", rblgender.SelectedValue);
                cmd.Parameters.AddWithValue("@image", FN);
                cmd.Parameters.AddWithValue("@hobbies", HOB);
                cmd.Parameters.AddWithValue("@isactive", chkisactive.Checked == true ? 1 : 0);
                cmd.ExecuteNonQuery();
                con.Close();
            }
            else
            {
                lblmsg.Text = "please upload only image file !!";
            }
        }
        else
        {
            string HOB = "";
            string FN = "";
            string Ext = "";
            Ext = Path.GetExtension(fuimage.PostedFile.FileName);
            if (Ext.ToLower() == ".jpg" || Ext.ToLower() == ".jpeg" || Ext.ToLower() == ".png")
            {
                for (int i = 0; i < chkhobbies.Items.Count; i++)
                {
                    if (chkhobbies.Items[i].Selected == true)
                    {
                        HOB += chkhobbies.Items[i].Text + ",";
                    }
                }
                HOB = HOB.TrimEnd(',');
                FN = DateTime.Now.Ticks.ToString() + Path.GetFileName(fuimage.PostedFile.FileName);
                fuimage.SaveAs(Server.MapPath("Employee" + "\" + FN));
                File.Delete(Server.MapPath("Employee" + "\" + ViewState["IMG"]));                    
                con.Open();
                SqlCommand cmd = new SqlCommand("usp_emp_update", con);
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@id", ViewState["ID"]);
                cmd.Parameters.AddWithValue("@name", txtname.Text);
                cmd.Parameters.AddWithValue("@cid", ddlcountry.SelectedValue);
                cmd.Parameters.AddWithValue("@sid", ddlstate.SelectedValue);
                cmd.Parameters.AddWithValue("@dob", txtdob.Text);
                cmd.Parameters.AddWithValue("@gender", rblgender.SelectedValue);
                cmd.Parameters.AddWithValue("@image", FN);
                cmd.Parameters.AddWithValue("@hobbies", HOB);
                cmd.Parameters.AddWithValue("@isactive", chkisactive.Checked == true ? 1 : 0);
                cmd.ExecuteNonQuery();
                con.Close();
            }
            else
            {
                lblmsg.Text = "please upload only image file !!";
            }
        }
        Fill_Grid();
    }

    protected void grd_RowCommand(object sender, GridViewCommandEventArgs e)
    {
        if (e.CommandName=="EDT")
        {
            con.Open();
            SqlCommand cmd = new SqlCommand("usp_emp_edit", con);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("@id", e.CommandArgument);
            SqlDataAdapter da = new SqlDataAdapter(cmd);
            DataSet ds = new DataSet();
            da.Fill(ds);
            con.Close();
            if (ds.Tables[0].Rows.Count > 0)
            {
                txtname.Text = ds.Tables[0].Rows[0]["name"].ToString();
                ddlcountry.SelectedValue = ds.Tables[0].Rows[0]["cid"].ToString();
                Fill_State(ddlcountry.SelectedValue);
                ddlstate.SelectedValue = ds.Tables[0].Rows[0]["sid"].ToString();
                txtdob.Text=ds.Tables[0].Rows[0]["dob"].ToString();
                rblgender.SelectedValue = ds.Tables[0].Rows[0]["gender"].ToString() == "1" ? "1" : ds.Tables[0].Rows[0]["gender"].ToString() == "2" ? "2" : "3";
                chkisactive.Checked = ds.Tables[0].Rows[0]["isactive"].ToString() == "1" ? true : false;
                string[] arr = ds.Tables[0].Rows[0]["hobbies"].ToString().Split(',');
                chkhobbies.ClearSelection();
                for (int i = 0; i < chkhobbies.Items.Count; i++)
                {
                    for (int j = 0; j < arr.Length; j++)
                    {
                        if (chkhobbies.Items[i].Text == arr[j])
                        {
                            chkhobbies.Items[i].Selected = true;
                            break;
                        }
                    }
                }
                ViewState["IMG"] = ds.Tables[0].Rows[0]["image"].ToString();
                btnsave.Text = "Update";
                ViewState["ID"] = e.CommandArgument;
            }
        }
        else if(e.CommandName == "DLT")
        {
            con.Open();
            SqlCommand cmd = new SqlCommand("usp_emp_delete", con);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("@id", e.CommandArgument);
            SqlParameter param = cmd.Parameters.Add("@image", SqlDbType.VarChar, 50);
            param.Direction = ParameterDirection.Output;
            cmd.ExecuteNonQuery();
            con.Close();
            string Old_image = cmd.Parameters["@image"].Value.ToString();
            File.Delete(Server.MapPath("Employee" + "\" + Old_image));
            Fill_Grid();
        }
    }
    Asp.net Inside Gridview:
    
    aspx:
    
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Employee.aspx.cs" Inherits="Asp_inside_gridview.Employee" %>
<%@ Register Assembly="AjaxControlToolkit" Namespace="AjaxControlToolkit" TagPrefix="ajax" %>
<!DOCTYPE html>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
</head>
<body>
    <form id="form1" runat="server">
        <ajax:ToolkitScriptManager ID="ajaxcal" runat="server"></ajax:ToolkitScriptManager>
    <div>
    <table>
            <tr>
                <td>Name :</td>
                <td><asp:TextBox ID="txtname" runat="server" /></td>
            </tr>
            <tr>
                <td>Country :</td>
                <td><asp:DropDownList ID="ddlcountry" runat="server" ></asp:DropDownList></td>
            </tr>
            <tr>
                <td>Date of Birth :</td>
                <td><asp:TextBox ID="txtdob" runat="server" />
                    <ajax:CalendarExtender ID="caldob" runat="server" Format="dd/MM/yyyy" PopupButtonID="txtdob" TargetControlID="txtdob" PopupPosition="BottomRight"></ajax:CalendarExtender></td>
            </tr>
            <tr>
                <td>Gender :</td>
                <td>
                    <asp:RadioButtonList ID="rblgender" runat="server" RepeatColumns="3">
                        <asp:ListItem Text="Male" Value="1"/>
                        <asp:ListItem Text="Female" Value="2" />
                        <asp:ListItem Text="Others" Value="3" />
                    </asp:RadioButtonList></td>
            </tr>
            <tr>
                <td>Image :</td>
                <td><asp:FileUpload ID="fuimage" runat="server" /><asp:Label ID="lblmsg" runat="server" ForeColor="Red" Font-Bold="true"></asp:Label></td>
            </tr>
            <tr>
                <td>Hobbies :</td>
                <td>
                    <asp:CheckBoxList ID="chkhobbies" runat="server" RepeatColumns="5">
                        <asp:ListItem Text="Cricket"></asp:ListItem>
                        <asp:ListItem Text="Football" ></asp:ListItem>
                        <asp:ListItem Text="Coding" ></asp:ListItem>
                        <asp:ListItem Text="Reading" ></asp:ListItem>
                        <asp:ListItem Text="Travelling" ></asp:ListItem>
                        <asp:ListItem Text="Gym" ></asp:ListItem>
                        <asp:ListItem Text="Singing" ></asp:ListItem>
                        <asp:ListItem Text="Dancing" ></asp:ListItem>
                        <asp:ListItem Text="Music" ></asp:ListItem>
                        <asp:ListItem Text="Movies" ></asp:ListItem>
                        <asp:ListItem Text="Cooking" ></asp:ListItem>
                    </asp:CheckBoxList></td>
            </tr>
            <tr>
                <td>IsActive :</td>
                <td><asp:CheckBox ID="chkisactive" runat="server" /></td>
            </tr>
            <tr>
                <td></td>
                <td><asp:Button ID="btnsave" Text="Save" runat="server" OnClick="btnsave_Click" /></td>
            </tr>
            <tr>
                <td></td>
                <td>
                    <asp:GridView ID="grd" runat="server" AutoGenerateColumns="false" DataKeyNames="id" OnRowUpdating="grd_RowUpdating" OnRowEditing="grd_RowEditing" OnRowCancelingEdit="grd_RowCancelingEdit" OnRowDeleting="grd_RowDeleting" OnRowDataBound="grd_RowDataBound" >
                         <Columns>
                             <asp:TemplateField HeaderText="ID">
                                <ItemTemplate>
                                    <%#Eval("id") %>
                                </ItemTemplate>
                            </asp:TemplateField>

                            <asp:TemplateField HeaderText="Name">
                                <ItemTemplate>
                                    <%#Eval("name") %>
                                </ItemTemplate>
                                <EditItemTemplate>
                                        <asp:TextBox ID="txteditname" runat="server" Text='<%#Eval("name") %>'></asp:TextBox>
                                    </EditItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="country">
                                <ItemTemplate>
                                    <%#Eval("cname") %>
                                </ItemTemplate>
                                 <EditItemTemplate>
                                        <asp:DropDownList ID="ddleditcountry" runat="server"></asp:DropDownList>
                                    </EditItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="Date of Birth">
                                <ItemTemplate>
                                    <%#Eval("dob") %>
                                </ItemTemplate>
                                 <EditItemTemplate>
                                     <asp:TextBox ID="txteditdob" runat="server" Text='<%#Eval("dob") %>' />
                    <ajax:CalendarExtender ID="caleditdob" runat="server" Format="dd/MM/yyyy" PopupButtonID="txteditdob" TargetControlID="txteditdob" PopupPosition="BottomRight"></ajax:CalendarExtender>
                                 </EditItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="Gender">
                                <ItemTemplate>
                                    <%#Eval("gender").ToString() == "1" ? "Male" : Eval("gender").ToString() == "2" ? "Female" :"Others" %>
                                </ItemTemplate>
                                 <EditItemTemplate>
                                    <asp:RadioButtonList ID="rbleditgender" runat="server" RepeatColumns="3">
                                    <asp:ListItem Text="Male" Value="1"/>
                                    <asp:ListItem Text="Female" Value="2" />
                                    <asp:ListItem Text="Others" Value="3" />
                                    </asp:RadioButtonList>
                                 </EditItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="Images">
                                <ItemTemplate>
                                   <asp:Image ID="img" runat="server" Width="100px" Height="80px" ImageUrl='<%#Eval("image","~/Employee/{0}") %>' />
                                </ItemTemplate>
                                 <EditItemTemplate>
                                        <asp:FileUpload ID="fueditimages" runat="server"></asp:FileUpload>
                                    </EditItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="Hobbies">
                                <ItemTemplate>
                                   <%#Eval("hobbies") %>
                                </ItemTemplate>
                                 <EditItemTemplate>
                                        <asp:CheckBoxList ID="chkedithobbies" runat="server" RepeatColumns="3">
                                            <asp:ListItem Text="Cricket"></asp:ListItem>
                                            <asp:ListItem Text="Football" ></asp:ListItem>
                                            <asp:ListItem Text="Coding" ></asp:ListItem>
                                            <asp:ListItem Text="Reading" ></asp:ListItem>
                                            <asp:ListItem Text="Travelling" ></asp:ListItem>
                                            <asp:ListItem Text="Gym" ></asp:ListItem>
                                            <asp:ListItem Text="Singing" ></asp:ListItem>
                                            <asp:ListItem Text="Dancing" ></asp:ListItem>
                                            <asp:ListItem Text="Music" ></asp:ListItem>
                                            <asp:ListItem Text="Movies" ></asp:ListItem>
                                            <asp:ListItem Text="Cooking" ></asp:ListItem>
                                        </asp:CheckBoxList>
                                    </EditItemTemplate>
                            </asp:TemplateField>

                             <asp:TemplateField HeaderText="Status">
                                <ItemTemplate>
                                    <%#Eval("isactive").ToString() == "1" ? "Active" : "Inactive" %>
                                </ItemTemplate>
                                 <EditItemTemplate> 
                                     <asp:CheckBox ID="chkeditisactive" runat="server" />
                                 </EditItemTemplate>
                            </asp:TemplateField>

                            <asp:TemplateField HeaderText="Delete">
                                <ItemTemplate>
                                   <asp:LinkButton ID="lnkbtndelete" runat="server" Text="Delete" CommandName="Delete" CommandArgument='<%#Eval("id") %>'></asp:LinkButton>                                
                                   <asp:LinkButton ID="lnkbtnedit" runat="server" Text="Edit" CommandName="Edit" CommandArgument='<%#Eval("id") %>'></asp:LinkButton>
                                </ItemTemplate>
                                <EditItemTemplate>
                                        <asp:LinkButton ID="lnkbtnupdate" runat="server" Text="Update" CommandName="Update"></asp:LinkButton>
                                        <asp:LinkButton ID="lnkbtncancel" runat="server" Text="Cancel" CommandName="Cancel"></asp:LinkButton>
                                    </EditItemTemplate>
                            </asp:TemplateField>
                        </Columns>
                    </asp:GridView>
                </td>
            </tr>
        </table>
    </div>
    </form>
</body>
</html>

cs:

protected void Page_Load(object sender, EventArgs e) { 如果(!IsPostBack) { Fill_Country(); Fill_Grid(); } }

    public void Fill_Country()
    {
        con.Open();
        SqlCommand cmd = new SqlCommand("usp_country_get", con);
        cmd.CommandType = CommandType.StoredProcedure;
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        da.Fill(ds);
        con.Close();
        if (ds.Tables[0].Rows.Count > 0)
        {
            ddlcountry.DataValueField = "cid";
            ddlcountry.DataTextField = "cname";
            ddlcountry.DataSource = ds;
            ddlcountry.DataBind();
            ddlcountry.Items.Insert(0, new ListItem("--Select--", "0"));
        }
    }

    public void Fill_Grid()
    {
        con.Open();
        SqlCommand cmd = new SqlCommand("usp_emp_get", con);
        cmd.CommandType = CommandType.StoredProcedure;
        SqlDataAdapter da = new SqlDataAdapter(cmd);
        DataSet ds = new DataSet();
        da.Fill(ds);
        con.Close();
        if (ds.Tables[0].Rows.Count > 0)
        {
            grd.DataSource = ds;
            grd.DataBind();
        }
        else
        {
            grd.DataSource = null;
            grd.DataBind();
        }
    }

    protected void btnsave_Click(object sender, EventArgs e)
    {
        string HOB = "";
        string FN = "";
        string Ext = "";
        Ext = Path.GetExtension(fuimage.PostedFile.FileName);
        if (Ext.ToLower() == ".jpg" || Ext.ToLower() == ".jpeg" || Ext.ToLower() == ".png")
        {
            for (int i = 0; i < chkhobbies.Items.Count; i++)
            {
                if (chkhobbies.Items[i].Selected == true)
                {
                    HOB += chkhobbies.Items[i].Text + ",";
                }
            }
            HOB = HOB.TrimEnd(',');
            FN = DateTime.Now.Ticks.ToString() + Path.GetFileName(fuimage.PostedFile.FileName);
            fuimage.SaveAs(Server.MapPath("Employee" + "\" + FN));
            con.Open();
            SqlCommand cmd = new SqlCommand("usp_emp_insert", con);
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.AddWithValue("@name", txtname.Text);
            cmd.Parameters.AddWithValue("@cid", ddlcountry.SelectedValue);
            cmd.Parameters.AddWithValue("@dob", txtdob.Text);
            cmd.Parameters.AddWithValue("@gender", rblgender.SelectedValue);
            cmd.Parameters.AddWithValue("@image", FN);
            cmd.Parameters.AddWithValue("@hobbies", HOB);
            cmd.Parameters.AddWithValue("@isactive", chkisactive.Checked == true ? 1 : 0);
            cmd.ExecuteNonQuery();
            con.Close();
        }
        else
        {
            lblmsg.Text = "please upload only image file !!";
        }

        Fill_Grid();
    }

    protected void grd_RowEditing(object sender, GridViewEditEventArgs e)
    {
        grd.EditIndex = e.NewEditIndex;
        Fill_Grid();
    }

    protected void grd_RowCancelingEdit(object sender, GridViewCancelEditEventArgs e)
    {
        grd.EditIndex = -1;
        Fill_Grid();
    }

    protected void grd_RowDeleting(object sender, GridViewDeleteEventArgs e)
    {
        string IDD = grd.DataKeys[e.RowIndex].Value.ToString();
        con.Open();
        SqlCommand cmd = new SqlCommand("usp_emp_delete", con);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@id", IDD);
        SqlParameter param = cmd.Parameters.Add("@image", SqlDbType.VarChar, 50);
        param.Direction = ParameterDirection.Output;
        cmd.ExecuteNonQuery();
        con.Close();
        string PPP = cmd.Parameters["@image"].Value.ToString();
        File.Delete(Server.MapPath("Employee" + "\" + PPP));
        Fill_Grid();
    }

    protected void grd_RowDataBound(object sender, GridViewRowEventArgs e)
    {
        if (e.Row.RowType == DataControlRowType.DataRow)
        {
            if ((e.Row.RowState & DataControlRowState.Edit) > 0)
            {
                DropDownList DDL = (DropDownList)e.Row.FindControl("ddleditcountry");
                CheckBoxList CBL = (CheckBoxList)e.Row.FindControl("chkedithobbies");
                RadioButtonList RBL = (RadioButtonList)e.Row.FindControl("rbleditgender");
                CheckBox CBIA = (CheckBox)e.Row.FindControl("chkeditisactive");

                con.Open();
                SqlCommand cmd = new SqlCommand("usp_country_get", con);
                cmd.CommandType = CommandType.StoredProcedure;
                SqlDataAdapter da = new SqlDataAdapter(cmd);
                DataSet ds = new DataSet();
                da.Fill(ds);
                con.Close();
                if (ds.Tables[0].Rows.Count > 0)
                {
                    DDL.DataValueField = "cid";
                    DDL.DataTextField = "cname";
                    DDL.DataSource = ds;
                    DDL.DataBind();
                    DDL.Items.Insert(0, new ListItem("--Select--", "0"));
                }

                DataRowView drv = (DataRowView)e.Row.DataItem;
                DDL.SelectedValue = drv["cid"].ToString();
                RBL.SelectedValue = drv["gender"].ToString();
                string[] arr = drv["hobbies"].ToString().Split(',');
                CBL.ClearSelection();
                for (int i = 0; i < CBL.Items.Count; i++)
                {
                    for (int j = 0; j < arr.Length; j++)
                    {
                        if (CBL.Items[i].Text == arr[j])
                        {
                            CBL.Items[i].Selected = true;
                            break;
                        }
                    }
                }

                CBIA.Checked = drv["isactive"].ToString() == "1" ? true : false;
                ViewState["IMG"] = drv["image"].ToString();
            }
        }
    }

    protected void grd_RowUpdating(object sender, GridViewUpdateEventArgs e)
    {
        TextBox TBN = (TextBox)grd.Rows[e.RowIndex].FindControl("txteditname");
        DropDownList DDLC = (DropDownList)grd.Rows[e.RowIndex].FindControl("ddleditcountry");
        TextBox TBD = (TextBox)grd.Rows[e.RowIndex].FindControl("txteditdob");
        RadioButtonList RBLG = (RadioButtonList)grd.Rows[e.RowIndex].FindControl("rbleditgender");
        FileUpload FUI = (FileUpload)grd.Rows[e.RowIndex].FindControl("fueditimages");
        CheckBoxList CBLH = (CheckBoxList)grd.Rows[e.RowIndex].FindControl("chkedithobbies");
        CheckBox CBI = (CheckBox)grd.Rows[e.RowIndex].FindControl("chkeditisactive");
        string IDD = grd.DataKeys[e.RowIndex].Value.ToString();

        string FN = "";
        string HOB = "";
        for (int i = 0; i < CBLH.Items.Count; i++)
        {
            if (CBLH.Items[i].Selected == true)
            {
                HOB += CBLH.Items[i].Text + ",";
            }
        }
        HOB = HOB.TrimEnd(',');

        FN = Path.GetFileName(FUI.PostedFile.FileName);

        con.Open();
        SqlCommand cmd = new SqlCommand("usp_emp_update", con);
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.AddWithValue("@id", IDD);
        cmd.Parameters.AddWithValue("@name", TBN.Text);
        cmd.Parameters.AddWithValue("@cid", DDLC.SelectedValue);
        cmd.Parameters.AddWithValue("@dob", TBD.Text);
        cmd.Parameters.AddWithValue("@gender", RBLG.SelectedValue);
        if (FN != "")
        {
            FN = DateTime.Now.Ticks.ToString() + FN;
            cmd.Parameters.AddWithValue("@image", FN);
            FUI.SaveAs(Server.MapPath("Employee" + "\" + FN));
            File.Delete(Server.MapPath("Employee" + "\" + ViewState["IMG"]));

        }
        else
        {
            cmd.Parameters.AddWithValue("@image", ViewState["IMG"]);
        }
        cmd.Parameters.AddWithValue("@hobbies", HOB);
        cmd.Parameters.AddWithValue("@isactive", CBI.Checked == true ? "1" : "2");
        cmd.ExecuteNonQuery();
        con.Close();
        grd.EditIndex = -1;
        Fill_Grid();
    }