从同一表单同时保存多行 - dotnet core [英] Save multiple rows simultaneously from the same form - dotnet core

查看:23
本文介绍了从同一表单同时保存多行 - dotnet core的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个表,其中有一个空列,用户可以在其中输入评论:

表格-----TbMapId |唯一广告 |经销商 |线--------------------------------------------------------------------1 |[在此处插入评论] |德比 |abc1232 |[在此处插入评论] |基斯利 |cda3453 |[在此处插入评论] |曼彻斯特 |876ghj

要评论的数据很多,我不能指望用户打开编辑"页面并逐条输入评论.相反,我需要用户能够输入一堆评论(比如 20 行,每次 20 行),然后单击提交按钮即可全部保存.

<小时>

如果您想直接跳到工作解决方案,请转到EDIT #2 &看看鲁迪接受的答案

<小时>

查看

 
<div class="col-lg-6"><div class="row"><input type="submit" value="Save" class="btn btn-primary"/><div class="col-md-12"><table class="table table-condensed table-bordered table-hover"><头><tr><td><b>TEMP ID</b></td><td><b>映射到</b></td><td><b>帐户代码</b></td><td><b>线</b></td><td><b>地图结果</b></td></tr></thead>@for (int i = 0; i < Model.TBMapBalancesList.Count; i++){<tr><td>@Html.DisplayFor(Model => Model.TBMapBalancesList[i].TbMapId)@Html.HiddenFor(Model => Model.TBMapBalancesList[i].TbMapId)</td><td>@Html.EditorFor(Model => Model.TBMapBalancesList[i].UniqueAdp, new { @class = "control-label_DI" })</td>@Html.DisplayFor(Model => Model.TBMapBalancesList[i].AccountsCode)<td>@Html.DisplayFor(Model => Model.TBMapBalancesList[i].Line)</td><td>@Html.DisplayFor(Model => Model.TBMapBalancesList[i].MapResult)</td></tr>}</tbody>

</表单>

模型

我今天了解到我需要使用 List 才能通过使用 @for 循环(如上所示)遍历表中的行.在我尝试使用 IEnumerable 之前.所以我为 public List 的模型添加了一个定义.TBMapBalancesList { 获取;放;}

 公共类 TbMapViewModel{公共 IEnumerableTBMapBalances { 获取;放;}公共 IEnumerableTBMapUniqueADP { 获取;放;}公共列表<TBMapBalances>TBMapBalancesList { 获取;放;}[...]}

控制器:

现在这是我需要帮助的地方,我的代码根本没有抛出任何错误.当我按下提交时什么也没有发生:

 [授权][HttpPost]公共异步任务TbMapViewEdit(TbMapViewModel tbMapViewModel){如果(模型状态.IsValid){foreach(tbMapViewModel.TBMapBalancesList 中的 var TbListId){var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();如果(获取代码!= null){getCode.TbMapId = TbListId.TbMapId;}}尝试{_context.Update(tbMapViewModel.TBMapBalances);等待 _context.SaveChangesAsync();}捕获 (DbUpdateConcurrencyException){扔;}}return RedirectToAction("TbMapView");}

编辑 #1

视图的变化

 <div class="col-lg-6"><div class="row"><input type="submit" value="Save" class="btn btn-primary"/><div class="col-md-12"><table class="table table-condensed table-bordered table-hover"><头><tr><td><b>TEMP ID</b></td><td><b>映射到</b></td><td><b>帐户代码</b></td><td><b>线</b></td><td><b>地图结果</b></td></tr></thead>@for (int i = 0; i < Model.TBMapBalances.Count; i++){<tr><td>@Html.DisplayFor(Model => Model.TBMapBalances[i].TbMapId)@Html.HiddenFor(Model => Model.TBMapBalances[i].TbMapId)</td><td>@Html.EditorFor(Model => Model.TBMapBalances[i].UniqueAdp, new { @class = "control-label_DI" })</td>@Html.DisplayFor(Model => Model.TBMapBalances[i].AccountsCode)<td>@Html.DisplayFor(Model => Model.TBMapBalances[i].Line)</td><td>@Html.DisplayFor(Model => Model.TBMapBalances[i].MapResult)</td></tr>}</tbody>

