为什么我的 ASP.NET 网络服务无法完成此 POST 请求?

Why is my ASP.NET web service unable to complete this POST request?

我在 Xamarin.Forms 中内置了一个数据输入应用程序,旨在将数据捕获为特定格式,然后 post 通过 ASP.NET 网络服务将其捕获到 SQL 服务器。我正在使用 RestSharp 来使这更容易。下面是我目前必须执行此操作的代码:

private async void Button_Clicked(object sender, EventArgs e)
        {
            try
            {
                string userResponse = await DisplayActionSheet("Are you sure?", "Yes", "No");
                if (userResponse == "Yes")
                {   
                    using (SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation))
                    {
                        List<DataToBeSent> d = conn.Query<DataToBeSent>("select * from DataToBeSent");
                        var dConvert = JsonConvert.SerializeObject(d, Formatting.Indented);
                        var client = new RestClient("url here");
                        client.Timeout = -1;
                        var request = new RestRequest(Method.POST);
                        request.RequestFormat = DataFormat.Json;
                        Token token = conn.Query<Token>("select * from Token").FirstOrDefault();
                        request.AddHeader("Authorization", "Bearer " + token.access_token);
                        request.AddParameter("application/json", dConvert, ParameterType.RequestBody);
                        IRestResponse response = client.Execute(request);
                        await DisplayAlert("", response.StatusCode.ToString() + response.Content.ToString(), "OK");
                    }
                    await Navigation.PopToRootAsync();
                }
            }
            catch (Exception ex)
            {
                await DisplayAlert("Error", $"Data failed to be inserted.\n{ex}", "OK");
            }
            
        }

当我尝试提交任何数据时,returns 会出现以下警告:

Token class 使用成功的 POST 请求检索 OAuth 令牌,供应用启动时用于 GET 数据。

我还使用 Postman 进行了测试,示例请求如下:

这导致我的网络服务出现以下错误:

