我有一个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
数据。
值得注意的是,我要向其发布数据的表没有主键。不幸的是,但是它必须没有主键。 表现在具有主键(名为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);
以下是来自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
调用。
答案 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;
}
}
感谢所有发表评论和贡献的人。