使用Azure Mobile应用中的移动客户端更新一行的错误



需要在我们创建的移动应用中添加编辑功能。

我们使用此博客文章中的代码解决版本冲突(即始终采用客户端的版本(。

但是,编辑功能有时会起作用,并且在大多数情况下也会导致错误。一次,服务器中的数据已更新,但移动客户端仍将保留一个即将来临的操作。

我们已经查看了客户端的例外,并且消息只是"发生错误"。还查看了服务器分析,结果代码为500。

我有三个问题:

  1. 为什么更新操作导致错误?
  2. 在客户端或服务器中调试错误还有其他方法吗?错误500非常通用,"错误发生"并不是很有帮助。
  3. 即使服务器中的销售模型与相应的SQL数据库之间存在差异,客户端是否可以创建销售并将其上传到服务器?

update

打开在服务器中的登录,将Patchsale更改为ASYNC,以便我们可以等待UpdateAsync(ID,PATCH(,然后放置一个try-catch,在此调用updateasync。

这是捕获区域中登录的内容:

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

Adrianhall怀疑.NET服务器中的销售模型与其相应的SQL Server之间的销售模型之间可能存在差异。我已经比较了这两个,并且似乎找不到任何区别(我认为在扩展EntityData时,包括ID,版本,创建,更新和删除(。此外,如果.NET服务器和SQL Server中的模型之间存在差异,那么我们如何创建销售并将其上传到服务器?

另外,在下面的服务器和SQL Server中的列中发布了销售模型。

这是参考的代码:

服务器:控制器中的更新方法

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"];
        }
    }

服务器:销售模型

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

SQL Server:销售列(Dunno除了列外还要显示什么(

Id(PK, nvarchar(128), not null)
PromoterId(nvarchar(max), null)
DateSold(datetime, not null)
QuantitySold(int, not null)
PriceSold(float, not null)
CorporateSale(bit, not null)
Remarks(nvarchar(255), null)
ProductId(FK, nvarchar(128), null)
StoreId(FK, nvarchar(128), null)
PaymentMethodId(FK, nvarchar(128), null)
SaleTransactionId(nvarchar(max), null)
Version(timestamp, not null)
CreatedAt(datetimeoffset(7), not null)
UpdatedAt(datetimeoffset(7), null)
Deleted(bit, not null)

代码500是"无效的服务器响应",通常是"请求导致服务器代码崩溃"。要诊断这一点,您需要进入Azure门户并打开诊断记录,然后查看日志流。如果可以,请通过远程调试器从Visual Studio连接(查看http://aka.ms/zumobook-第8章,以获取一些有用的提示(。

通过查看代码,我看到了一些问题 - 例如,使用dateTime而不是dateTimeOffset?。但是,这些都不应引起崩溃,因此我怀疑在模型定义方面,ASP.NET服务器和SQL Server之间的不匹配。但是,您还没有提供足够的信息来确定地说。

在我的情况下,使用以下fk的关系在下面的下面使用,如下所示。在我的客户端对象和服务器对象之间,唯一的区别是标记属性。如果我从服务器对象中删除它,则更新正常。我不知道阿德里安·霍尔(Adrian Hall(如何在他的github样本上给出这个例子,并且在这里起作用。

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

相关内容

最新更新