</表单>

模型变化

使用系统;使用 System.Collections.Generic;使用 System.Linq;使用 System.Threading.Tasks;命名空间 ASPNET_Core_1_0.Models.TbMapViewModels{公共类 TbMapViewModel{公共 IEnumerableTBMapUniqueADP { 获取;放;}公共列表<TBMapBalances>TBMapBalances { 获取;放;}[...]}}

控制器变更:

现在这是我需要帮助的地方,我的代码在当前状态下根本不会抛出任何错误 - 当我按下提交时,什么也没有发生,也没有数据被保存到数据库中.

但是,当您取消注释行 _context.Update(tbMapViewModel.TBMapBalances);我收到一个错误,指出 List 不属于任何模型并且未找到.

另外,下面的代码是我写的东西,试图按照这个 SO 帖子:update-multiple-records-at-once-in-asp-net-mvc - 最初我试图让它异步,但我得到了更多错误,无法继续.我想我会尽可能地密切关注它,希望它能为我提供一个工作起点.

 [授权][HttpPost]公共 IActionResult TbMapViewEdit(TbMapViewModel tbMapViewModel){如果(模型状态.IsValid){foreach(tbMapViewModel.TBMapBalances 中的 var TbListId){var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();如果(获取代码!= null){getCode.TbMapId = TbListId.TbMapId;}}//_context.Update(tbMapViewModel.TBMapBalances);_context.SaveChanges();}return RedirectToAction("TbMapView");}

编辑 #2 - 拯救英雄 - 非常感谢@RudiVisser 的帮助

首先,如果你们中的任何人 - 像我一样 - 坚持使用 .net core 1.0.0确保首先升级到最新版本(1.1.7 lts).我悲痛的部分原因是我是 USER 1.0 并且没有升级我的安装,因为修复和添加不断出现.不要像我那样做那个人...

以下所有内容都感谢 Rudi 的帮助:

查看

@using (Html.BeginForm("TbMapViewEdit", "TbMap")){<div class="col-lg-6"><div class="row"><input type="submit" value="Save" class="btn btn-primary"/><div class="col-md-12"><table class="table table-condensed table-bordered table-hover"><头><tr><td><b>TEMP ID</b></td><td><b>映射到</b></td><td><b>帐户代码</b></td><td><b>线</b></td><td><b>地图结果</b></td></tr></thead>@Html.EditorFor(m => m.TBMapBalances);</tbody>

}

将您的方法"、控制器"放入(Html.BeginForm("TbMapViewEdit", "TbMap")) 否则表单POST 操作将设置为当前位置.

模型

为简洁起见被截断.我有一个带有 List 的视图模型,我会将数据保存到另一个表中,只是为了显示一些信息.

 公共类 TbMapViewModel{公共 IEnumerableTBMapUniqueADP { 获取;放;}公共列表<TBMapBalances>TBMapBalances { 获取;放;} = new List();[...]}

控制器

[授权][HttpPost]公共 IActionResult TbMapViewEdit(TbMapViewModel tbMapViewModel){如果(模型状态.IsValid){foreach(tbMapViewModel.TBMapBalances 中的 var TbListId){var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();如果(获取代码!= null){getCode.UniqueAdp = TbListId.UniqueAdp;}}_context.SaveChanges();}return RedirectToAction("TbMapView");}

我在这里犯的错误是我试图用它本身的副本替换密钥(查找 ID 为 1 并将其设置为 ID 1),而不是选择我需要的实际字段编辑在我的情况下是 UniqueAdp.

然后我想到了一个新东西,那就是编辑器模板:

编辑器模板

在视图"文件夹下的共享"文件夹中创建一个名为 EditorTemplates 的文件夹,并使用您要编辑的模型的确切名称.在我的例子中,模型被称为 TBMapBalances 所以我在新创建的文件夹中创建了一个 TBMapBalances.cshtml 文件,然后粘贴它(这最初在我的主视图文件中):

@model ASPNET_Core_1_0.Models.TBMapBalances<tr><td>@Html.DisplayFor(Model => Model.TbMapId)@Html.HiddenFor(Model => Model.TbMapId)</td><td>@Html.EditorFor(Model => Model.UniqueAdp, new { @class = "control-label_DI" })</td><td>@Html.DisplayFor(Model => Model.AccountsCode)</td><td>@Html.DisplayFor(Model => Model.Line)</td><td>@Html.DisplayFor(Model => Model.MapResult)</td></tr>

顺便说一下,new { @class = "control-label_DI" } 应该是为每个创建的输入字段添加类.这似乎在 .net core 中不起作用,留在那里只是为了提醒自己我需要以某种方式这样做.

研究:

在asp.net mvc中一次更新多条记录

https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms

http://www.binaryintellect.net/articles/b1e0b153-47f4-4b29-8583-958aa22d9284.aspx

如何在 MVC Core 中绑定数组

https://www.red-gate.com/simple-talk/dotnet/asp-net/model-binding-asp-net-core/

ASP.NET Core 1.0 POST IEnumerable;到控制器

解决方案

这个问题有两部分,第一是需要一种编辑数据集合的方法.这可以通过 EditorTemplates 解决,它涉及创建单个编辑器模型,然后在您希望编辑的项目集合上调用 @Html.EditorFor(..).

在 Github 上提供了一个最小示例(Full Fx,而不是 Core).

第二个问题是更新实体的方式,更改的属性是错误的,因此没有保存(PK 正在更新到 PK),并且实体在已经被跟踪时被附加.

foreach(tbMapViewModel.TBMapBalancesList 中的 var TbListId){var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();如果(获取代码!= null){getCode.TbMapId = TbListId.TbMapId;}}尝试{_context.Update(tbMapViewModel.TBMapBalances);等待 _context.SaveChangesAsync();}捕获 (DbUpdateConcurrencyException){扔;}

当您从数据库中检索模型时,请务必记住 Entity Framework 为您做什么.它由上下文自动跟踪,因此它已经附加并准备好更新,您更改的任何内容都将自动跟踪并随后保存.

_context.Update(..) 的调用尝试将非跟踪模型(来自您发布的数据)附加到基于 ID 的上下文,但因为您已经提取了该 IDout(在你的 .Where(..).FirstOrDefault(..))它已经被跟踪了,所以爆炸了.

另外鉴于这是 EFC 1.0 并且您没有 .Find(..) 方法,使用 .SingleOrDefault(..) 可能是更好的使用方法在主键字段上.

你重写的代码可能是这样的:

foreach(tbMapViewModel.TBMapBalancesList 中的 varpostedModel){var dbModel = _context.TBMapBalances.SingleOrDefault(p => p.TbMapId ==postedModel.TbMapId);如果(dbModel != null){dbModel.UniqueAdp = PostedModel.UniqueAdp;}}等待 _context.SaveChangesAsync();

为了后代,虽然出于安全原因我不会推荐它,如果您想将整个发布的模型附加到上下文(基于 ID)并更新它,您可以使用与原始模型类似的代码来执行此操作,删除foreach 循环:

_context.UpdateRange(tbMapViewModel.TBMapBalances);等待 _context.SaveChangesAsync();

(我不推荐它,因为发布的所有内容都将在数据库中设置,根据经验,建议只设置您希望按照第一个代码集更新的字段.但是,它应该,比 foreach 循环更快,因为您没有从数据库加载并保存回,只有后者)

I have a table that has one empty column into which user can enter a comment:

Table
-----

TbMapId |        UniqueAdp         |    Dealership    |    Line
--------------------------------------------------------------------
1       |    [Insert comment here] |    Derby         |    abc123
2       |    [Insert comment here] |    Keighley      |    cda345
3       |    [Insert comment here] |    Manchester    |    876ghj

There is a lot of data to comment on, I can't expect a user to open an 'Edit' page and type in a comment one by one. Instead I need user to be able to input a bunch of comments (say 20 at a time against 20 rows) and save them all at one click of submit button.


If you want to jump straight to working solution go to EDIT #2 & look at Rudi's accepted answer


View

        <form asp-action="TbMapViewEdit">
            <div class="col-lg-6">
                <div class="row">
                    <input type="submit" value="Save" class="btn btn-primary" />
                    <div class="col-md-12">
                        <table class="table table-condensed table-bordered table-hover">
                            <thead>
                                <tr>
                                    <td><b>TEMP ID</b></td>
                                    <td><b>Map To</b></td>
                                    <td><b>Accounts Code</b></td>
                                    <td><b>Line</b></td>
                                    <td><b>Map Result</b></td>
                                </tr>
                            </thead>
                            <tbody>

                                @for (int i = 0; i < Model.TBMapBalancesList.Count; i++)
                                { 
                                    <tr>
                                        <td>
                                            @Html.DisplayFor(Model => Model.TBMapBalancesList[i].TbMapId)
                                            @Html.HiddenFor(Model => Model.TBMapBalancesList[i].TbMapId)
                                        </td>
                                        <td>@Html.EditorFor(Model => Model.TBMapBalancesList[i].UniqueAdp, new { @class = "control-label_DI" })</td>
                                        <td>@Html.DisplayFor(Model => Model.TBMapBalancesList[i].AccountsCode)</td>
                                        <td>@Html.DisplayFor(Model => Model.TBMapBalancesList[i].Line)</td>
                                        <td>@Html.DisplayFor(Model => Model.TBMapBalancesList[i].MapResult)</td>
                                    </tr>
                                }

                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </form>

Model

I've learned today that I need to use List to be able to iterate through the lines in table by the use of @for loop (as shown above). before I was trying to use IEnumerable. So I added a definition to the model for public List<TBMapBalances> TBMapBalancesList { get; set; }

 public class TbMapViewModel
    {
        public IEnumerable<ASPNET_Core_1_0.Models.TBMapBalances> TBMapBalances { get; set; }
        public IEnumerable<ASPNET_Core_1_0.Models.TBMapUniqueADP> TBMapUniqueADP { get; set; }
        public List<TBMapBalances> TBMapBalancesList { get; set; }

       [...]

    }

Controller:

Now this is where I need the help with, my code doesn't throw any errors at all. When I press Submit nothing happens:

        [Authorize]
        [HttpPost]
        public async Task<IActionResult> TbMapViewEdit(TbMapViewModel tbMapViewModel)
        {

            if (ModelState.IsValid)
            {
                foreach (var TbListId in tbMapViewModel.TBMapBalancesList)
                {
                    var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();

                    if (getCode != null)
                    {
                        getCode.TbMapId = TbListId.TbMapId;
                    }

                }

                try
                {
                    _context.Update(tbMapViewModel.TBMapBalances);
                    await _context.SaveChangesAsync();
                }

                catch (DbUpdateConcurrencyException)
                {
                    throw;
                }
            }

            return RedirectToAction("TbMapView");
        }

EDIT #1

Changes to View

        <form asp-action="TbMapViewEdit">
            <div class="col-lg-6">
                <div class="row">
                    <input type="submit" value="Save" class="btn btn-primary" />
                    <div class="col-md-12">
                        <table class="table table-condensed table-bordered table-hover">
                            <thead>
                                <tr>
                                    <td><b>TEMP ID</b></td>
                                    <td><b>Map To</b></td>
                                    <td><b>Accounts Code</b></td>
                                    <td><b>Line</b></td>
                                    <td><b>Map Result</b></td>
                                </tr>
                            </thead>
                            <tbody>
                                @for (int i = 0; i < Model.TBMapBalances.Count; i++)
                                { 
                                    <tr>
                                        <td>
                                            @Html.DisplayFor(Model => Model.TBMapBalances[i].TbMapId)
                                            @Html.HiddenFor(Model => Model.TBMapBalances[i].TbMapId)
                                        </td>
                                        <td>@Html.EditorFor(Model => Model.TBMapBalances[i].UniqueAdp, new { @class = "control-label_DI" })</td>
                                        <td>@Html.DisplayFor(Model => Model.TBMapBalances[i].AccountsCode)</td>
                                        <td>@Html.DisplayFor(Model => Model.TBMapBalances[i].Line)</td>
                                        <td>@Html.DisplayFor(Model => Model.TBMapBalances[i].MapResult)</td>
                                    </tr>
                                }

                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
        </form>

Changes to model

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ASPNET_Core_1_0.Models.TbMapViewModels
{
    public class TbMapViewModel
    {

        public IEnumerable<ASPNET_Core_1_0.Models.TBMapUniqueADP> TBMapUniqueADP { get; set; }
        public List<TBMapBalances> TBMapBalances { get; set; }

        [...]
    }
}

Changes to Controller:

Now this is where I need the help with, my code doesn't throw any errors at all when at the current state - when I press Submit nothing happens and no data gets saved to the database.

however, when you uncomment line _context.Update(tbMapViewModel.TBMapBalances); I get an error that List is not part of any Model and is not found.

Also, below code is something I wrote trying to follow this SO post: update-multiple-records-at-once-in-asp-net-mvc - Initially I was trying to make it Async but I was getting even more errors and couldn't continue. I thought I am going to follow it as closely as possible in hope that it will get me a working starting point.

        [Authorize]
        [HttpPost]
        public IActionResult TbMapViewEdit(TbMapViewModel tbMapViewModel)
        {

            if (ModelState.IsValid)
            {
                foreach (var TbListId in tbMapViewModel.TBMapBalances)
                {
                    var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();

                    if (getCode != null)
                    {
                        getCode.TbMapId = TbListId.TbMapId;
                    }

                }
               // _context.Update(tbMapViewModel.TBMapBalances);
                _context.SaveChanges();

            }

            return RedirectToAction("TbMapView");
        }

EDIT #2 - A hero to the rescue - big thanks to @RudiVisser for help

First of all if any of you guys are - like me - stuck using .net core 1.0.0 make sure you upgrade to the latest version first (1.1.7 lts). Part of my grief was that I was an USER 1.0 and did not upgrade my installation as fixes and additions kept coming out. Don't be that guy, like I was...

All below is thanks to Rudi's help:

View

@using (Html.BeginForm("TbMapViewEdit", "TbMap"))
{
            <div class="col-lg-6">
                <div class="row">
                    <input type="submit" value="Save" class="btn btn-primary" />
                    <div class="col-md-12">
                        <table class="table table-condensed table-bordered table-hover">
                            <thead>
                                <tr>
                                    <td><b>TEMP ID</b></td>
                                    <td><b>Map To</b></td>
                                    <td><b>Accounts Code</b></td>
                                    <td><b>Line</b></td>
                                    <td><b>Map Result</b></td>
                                </tr>
                            </thead>
                            <tbody>
                                 @Html.EditorFor(m => m.TBMapBalances);
                            </tbody>
                        </table>
                    </div>
                </div>
            </div>
}

Put your "Method", "Controller" in (Html.BeginForm("TbMapViewEdit", "TbMap")) otherwise the form POST action will be set to the current location.

Model

Truncated for brevity. I have view model with List that I will be saving the data to and one other table just for displaying some info.

 public class TbMapViewModel
    {
        public IEnumerable<ASPNET_Core_1_0.Models.TBMapUniqueADP> TBMapUniqueADP { get; set; }
        public List<TBMapBalances> TBMapBalances { get; set; } = new List<TBMapBalances>();

[...]
}

Controller

[Authorize]
[HttpPost]
public IActionResult TbMapViewEdit(TbMapViewModel tbMapViewModel)
{

    if (ModelState.IsValid)
    {
        foreach (var TbListId in tbMapViewModel.TBMapBalances)
        {
            var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();

            if (getCode != null)
            {
                getCode.UniqueAdp = TbListId.UniqueAdp;
            }

        }
        _context.SaveChanges();
    }

    return RedirectToAction("TbMapView");
}

Error that I was making here is that I was trying to replace the key with essentially the copy of itself (Find ID of 1 and set it to ID of 1) instead of picking up on the actual one field that I needed to edit which in my case was UniqueAdp.

Then came the new thing to me, which was Editor Template:

Editor Template

Create a folder called EditorTemplates in 'Shared' Folder under your 'Views' folder with the exact name of the model that you intend to edit. In my case the model was called TBMapBalances so I created a TBMapBalances.cshtml file inside the newly created folder, then pasted this (this was originally in my main view file):

@model ASPNET_Core_1_0.Models.TBMapBalances

<tr>
    <td>
        @Html.DisplayFor(Model => Model.TbMapId)
        @Html.HiddenFor(Model => Model.TbMapId)
    </td>
    <td>@Html.EditorFor(Model => Model.UniqueAdp, new { @class = "control-label_DI" })</td>
    <td>@Html.DisplayFor(Model => Model.AccountsCode)</td>
    <td>@Html.DisplayFor(Model => Model.Line)</td>
    <td>@Html.DisplayFor(Model => Model.MapResult)</td>
</tr>

By the way the new { @class = "control-label_DI" } is there to supposedly add class to each created input field. This doesn't seem to work in .net core and is left there just as a reminder to myself that I need to do this somehow.

Research:

Update multiple records at once in asp.net mvc

https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms

http://www.binaryintellect.net/articles/b1e0b153-47f4-4b29-8583-958aa22d9284.aspx

How to bind an Array in MVC Core

https://www.red-gate.com/simple-talk/dotnet/asp-net/model-binding-asp-net-core/

ASP.NET Core 1.0 POST IEnumerable<T> to controller

解决方案

This problem has 2 parts to it, the first is that there needed to be a way to edit collections of data. This can be solved with EditorTemplates, which involves creating a single editor model and then calling @Html.EditorFor(..) on the collection of items you wish to edit.

A minimal sample (Full Fx, not Core) is available on Github.

The second problem was with the way the entities were being updated, the property being changed was wrong and hence not saving (the PK was being updated to the PK) and the entity was being attached when it's already tracked.

foreach (var TbListId in tbMapViewModel.TBMapBalancesList)
{
    var getCode = _context.TBMapBalances.Where(p => p.TbMapId == TbListId.TbMapId).FirstOrDefault();
    if (getCode != null)
    {
        getCode.TbMapId = TbListId.TbMapId;
    }
}
try
{
    _context.Update(tbMapViewModel.TBMapBalances);
    await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
    throw;
}

It's important to remember what Entity Framework does for you when you retrieve a model from the database. It is automatically tracked by the context, and so it's already attached and ready to update, anything you change will be automatically tracked and subsequently saved.

The call to _context.Update(..) tries to attach the non-tracked models (from your POSTed data) to the context based on ID, but because you've already pulled that ID out (in your .Where(..).FirstOrDefault(..)) it's already tracked, and so blows up.

Also given that this is EFC 1.0 and you have no .Find(..) method, using .SingleOrDefault(..) is probably a better method to use on a primary key field.

Your rewritten code could be as so:

foreach (var postedModel in tbMapViewModel.TBMapBalancesList)
{
    var dbModel = _context.TBMapBalances.SingleOrDefault(p => p.TbMapId == postedModel.TbMapId);
    if (dbModel != null)
    {
        dbModel.UniqueAdp = postedModel.UniqueAdp;
    }
}
await _context.SaveChangesAsync();

For posterity though I wouldn't recommend it for security reasons, if you wanted to attach your whole posted model to the context (based on ID) and update it, you can do so with code similar to your original, removing the foreach loop:

_context.UpdateRange(tbMapViewModel.TBMapBalances);
await _context.SaveChangesAsync();

(I don't recommend it because everything that was posted will then be set in the database, from experience it's advisable to only set the fields you're expecting to update as per the first code set. It should, however, be quicker than the foreach loop given that you're not loading from the database and saving back in, only the latter)

这篇关于从同一表单同时保存多行 - dotnet core的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
C#/.NET最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