我在 DevExpress 网格中的特定行正确连接到 API 时遇到问题。
我认为问题出在 API 上,因为网格中的某些行我可以通过以太删除或编辑它们来操作。但是像上面提到的其他一些行不能被以太编辑或删除,但所有创建的新数据也可以被操纵。希望有人遇到过这个问题,我提供了一些代码和错误消息供大家查看。
网格的代码
@page "/FetchData"
@inject HttpClient Http
<h2>DevExpress Data Grid:</h2>
@if (customer == null)
{
<h1>thinking!?!?!?</h1>
}
else
{
<DxDataGrid Data=@customer
DataNavigationMode="@DataGridNavigationMode.VirtualScrolling"
RowRemoving=@((dataItem) => OnRowRemoving(dataItem))
RowUpdating=@((updatingDataItem, newValues) => OnRowUpdating(updatingDataItem, newValues))
RowInserting=@((newValues) => OnRowInserting(newValues))>
<DxDataGridCommandColumn Width="150px"></DxDataGridCommandColumn>
<DxDataGridColumn Field=@nameof(Customer.CustomerId) Caption="ID"></DxDataGridColumn>
<DxDataGridColumn field=@nameof(Customer.FirstName) Caption="FirstName"></DxDataGridColumn>
<DxDataGridColumn Field=@nameof(Customer.LastName) Caption="LastName"></DxDataGridColumn>
</DxDataGrid>
<br />
<br />
<DxDataGrid Data=@customer
PageSize=15
RowRemoving=@((dataItem) => OnRowRemoving(dataItem))
RowUpdating=@((updatingDataItem, newValues) => OnRowUpdating(updatingDataItem, newValues))
RowInserting=@((newValues) => OnRowInserting(newValues))>
<DxDataGridCommandColumn Width="150px"></DxDataGridCommandColumn>
<DxDataGridColumn Field=@nameof(Customer.CustomerId) Caption="ID"></DxDataGridColumn>
<DxDataGridColumn field=@nameof(Customer.FirstName) Caption="FirstName"></DxDataGridColumn>
<DxDataGridColumn Field=@nameof(Customer.LastName) Caption="LastName"></DxDataGridColumn>
</DxDataGrid>
}
@functions {
Customer[] customer;
Customer cust = new Customer();
private const string APIServer = "http://Notrealapi.com/api/customers/";
protected override async Task OnInitAsync()
{
customer = await Http.GetJsonAsync<Customer[]>("http://Notrealapi.com/api/customers/");
}
async void OnRowRemoving(Customer dataItem)
{
await Http.DeleteAsync("http://Notrealapi.com/api/customers/" + dataItem.CustomerId);
customer = await Http.GetJsonAsync<Customer[]>("http://Notrealapi.com/api/customers/");
StateHasChanged();
}
async void OnRowUpdating(Customer dataItem, Dictionary<string, object> newValue)
{
Dictionary<string, object> tempNewValues = new Dictionary<string, object>(newValue);
cust = await Http.GetJsonAsync<Customer>("http://Notrealapi.com/api/customers/" + dataItem.CustomerId);
foreach (var field in tempNewValues.Keys)
{
switch (field)
{
case "ID":
dataItem.CustomerId = (int)tempNewValues[field];
break;
case "FirstName":
dataItem.FirstName = (string)tempNewValues[field];
break;
case "LastName":
dataItem.LastName = (string)tempNewValues[field];
break;
}
}
//dataItem.FirstName = cust.FirstName;
//dataItem.LastName = cust.LastName;
await Http.SendJsonAsync(HttpMethod.Put, "http://Notrealapi.com/api/customers/" + dataItem.CustomerId, dataItem);
cust = new Customer();
customer = await Http.GetJsonAsync<Customer[]>("http://Notrealapi.com/api/customers/");
StateHasChanged();
}
async void OnRowInserting(Dictionary<string, object> newValue)
{
Dictionary<string, object> tempNewValues = new Dictionary<string, object>(newValue);
cust = new Customer();
await Http.SendJsonAsync(HttpMethod.Post, "http://Notrealapi.com/api/customers/", tempNewValues);
cust = new Customer();
customer = await Http.GetJsonAsync<Customer[]>("http://Notrealapi.com/api/customers/");
StateHasChanged();
}
public class Customer
{
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zipcode { get; set; }
}
}
来自 API Customer.cs 的一些代码
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace testsitegp.Models
{
public partial class Customer
{
public Customer()
{
Order = new HashSet<Order>();
}
public int CustomerId { get; set; }
[StringLength(50)]
public string FirstName { get; set; }
[StringLength(50)]
public string LastName { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zipcode { get; set; }
public ICollection<Order> Order { get; set; }
}
}
客户控制器.cs
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Net;
using testsitegp.Models;
using testsitegp.contracts;
using Microsoft.AspNetCore.Cors;
namespace HPlusSportsAPI.Controllers
{
[Produces("application/json")]
[Route("api/Customers")]
public class CustomersController : Controller
{
private readonly ICostomerRepository _customerRepository;
public CustomersController(ICostomerRepository costomerRepository)
{
_customerRepository = costomerRepository;
}
private async Task<bool> CustomerExists(int id)
{
return await _customerRepository.Exists(id);
}
//[EnableCors("AnotherPolicy")]
[HttpGet]
[Produces(typeof(DbSet<Customer>))]
public IActionResult GetCustomer()
{
var results = new ObjectResult(_customerRepository.GetAll())
{
StatusCode = (int)HttpStatusCode.OK
};
Request.HttpContext.Response.Headers.Add("X-Total-Count", _customerRepository.GetAll().Count().ToString());
return results;
}
//[EnableCors("AnotherPolicy")]
[HttpGet("{id}")]
[Produces(typeof(Customer))]
public async Task<IActionResult> GetCustomer([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var customer = await _customerRepository.Find(id);
if (customer == null)
{
return NotFound();
}
return Ok(customer);
}
//[EnableCors("AnotherPolicy")]
[HttpPut("{id}")]
[Produces(typeof(Customer))]
public async Task<IActionResult> PutCustomer([FromRoute] int id, [FromBody] Customer customer)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (id != customer.CustomerId)
{
return BadRequest();
}
try
{
await _customerRepository.Update(customer);
return Ok(customer);
}
catch (DbUpdateConcurrencyException)
{
if(!await CustomerExists(id))
{
return NotFound();
}
else
{
throw;
}
}
}
//[EnableCors("AnotherPolicy")]
[HttpPost]
[Produces(typeof(Customer))]
public async Task<IActionResult> PostCustomer([FromBody] Customer customer)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
await _customerRepository.Add(customer);
return CreatedAtAction("GetCustomer", new { id = customer.CustomerId }, customer);
}
//[EnableCors("AnotherPolicy")]
[HttpDelete("{id}")]
[Produces(typeof(Customer))]
public async Task<IActionResult> DeleteCustomer([FromRoute] int id)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (! await CustomerExists(id))
{
return NotFound();
}
await _customerRepository.Remove(id);
return Ok();
}
}
}
CustomerRepository.cs
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using testsitegp.contracts;
using testsitegp.Models;
namespace testsitegp.repository
{
public class CustomerRepository : ICostomerRepository
{
private H_Plus_SportsContext _context;
public CustomerRepository(H_Plus_SportsContext context)
{
_context = context;
}
public async Task<Customer> Add(Customer customer)
{
await _context.Customer.AddAsync(customer);
await _context.SaveChangesAsync();
return customer;
}
public async Task<bool> Exists(int id)
{
return await _context.Customer.AnyAsync(c => c.CustomerId == id);
}
public async Task<Customer> Find(int id)
{
return await _context.Customer.Include(customer => customer.Order).SingleOrDefaultAsync(a => a.CustomerId == id);
}
public IEnumerable<Customer> GetAll()
{
return _context.Customer;
}
public async Task<Customer> Remove(int id)
{
var customer = await _context.Customer.SingleAsync(a => a.CustomerId == id);
_context.Customer.Remove(customer);
await _context.SaveChangesAsync();
return customer;
}
public async Task<Customer> Update(Customer customer)
{
_context.Customer.Update(customer);
await _context.SaveChangesAsync();
return customer;
}
}
}
这是设置类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using testsitegp.Models;
using testsitegp.contracts;
using testsitegp.repository;
using H_Plus_Sports.Contracts;
using H_Plus_Sports.Repositories;
namespace testsitegp
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped<ICostomerRepository, CustomerRepository>();
services.AddScoped<IOrderItemRepository, OrderItemRepository>();
services.AddScoped<IOrderRepository, OrderRepository>();
services.AddScoped<IProductRepository, ProductRepository>();
services.AddScoped<ISalespersonRepository, SalespersonRepository>();
// services.AddCors(options =>
//{
//options.AddPolicy(MyAllowSpecificOrigins,
// builder =>
//{
//builder.WithOrigins("https://websitetestgp.azurewebsites.net",
//"https://websitetest22.azurewebsites.net",
//"https://websitetest23.azurewebsites.net",
//"http://goodtest.com",
// "http://localhost:57870")
//.AllowAnyHeader()
//.AllowAnyMethod();
//});
// options.AddPolicy("AnotherPolicy",
// builder =>
//{
//builder.WithOrigins("https://websitetestgp.azurewebsites.net",
//"https://websitetest22.azurewebsites.net",
//"https://websitetest23.azurewebsites.net",
//"http://goodtest.com",
//"http://localhost:57870")
//.AllowAnyHeader()
//.AllowAnyMethod();
// });
// });
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var connection = "Server=tcp:testsitegp.database.windows.net,1433;Initial Catalog=H_Plus_Sports;Persist Security Info=False;" +
"User ID=_____;Password=______;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";
services.AddDbContext<H_Plus_SportsContext>(options => options.UseSqlServer(connection));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
//app.UseCors(MyAllowSpecificOrigins);
app.UseHttpsRedirection();
app.UseMvc();
}
}
}
这是我尝试操作其中一个损坏的行时遇到的错误
blazor.server.js:15 [2019-08-01T12:48:22.608Z] 错误:System.IO.IOException:无法从传输连接读取数据:现有连接被远程主机强行关闭.. -- -> System.Net.Sockets.SocketException (10054):现有连接被远程主机强行关闭。--- 内部异常堆栈跟踪结束 --- 在 System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.GetResult(Int16 token) 在 System.Net.Sockets.Socket.AwaitableSocketAsyncEventArgs.ThrowException(SocketError error, CancellationToken cancelToken) 在 System. System.Net.Http.HttpConnection.ChunkedEncodingReadStream.CopyToAsyncCore(Stream destination, CancellationToken cancelToken) 处的 Net.Http.HttpConnection.FillAsync() System.Net.Http.HttpClient.GetStringAsyncCore(Task
1 getTask) at Microsoft.AspNetCore.Components.HttpClientJsonExtensions.GetJsonAsync[T](HttpClient httpClient, String requestUri) at Websitewithpopup.Pages.BigGrid.OnRowUpdating(Customer dataItem, Dictionary
2 newValue) 在 Q:\testsite\WebsitewithpopupDemoHP\Websitewithpopup\Pages\BigGrid.razor:line 123 at System.Threading.Tasks.Task.<>c.b__139_0(Object state) at Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext。 ExecuteSynchronously(TaskCompletionSource`1 完成,SendOrPostCallback d,对象状态)在 Microsoft.AspNetCore.Components.Rendering.RendererSynchronizationContext。<>c.<.cctor>b__23_0(对象状态)在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback回调,对象状态)---从先前引发异常的位置结束堆栈跟踪---在 Microsoft.AspNetCore.Components.Rendering 的 System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)。RendererSynchronizationContext.ExecuteBackground(WorkItem 项)[2019-08-01T12:48:22.610Z] 信息:连接断开。
图一:
图二:
图 3:
图四:
图 5: