使用Azure移动应用程序中的移动客户端更新行时出错

时间:2017-04-21 08:55:50

标签: c# xamarin.android azure-mobile-services

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

我们使用此blog post中的代码来解决版本冲突(即始终使用客户端的版本)。

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

我们已经查看了客户端中的异常,并且消息只是“发生了错误”。另请查看服务器分析,结果代码为500。

我有三个问题:

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

    打开服务器中的日志记录,将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;
        }
    }
    

2 个答案:

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