值得注意的是,我正在posting数据的table没有主键。它是不幸的是,它没有一个要求。 Table 现在有一个主键(名为 UniqueID。我还注意到 List<DataToBeSent>,在序列化时,returns 带有转义字符。为什么会出现这些错误?有谁知道如何修复它们?

更新 1: 根据要求; JSON 传递如下。

"[\n  {\n    \"column1\": \"data1\",\n    \"column2\": \"data2\"\n  }\n]"

数据库模型代码如下。

<!--Errors Found During Generation:
warning 6002: The table/view 'databaseName.dbo.DataToBeSent' does not have a primary key defined. The key has been inferred and the definition was created as a read-only table/view.-->
        <EntityType Name="DataToBeSent">
          <Key>
            <PropertyRef Name="column1" />
            <PropertyRef Name="column2" />
          </Key>
          <Property Name="column1" Type="nvarchar" MaxLength="50" Nullable="false" />
          <Property Name="column2" Type="nvarchar" MaxLength="50" Nullable="false" />
        </EntityType>
<EntitySet Name="DataToBeSent" EntityType="Self.DataToBeSent" store:Type="Tables" store:Schema="dbo">
            <DefiningQuery>
              SELECT
              [DataToBeSent].[column1] AS [column1],
              [DataToBeSent].[column2] AS [column2]
            </DefiningQuery>
          </EntitySet>

更新 2: 我尝试在 Xamarin 后端更新我的 POST 请求代码。这是我目前拥有的。

List<DataToBeSent> DATA = conn.Query<DataToBeSent>("select * from DataToBeSent");
                        var data = JsonConvert.SerializeObject(DATA, Formatting.None);
                        Token token = conn.Query<Token>("select * from Token").FirstOrDefault();
                        var client = new RestClient("url");
                        client.Timeout = -1;
                        var request = new RestRequest(Method.POST);
                        request.AddHeader("Content-Type", "application/json");
                        request.AddHeader("Authorization", "Bearer " + token.access_token);
                        request.AddJsonBody(data);
                        IRestResponse response = client.Execute(request);
                        await DisplayAlert("Response", response.StatusCode + response.Content, "OK");

我不知道为什么会出现序列化错误 - 当将 Visual Studio 中的结果作为 JSON 对象查看时,转义字符不存在。这向我表明序列化正在正确发生,但我仍然收到相同的错误消息 (BadRequest)。我正在尝试提交 List<> 个对象,所以我想知道 JsonConvert.SerializeObject 是否是要使用的正确方法。

更新 3: 我试过按照下面@Mat J 的建议发布单个对象。除了将 List<> 对象更改为具有 .FirstOrDefault() 的单个对象外,代码与更新 2 相同。见下文。

DataToBeSent DATA = conn.Query<DataToBeSent>("select * from DataToBeSent").FirstOrDefault();
var data = JsonConvert.SerializeObject(DATA, Formatting.None);

应用中显示的响应。

下面是来自 Web 服务的我的控制器代码。我将其自动生成为 Web API 2 Controller, using Entity Framework,并在其上方添加了方括号以使用我的 OAuth 安全方法。

[Authorize(Roles = "Admin, User")]
[HttpPost]
[Route("api/v/DataToBeSent")]
[ResponseType(typeof(DataToBeSent))]
public IHttpActionResult PostDataToBeSent(DataToBeSent dataToBeSent)
 {
      if (!ModelState.IsValid)
      {
          return BadRequest(ModelState);
      }

      db.DataToBeSent.Add(dataToBeSent);

      try
      {
          db.SaveChanges();
      }
      catch (DbUpdateException)
      {
          if (DataToBeSentExists(dataToBeSent.UniqueID))
          {
              return Conflict();
          }
          else
          {
              throw;
          }
      }

      return CreatedAtRoute("DefaultApi", new { id = dataToBeSent.UniqueID }, dataToBeSent);
  }

DataToBeSenttable现在有一个主键,名称如上UniqueID

我确实希望能够提交整个 List<> 个对象,而不是像 for 循环那样对列表中的每个单独对象进行单独的 POST 调用。

我建议阅读 RestSharp 文档。我们试图让它更易于使用,我不确定您为什么不利用它。

让我们看一下这段代码:

var data = JsonConvert.SerializeObject(DATA, Formatting.None);
Token token = conn.Query<Token>("select * from Token").FirstOrDefault();
var client = new RestClient("url");
client.Timeout = -1;
var request = new RestRequest(Method.POST);
request.AddHeader("Content-Type", "application/json");
request.AddHeader("Authorization", "Bearer " + token.access_token);
request.AddJsonBody(data);
IRestResponse response = client.Execute(request);
  • 首先,AddJsonBody 接受一个 object,它会为您序列化。您正在发送一个 string,其中已经包含一个序列化的 object,所以这永远不会起作用。

  • 通过调用 AddJsonObject,您已经将内容类型设置为 application/json,无需再次设置。

  • 无需使用手动设置的承载 header,您只需使用为身份验证目的而构建的 JwtAuthenticator,无需操作 headers 对于每个请求。

  • 客户端建议单例,不要每个请求都re-created

我可以建议使用以下内容:

public void WhateverIsCalledOnce()
{
    var roken = conn.Query<Token>("select * from Token").First();
    _client = new RestClient("url").UseNewtonsoftJson();
    _client.Authenticator = new JwtAuthenticator(token.access_token);
}

public async Task CallRemoteServer()
{
    var data = await _connection.GetDataFromDb("query");
    var request = new RestRequest("/api/v/DataToBeSent")
        .AddJsonBody(data);
    var result = await _client.PostAsync<DataToBeReturned>(request);
}

UseNewtonsoftJson 扩展方法在 NuGet 的 RestSharp.Serializers.NewtonsoftJson 包中可用。

我解决了这个问题,将其张贴在这里以供日后遇到问题的任何人使用。正如@Mat J 在问题的评论中指出的那样,当控制器仅设置为接收单个对象时,我试图发送一个数组。第 1 步是更新该代码以允许控制器接收 List<> 而不是单个对象。第 2 步意识到我将 POST 控制器的 [Route] 属性设置为与 table 的 GET 控制器相同。可以在问题的 Update 2 中找到有效的 Xamarin 端代码,尽管 @Alexey Zimarev 的回答可能会更有效率。可以在下面找到更新的 Web 服务控制器代码。

[Authorize(Roles = "Admin, User")]
[HttpPost]
[Route("api/postall/datatobesent")]
public IHttpActionResult PostAllDataToBeSent([FromBody] List<DataToBeSent> dataToBeSent)
{
    if (!ModelState.IsValid)
    {
        return BadRequest(ModelState);
    }

    foreach(var data in dataToBeSent)
    {
        db.DataToBeSent.Add(data);
    }

    try
    {
        db.SaveChanges();

        return Ok();
    }
    catch (Exception)
    {
        throw;
    }

}

感谢所有评论和贡献的人。