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

时间:2020-01-02 05:50:36

标签: c# asp.net xamarin json.net restsharp

我有一个Xamarin.Forms内置的数据输入应用程序,旨在将数据捕获为特定格式,然后通过ASP.NET Web服务将其发布到SQL Server中。我正在使用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");
            }

        }

当我尝试提交任何数据时,它将返回以下警报:

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

我还对Postman进行了测试,以下样品要求: enter image description here enter image description here

这会在我的Web服务中导致以下错误: enter image description here

值得注意的是,我要向其发布数据的表没有主键。不幸的是,但是它必须没有主键。 表现在具有主键(名为UniqueID。我还注意到List<DataToBeSent>在序列化时返回带有转义符。为什么会发生这些错误?有人知道如何解决吗?

更新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()的单个对象外,代码与Update 2相同。见下文。

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

应用程序中显示的响应。 enter image description here

以下是来自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);
  }

DataToBeSent现在有一个主键,如上所述,名为UniqueID

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

2 个答案:

答案 0 :(得分:2)

我建议阅读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,它已经包含一个序列化的对象,因此它将永远无法工作。

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

  • 您无需使用手动设置的承载标头,而只需使用为认证目的而构建的JwtAuthenticator,而无需为每个请求操纵标头。

  • 建议客户端为单例,不要为每个请求重新创建。

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

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);
}

在NuGet的UseNewtonsoftJson包中提供了RestSharp.Serializers.NewtonsoftJson扩展方法。

答案 1 :(得分:0)

我解决了问题,将其发布在这里,供以后遇到问题的任何人使用。正如@Mat J在问题注释中指出的那样,当控制器仅设置为接收单个对象时,我试图发送一个数组。步骤1是更新该代码,以允许控制器接收List<>而不是单个对象。第2步意识到,我将POST控制器的[Route]属性设置为与表的GET控制器相同。在问题的更新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;
    }

}

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