需要在我们创建的移动应用中添加编辑功能。
我们使用此blog post中的代码来解决版本冲突(即始终使用客户端的版本)。
但是,编辑功能有时会起作用,并且大多数情况下也会导致错误。有一次服务器中的数据已更新,但即将进行的操作仍留在移动客户端中。
我们已经查看了客户端中的异常,并且消息只是“发生了错误”。另请查看服务器分析,结果代码为500。
我有三个问题:
更新
打开服务器中的日志记录,将PatchSale更改为异步,以便我们可以等待UpdateAsync(id,patch),并将try-catch放在等待调用UpdateAsync的位置。
以下是捕获区域中记录的内容:
json_normalize(data['data']['game']['plays']['play'])
AdrianHall怀疑.NET服务器中的销售模型与其对应的SQL服务器之间可能存在差异。我已经比较了两者,似乎没有发现任何差异(我假设在扩展EntityData时包含了Id,Version,CreatedAt,UpdatedAt和Deleted)。此外,如果.NET服务器和SQL服务器中的模型之间存在差异,我们可以创建销售并将其上传到服务器吗?
此外,在下面的服务器中发布了销售模型,在SQL服务器中发布了这些列。
以下是供参考的代码:
服务器:控制器中的更新方法
CATCH:
Helplink
Message
Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details.
StackTrace
at Microsoft.Azure.Mobile.Server.Tables.EntityUtils.<SubmitChangesAsync>d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Mobile.Server.EntityDomainManager`1.<UpdateAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Mobile.Server.EntityDomainManager`1.<UpdateAsync>d__3.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.Azure.Mobile.Server.TableController`1.<PatchAsync>d__12.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at SynthesisServer.Controllers.SaleController.<PatchSale>d__3.MoveNext()
Source
Microsoft.Azure.Mobile.Server.Entity
移动客户端:正在更新销售
public Task<Sale> PatchSale(string id, Delta<Sale> patch)
{
System.Diagnostics.Trace.TraceInformation("INSIDE PATCH SALE!!!");
return UpdateAsync(id, patch);
}
移动客户端:同步销售
public async Task<Sale> UpdateSaleAsync(Sale sale)
{
await saleTable.UpdateAsync(sale);
return sale;
}
移动客户端:销售模式
public async Task<bool> SyncSalesAsync()
{
bool wasPushed = true;
try
{
// Sync data with cloud
await MobileService.SyncContext.PushAsync();
await saleTable.PullAsync("allSales", saleTable.CreateQuery());
}
catch (MobileServicePreconditionFailedException<Sale> conflict)
{
Console.WriteLine($"taskTitle_Changed - Conflict Resolution for item ${conflict.Item.Id}");
}
catch (MobileServicePushFailedException exc)
{
Console.WriteLine("Sync Sales MSPFE Exception: ");
Console.WriteLine("/////////////////////");
Console.WriteLine("Message:");
Console.WriteLine(exc.Message);
Console.WriteLine("HelpLink:");
Console.WriteLine(exc.HelpLink);
Console.WriteLine("Source:");
Console.WriteLine(exc.Source);
Console.WriteLine("Stack Trace:");
Console.WriteLine(exc.StackTrace);
Console.WriteLine("/////////////////////");
if (exc.PushResult != null)
{
var c = 1;
foreach (var i in exc.PushResult.Errors)
{
Console.WriteLine("Inside push Details: " + c);
Console.WriteLine("Handled: ");
Console.WriteLine(i.Handled);
Console.WriteLine("Item");
Console.WriteLine(i.Item);
Console.WriteLine("O Kind");
Console.WriteLine(i.OperationKind);
Console.WriteLine("Status");
Console.WriteLine(i.Status);
Console.WriteLine("Table Name");
Console.WriteLine(i.TableName);
Console.WriteLine("Raw Result");
Console.WriteLine(i.RawResult);
Console.WriteLine("Result");
Console.WriteLine(i.Result);
Console.WriteLine("Item");
Console.WriteLine(i.Item);
c++;
Console.WriteLine("Cast Result to Sale");
var serverItem = i.Result.ToObject<Sale>();
Console.WriteLine("Cast Item to Sale");
var localItem = i.Item.ToObject<Sale>();
if (serverItem.Equals(localItem))
{
Console.WriteLine("server item equals");
// Items are the same, so ignore the conflict
await i.CancelAndDiscardItemAsync();
}
else
{
Console.WriteLine("else");
Console.WriteLine("localitem version: " + localItem.Version);
Console.WriteLine("serveritem version: " + serverItem.Version);
// Always take the client
localItem.Version = serverItem.Version ?? localItem.Version;
var item = JObject.FromObject(localItem);
Console.WriteLine("item from jobject");
Console.WriteLine(item);
try
{
await i.UpdateOperationAsync(item);
}
catch (Exception e)
{
Console.WriteLine("Else Message Error");
Console.WriteLine(e.Message);
Console.WriteLine("Else Stack Trace");
Console.WriteLine(e.StackTrace);
}
}
}
}
return false;
}
catch (MobileServiceInvalidOperationException msioe)
{
Console.WriteLine("Sync Sales MSIOE Exception: ");
Console.WriteLine("/////////////////////");
Console.WriteLine(msioe.Message);
Console.WriteLine("----");
Console.WriteLine(msioe.HelpLink);
Console.WriteLine("----");
Console.WriteLine(msioe.Source);
Console.WriteLine("----");
Console.WriteLine(msioe.StackTrace);
return false;
}
catch (Exception e)
{
Console.WriteLine("Sync Sales General Exception: ");
Console.WriteLine("/////////////////////");
Console.WriteLine(e.Message);
Console.WriteLine("----");
Console.WriteLine(e.HelpLink);
Console.WriteLine("----");
Console.WriteLine(e.Source);
Console.WriteLine("----");
Console.WriteLine(e.StackTrace);
return false;
}
return wasPushed;
}
服务器:销售模式
public class Sale
{
[JsonProperty(PropertyName = "id")]
public string Id { get; set; }
[JsonProperty(PropertyName = "productId")]
public string ProductId { get; set; }
[JsonProperty(PropertyName = "promoterId")]
public string PromoterId { get; set; }
[JsonProperty(PropertyName = "storeId")]
public string StoreId { get; set; }
[JsonProperty(PropertyName = "paymentMethodId")]
public string PaymentMethodId { get; set; }
[JsonProperty(PropertyName = "corporateSale")]
public bool CorporateSale { get; set; }
[JsonProperty(PropertyName = "dateSold")]
public DateTime? DateSold { get; set; }
[JsonProperty(PropertyName = "priceSold")]
public double PriceSold { get; set; }
[JsonProperty(PropertyName = "quantitySold")]
public int QuantitySold { get; set; }
[JsonProperty(PropertyName = "remarks")]
public string Remarks { get; set; }
[JsonProperty(PropertyName = "deleted")]
public bool Deleted { get; set; }
[JsonProperty(PropertyName = "createdAt")]
public DateTime CreatedAt { get; set; }
[JsonProperty(PropertyName = "updatedAt")]
public DateTime UpdatedAt { get; set; }
[JsonProperty(PropertyName = "version")]
public string Version { get; set; }
[JsonProperty(PropertyName = "saleTransactionId")]
public string SaleTransactionId { get; set; }
[JsonIgnore]
public virtual Dictionary<string, string> Data
{
get
{
var data = new Dictionary<string, string>
{
["Id"] = Id,
["ProductId"] = ProductId,
["PromoterId"] = PromoterId,
["StoreId"] = StoreId,
["PaymentMethodId"] = StoreId,
["CorporateSale"] = CorporateSale.ToString(),
["DateSold"] = "",
["PriceSold"] = PriceSold.ToString(),
["QuantitySold"] = QuantitySold.ToString(),
["Remarks"] = Remarks,
["SaleTransactionId"] = SaleTransactionId,
["Deleted"] = Deleted.ToString(),
["CreatedAt"] = CreatedAt.ToString(),
["UpdatedAt"] = UpdatedAt.ToString(),
["Version"] = Version
};
if (DateSold != null) data["DateSold"] = ((DateTime)DateSold).ToString();
return data;
}
}
[JsonIgnore]
public bool IsNew
{
get
{
return string.IsNullOrEmpty(PromoterId) || UpdatedAt == null || CreatedAt == null || string.IsNullOrEmpty(Version);
}
}
public virtual Product Product { get; set;}
public virtual Store Store { get; set; }
public virtual PaymentMethod PaymentMethod { get; set; }
// Default constructor
public Sale() {}
public Sale(Dictionary<String, String> data)
{
DateSold = DateTime.Parse(data["DateSold"]);
CorporateSale = bool.Parse(data["CorporateSale"]);
ProductId = data["ProductId"];
PriceSold = Double.Parse(data["PriceSold"]);
QuantitySold = int.Parse(data["QuantitySold"]);
StoreId = data["StoreId"];
PaymentMethodId = data["PaymentMethodId"];
Remarks = data["Remarks"];
SaleTransactionId = Guid.NewGuid().ToString();
}
public virtual string TransactionId()
{
string value = "Not Synced";
if (!string.IsNullOrEmpty(SaleTransactionId)) value = SaleTransactionId;
return value;
}
public override string ToString()
{
return "I'm a Sale: DateSold " + DateSold + " ProductID " + ProductId + " StoreID " + StoreId + " Corporate Sale " + CorporateSale;
}
public virtual string FormattedCorporateSale()
{
string result = "No";
if (CorporateSale) result = "Yes";
return result;
}
public virtual string FormattedDateSold ()
{
if (DateSold == null) return "DateSold not recorded";
// Convert DateSold from DateTime? to DateTime cos DateTime? doesn't have the ToString with overload for
// formatting
DateTime date = (DateTime)DateSold;
return date.ToString("dd MMM yyyy") + " " + date.ToString("ddd");
}
public virtual string FormattedPriceSold()
{
return string.Format("{0:n}", PriceSold);
}
public virtual string FormattedPriceSoldForIndex()
{
return string.Format("{0:n}", PriceSold);
}
public virtual string FormattedQuantitySold()
{
string formattedQuantitySold = QuantitySold.ToString () + " unit";
if (QuantitySold > 1) formattedQuantitySold = formattedQuantitySold + "s";
return formattedQuantitySold;
}
public virtual string FormattedQuantitySoldForIndex()
{
string formattedQuantitySold = QuantitySold.ToString() + " unit";
if (QuantitySold > 1) formattedQuantitySold = formattedQuantitySold + "s";
return formattedQuantitySold;
}
public virtual string FormattedRemarks()
{
string result = "none";
if (!(String.IsNullOrEmpty(Remarks))) result = Remarks;
return result;
}
public virtual string FormattedProductSku()
{
return "Im a regular sale";
}
public virtual string FormattedProductSkuForIndex()
{
return "Im a regular sale";
}
public virtual string FormattedProductPartNumber()
{
return "I'm a regualr sale";
}
public virtual string FormattedStoreName()
{
return "I'm a regular sale";
}
public virtual string FormattedPaymentMethodName()
{
return "I'm a regular sale";
}
public virtual bool IsNoSale()
{
throw new NotImplementedException();
}
// Updates only those properties that are on the form
public virtual void Update(Dictionary<string, string> data)
{
DateSold = DateTime.Parse(data["DateSold"]);
CorporateSale = bool.Parse(data["CorporateSale"]);
ProductId = data["ProductId"];
PriceSold = Double.Parse(data["PriceSold"]);
QuantitySold = int.Parse(data["QuantitySold"]);
StoreId = data["StoreId"];
PaymentMethodId = data["PaymentMethodId"];
Remarks = data["Remarks"];
}
}
SQL Server:销售栏(不知道除了列之外还有什么其他内容)
[Table("sales.Sales")]
public class Sale : EntityData
{
public string PromoterId { get; set; }
public DateTime DateSold { get; set; }
[Range(1, Int32.MaxValue, ErrorMessage = "Quantity Sold must be > 0")]
public int QuantitySold { get; set; }
[Range (1, Double.MaxValue, ErrorMessage = "Price Sold must be > 0")]
public double PriceSold { get; set; }
public bool CorporateSale { get; set; }
[StringLength(255)]
public string Remarks { get; set; }
public string ProductId { get; set; }
public string StoreId { get; set; }
public string PaymentMethodId { get; set; }
public string SaleTransactionId { get; set; }
public virtual Product Product { get; set; }
public virtual Store Store { get; set; }
public virtual PaymentMethod PaymentMethod { get; set; }
[NotMapped, JsonIgnore]
public virtual Promoter Promoter { get; set; }
[NotMapped]
public string DateUploaded
{
get
{
string date = "";
if (CreatedAt != null)
{
var transformed = CreatedAt.GetValueOrDefault();
date = transformed.ToString("yyyy-MMM-dd");
}
return date;
}
set
{
}
}
[NotMapped]
public string DateSold_String
{
get
{
string date = "";
if (DateSold != null)
{
var transformed = DateSold;
date = transformed.ToString("yyyy-MMM-dd");
}
return date;
}
set
{
}
}
public override string ToString()
{
var message = "I'm a Sale! DateSold: ";
if (DateSold != null) message = message + DateSold;
else message = message + "x";
if (String.IsNullOrEmpty(ProductId)) message = message + " ProductID: " + "x";
else message = message + " ProductID: " + ProductId;
if (String.IsNullOrEmpty(StoreId)) message = message + " StoreID: " + "x";
else message = message + " StoreID: " + StoreId;
if (String.IsNullOrEmpty(PromoterId)) message = message + " PromoterID: " + "x";
else message = message + " PromoterID: " + PromoterId;
return message;
}
}
答案 0 :(得分:1)
代码500是&#34;无效的服务器响应&#34;,这通常是#34;该请求导致服务器代码崩溃&#34;。要诊断这一点,您需要进入Azure门户并打开诊断日志记录,然后查看日志流。如果可以的话,可以通过远程调试器从Visual Studio连接(请查看http://aka.ms/zumobook - 第8章,了解一些有用的提示)。
从查看代码,我看到一些问题 - 例如,使用DateTime而不是DateTimeOffset?但是,这些都不会导致崩溃,所以我怀疑ASP.NET服务器和SQL服务器在模型定义方面不匹配。但是,您没有提供足够的信息来明确说出这一点。
答案 1 :(得分:0)
在我的情况下,似乎在使用FK关系的服务器端使用如下所示,如下所示不起作用。我的客户端对象和服务器对象之间只有区别是Tag属性。如果我从服务器对象中删除它,更新工作正常。我不知道Adrian Hall如何在他的github示例中给出这个例子,它可以在here上工作。
public class TodoItem : EntityData
{
public string UserId { get; set; }
public string Text { get; set; }
public bool Complete { get; set; }
public string TagId { get; set; }
[ForeignKey("TagId")]
public Tag Tag { get; set; }
}