Shopify 与 Newtonsoft (JSON.NET) 问题
Shopify with Newtonsoft (JSON.NET) issue
我遇到了一个问题,我无法解决我正在构建的 WCF 服务,我在其中收到错误:
"Type 'Newtonsoft.Json.Linq.JToken' is a recursive collection data
contract which is not supported. Consider modifying the definition of
collection 'Newtonsoft.Json.Linq.JToken' to remove references to
itself"
我知道主要的解决方案是取消选中在我的服务引用中重用该 Newtonsoft 引用的选项,但我没有列出要取消选中的选项。我确认 json.net 在我的服务中被正确引用。
奇怪的是,当我离开这个电话时,我确认我得到了结果
public List<T> CallService<T>(string query)
{
var data = new List<T>();
var fullyEscapedUri = _ShopUri.AbsoluteUri.EndsWith("/") ? _ShopUri : new Uri(_ShopUri + "/");
var uri = new Uri(fullyEscapedUri, typeof(T).Name);
if (!string.IsNullOrWhiteSpace(query))
{
var uriBuilder = new UriBuilder(uri) { Query = query };
uri = uriBuilder.Uri;
}
string url = String.Format("{0}{1}", _ShopUri, query);
var request = WebRequest.Create(url);
request.Method = "GET";
request.ContentType = "application/json";
string base64EncodedUsernameAndPassword = string.Format("{0}:{1}", _Username, _Password);
string authHeader = string.Format("Basic {0}", Convert.ToBase64String(Encoding.UTF8.GetBytes(base64EncodedUsernameAndPassword)));
request.Headers["Authorization"] = authHeader;
using (var response = request.GetResponse())
{
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
string json = reader.ReadToEnd();
var jsonObj = JsonConvert.DeserializeObject(json, new JsonSerializerSettings()
{
Formatting = Formatting.Indented,
TypeNameHandling = TypeNameHandling.Auto,
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}) as JObject;
var jsonArray = jsonObj[_ObjectType] as JArray;
foreach (var jsonEmp in jsonArray)
{
var obj = JsonConvert.DeserializeObject<T>(jsonEmp.ToString());
data.Add(obj);
}
}
}
}
return data;
}
此方法是我编写的自定义 class 中的方法,因此有几个变量看起来好像没有定义 - 我会收到一大堆代码。但如您所见,我需要此方法来动态调用任何 Shopify 端点。在这个例子中,第一次进入的_ObjectType变量是"orders."
这是我的订单class定义:
public class Orders : ShopifyObject
{
[JsonProperty(PropertyName = "orders")]
public List<Order> orders;
}
public class Order : ShopifyObject
{
/// <summary>
/// The mailing address associated with the payment method. This address is an optional field that will not be available on orders that do not require one.
/// </summary>
[JsonProperty("billing_address")]
public Address BillingAddress { get; set; }
/// <summary>
/// The IP address of the browser used by the customer when placing the order.
/// </summary>
[JsonProperty("browser_ip")]
public string BrowserIp { get; set; }
/// <summary>
/// Indicates whether or not the person who placed the order would like to receive email updates from the shop.
/// This is set when checking the "I want to receive occasional emails about new products, promotions and other news" checkbox during checkout.
/// </summary>
[JsonProperty("buyer_accepts_marketing")]
public bool? BuyerAcceptsMarketing { get; set; }
/// <summary>
/// The reason why the order was cancelled. If the order was not cancelled, this value is null. Known values are "customer", "fraud", "inventory" and "other".
/// </summary>
[JsonProperty("cancel_reason")]
public string CancelReason { get; set; }
/// <summary>
/// The date and time when the order was cancelled. If the order was not cancelled, this value is null.
/// </summary>
[JsonProperty("cancelled_at")]
public DateTimeOffset? CancelledAt { get; set; }
/// <summary>
/// Unique identifier for a particular cart that is attached to a particular order.
/// </summary>
[JsonProperty("cart_token")]
public string CartToken { get; set; }
/// <summary>
/// A <see cref="ShopifySharp.ClientDetails"/> object containing information about the client.
/// </summary>
[JsonProperty("client_details")]
public ClientDetails ClientDetails { get; set; }
/// <summary>
/// The date and time when the order was closed. If the order was not clsoed, this value is null.
/// </summary>
[JsonProperty("closed_at")]
public DateTimeOffset? ClosedAt { get; set; }
/// <summary>
/// The customer's contact email address.
/// </summary>
[JsonProperty("contact_email"), Obsolete("ContactEmail is not documented by Shopify and will be removed in a future release.")]
public string ContactEmail { get; set; }
/// <summary>
/// The date and time when the order was created in Shopify.
/// </summary>
[JsonProperty("created_at")]
public DateTimeOffset? CreatedAt { get; set; }
/// <summary>
/// The three letter code (ISO 4217) for the currency used for the payment.
/// </summary>
[JsonProperty("currency")]
public string Currency { get; set; }
/// <summary>
/// A <see cref="ShopifySharp.Customer"/> object containing information about the customer. This value may be null if the order was created through Shopify POS.
/// </summary>
[JsonProperty("customer")]
public Customer Customer { get; set; }
/// <summary>
/// Applicable discount codes that can be applied to the order.
/// </summary>
[JsonProperty("discount_codes")]
public IEnumerable<DiscountCode> DiscountCodes { get; set; }
/// <summary>
/// The order's email address. Note: On and after 2015-11-03, you should be using <see cref="ContactEmail"/> to refer to the customer's email address.
/// Between 2015-11-03 and 2015-12-03, updates to an order's email will also update the customer's email. This is temporary so apps can be migrated over to
/// doing customer updates rather than order updates to change the contact email. After 2015-12-03, updating updating an order's email will no longer update
/// the customer's email and apps will have to use the customer update endpoint to do so.
/// </summary>
[JsonProperty("email")]
public string Email { get; set; }
/// <summary>
/// The financial status of an order. Known values are "authorized", "paid", "pending", "partially_paid", "partially_refunded", "refunded" and "voided".
/// </summary>
[JsonProperty("financial_status")]
public string FinancialStatus { get; set; }
/// <summary>
/// An array of <see cref="Fulfillment"/> objects for this order.
/// </summary>
[JsonProperty("fulfillments")]
public IEnumerable<Fulfillment> Fulfillments { get; set; }
/// <summary>
/// The fulfillment status for this order. Known values are 'fulfilled', 'null' and 'partial'.
/// </summary>
[JsonProperty("fulfillment_status")]
public string FulfillmentStatus { get; set; }
/// <summary>
/// Tags are additional short descriptors, commonly used for filtering and searching, formatted as a string of comma-separated values.
/// </summary>
[JsonProperty("tags")]
public string Tags { get; set; }
/// <summary>
/// The URL for the page where the buyer landed when entering the shop.
/// </summary>
[JsonProperty("landing_site")]
public string LandingSite { get; set; }
/// <summary>
/// An array of <see cref="LineItem"/> objects, each one containing information about an item in the order.
/// </summary>
[JsonProperty("line_items")]
public IEnumerable<LineItem> LineItems { get; set; }
/// <summary>
/// The unique numeric identifier for the physical location at which the order was processed. Only present on orders processed at point of sale.
/// </summary>
[JsonProperty("location_id")]
public long? LocationId { get; set; }
/// <summary>
/// The customer's order name as represented by a number, e.g. '#1001'.
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// The text of an optional note that a shop owner can attach to the order.
/// </summary>
[JsonProperty("note")]
public string Note { get; set; }
/// <summary>
/// Extra information that is added to the order.
/// </summary>
[JsonProperty("note_attributes")]
public IEnumerable<NoteAttribute> NoteAttributes { get; set; }
/// <summary>
/// Numerical identifier unique to the shop. A number is sequential and starts at 1000.
/// </summary>
[JsonProperty("number")]
public int? Number { get; set; }
/// <summary>
/// A unique numeric identifier for the order. This one is used by the shop owner and customer.
/// This is different from the id property, which is also a unique numeric identifier for the order, but used for API purposes.
/// </summary>
[JsonProperty("order_number")]
public int? OrderNumber { get; set; }
/// <summary>
/// The URL pointing to the order status web page. The URL will be null unless the order was created from a checkout.
/// </summary>
[JsonProperty("order_status_url")]
public string OrderStatusUrl { get; set; }
/// <summary>
/// Payment details for this order. May be null if the order was created via API without payment details.
/// </summary>
[JsonProperty("payment_details"), Obsolete("PaymentDetails has been deprecated and will be removed in a future release. This data is now available via the Transaction API.")]
public PaymentDetails PaymentDetails { get; set; }
/// <summary>
/// The list of all payment gateways used for the order.
/// </summary>
[JsonProperty("payment_gateway_names")]
public IEnumerable<string> PaymentGatewayNames { get; set; }
/// <summary>
/// The date that the order was processed at.
/// </summary>
[JsonProperty("processed_at")]
public DateTimeOffset? ProcessedAt { get; set; }
/// <summary>
/// The type of payment processing method. Known values are 'checkout', 'direct', 'manual', 'offsite', 'express', 'free' and 'none'.
/// </summary>
[JsonProperty("processing_method")]
public string ProcessingMethod { get; set; }
/// <summary>
/// The website that the customer clicked on to come to the shop.
/// </summary>
[JsonProperty("referring_site")]
public string ReferringSite { get; set; }
/// <summary>
/// The list of <see cref="Refund"/> objects applied to the order
/// </summary>
[JsonProperty("refunds")]
public IEnumerable<Refund> Refunds { get; set; }
/// <summary>
/// The mailing address to where the order will be shipped. This address is optional and will not be available on orders that do not require one.
/// </summary>
[JsonProperty("shipping_address")]
public Address ShippingAddress { get; set; }
/// <summary>
/// An array of <see cref="ShippingLine"/> objects, each of which details the shipping methods used.
/// </summary>
[JsonProperty("shipping_lines")]
public IEnumerable<ShippingLine> ShippingLines { get; set; }
/// <summary>
/// Where the order originated. May only be set during creation, and is not writeable thereafter.
/// Orders created via the API may be assigned any string of your choice except for "web", "pos", "iphone", and "android".
/// Default is "api".
/// </summary>
[JsonProperty("source_name")]
public string SourceName { get; set; }
/// <summary>
/// Price of the order before shipping and taxes
/// </summary>
[JsonProperty("subtotal_price")]
public decimal? SubtotalPrice { get; set; }
/// <summary>
/// An array of <see cref="TaxLine"/> objects, each of which details the total taxes applicable to the order.
/// </summary>
[JsonProperty("tax_lines")]
public IEnumerable<TaxLine> TaxLines { get; set; }
/// <summary>
/// States whether or not taxes are included in the order subtotal.
/// </summary>
[JsonProperty("taxes_included")]
public bool? TaxesIncluded { get; set; }
/// <summary>
/// Unique identifier for a particular order.
/// </summary>
[JsonProperty("token")]
public string Token { get; set; }
/// <summary>
/// The total amount of the discounts applied to the price of the order.
/// </summary>
[JsonProperty("total_discounts")]
public decimal? TotalDiscounts { get; set; }
/// <summary>
/// The sum of all the prices of all the items in the order.
/// </summary>
[JsonProperty("total_line_items_price")]
public decimal? TotalLineItemsPrice { get; set; }
/// <summary>
/// The sum of all the prices of all the items in the order, with taxes and discounts included (must be positive).
/// </summary>
[JsonProperty("total_price")]
public decimal? TotalPrice { get; set; }
/// <summary>
/// The sum of all the prices of all the items in the order, in USD, with taxes and discounts included (must be positive).
/// </summary>
[JsonProperty("total_price_usd"), Obsolete("TotalPriceUsd is not documented by Shopify and will be removed in a future release.")]
public decimal? TotalPriceUsd { get; set; }
/// <summary>
/// The sum of all the taxes applied to the order (must be positive).
/// </summary>
[JsonProperty("total_tax")]
public decimal? TotalTax { get; set; }
/// <summary>
/// The sum of all the weights of the line items in the order, in grams.
/// </summary>
[JsonProperty("total_weight")]
public long? TotalWeight { get; set; }
/// <summary>
/// The date and time when the order was last modified.
/// </summary>
[JsonProperty("updated_at")]
public DateTimeOffset? UpdatedAt { get; set; }
/// <summary>
/// The unique numerical identifier for the user logged into the terminal at the time the order was processed at. Only present on orders processed at point of sale.
/// </summary>
[JsonProperty("user_id")]
public long? UserId { get; set; }
/// <summary>
/// An array of <see cref="Transaction"/> objects that detail all of the transactions in
/// this order.
/// </summary>
[JsonProperty("transactions")]
public IEnumerable<Transaction> Transactions { get; set; }
}
当它从客户端调用 GetOrders() 时,我似乎收到了上面提到的错误消息:
ProductService.ProductServiceClient productService = new ProductService.ProductServiceClient();
OrderService.OrderServiceClient service = new OrderService.OrderServiceClient();
var orders = service.GetOrders(String.Format("orders.json?created_at_min={0}&created_at_max={1}", min, max));
强文本
我已经在我的客户端应用程序中搜索了所有对 Newtonsoft 的引用,但我没有找到任何暗示它被调用的线索 "recursively." 我已经删除并重新添加了该服务参考,同样的问题。
服务和客户端都是v4.6.1.
有什么想法吗?
本
编辑:出于某种原因我现在无法触发错误,但是当它确实发生时,我将其作为外部异常,然后是主要错误消息和内部异常:
Unhandled Exception: System.ServiceModel.CommunicationException: An error occurred while receiving the HTTP response to http://localhost:3000/OrderService.svc/GetOrders. This could be due to the service endpoint
binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down).
See server logs for more details.
---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive.
---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.Connection.SyncRead(HttpWebRequest request, Boolean userRetrievedStream, Boolean probeRead)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
--- End of inner exception stack trace ---
Server stack trace:
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at ShopifyServiceClient.OrderService.IOrderService.GetOrders(String query)
at ShopifyServiceClient.OrderService.OrderServiceClient.GetOrders(String query)
at ShopifyServiceClient.Program.Main(String[] args)
再往下....
System.Runtime.Serialization.InvalidDataContractException,
System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089
Type 'Newtonsoft.Json.Linq.JToken' is a recursive collection data
contract which is not supported. Consider modifying the definition of
collection 'Newtonsoft.Json.Linq.JToken' to remove references to
itself.
这是我的服务的入口点:
public class OrderService : IOrderService
{
public ReturnContract GetOffset()
{
return new ReturnContract { Offset = new DateTimeOffset(DateTime.Now) };
}
//non-async calls
public List<Order> GetOrders(string query)
{
OrderData orders = new OrderData(query);
return orders.CallOrders();
}
[DataContract]
[KnownType(typeof(DateTimeOffset))]
public class ReturnContract
{
[DataMember]
public DateTimeOffset? Offset { get; set; }
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
CallOrders()
实现和 CallService<T>
显示进入方法的类型 Order 的方法:
internal class OrderData
{
private string _shopifyStore = Global.EcomShop;
private string _apiKey = Global.EcomShopAPIKey;
private string _apiPassword = Global.EcomShopAPIPassword;
private string _query;
internal OrderData(string query)
{
_query = query;
}
internal List<Order> CallOrders()
{
var orderService = new ShopifyService(_shopifyStore, _apiKey, _apiPassword, "orders");
var orders = orderService.CallService<Order>(_query);
return orders;
}
}
好吧,在这种情况下,它原来是一个 JSON 反序列化问题。过去发生这种情况时,我收到了 "object reference not set to an instance of an object" 错误。我认为这很奇怪,因为我确实看到 Shopify 对象从服务返回。
我遇到了一个问题,我无法解决我正在构建的 WCF 服务,我在其中收到错误:
"Type 'Newtonsoft.Json.Linq.JToken' is a recursive collection data contract which is not supported. Consider modifying the definition of collection 'Newtonsoft.Json.Linq.JToken' to remove references to itself"
我知道主要的解决方案是取消选中在我的服务引用中重用该 Newtonsoft 引用的选项,但我没有列出要取消选中的选项。我确认 json.net 在我的服务中被正确引用。
奇怪的是,当我离开这个电话时,我确认我得到了结果
public List<T> CallService<T>(string query)
{
var data = new List<T>();
var fullyEscapedUri = _ShopUri.AbsoluteUri.EndsWith("/") ? _ShopUri : new Uri(_ShopUri + "/");
var uri = new Uri(fullyEscapedUri, typeof(T).Name);
if (!string.IsNullOrWhiteSpace(query))
{
var uriBuilder = new UriBuilder(uri) { Query = query };
uri = uriBuilder.Uri;
}
string url = String.Format("{0}{1}", _ShopUri, query);
var request = WebRequest.Create(url);
request.Method = "GET";
request.ContentType = "application/json";
string base64EncodedUsernameAndPassword = string.Format("{0}:{1}", _Username, _Password);
string authHeader = string.Format("Basic {0}", Convert.ToBase64String(Encoding.UTF8.GetBytes(base64EncodedUsernameAndPassword)));
request.Headers["Authorization"] = authHeader;
using (var response = request.GetResponse())
{
using (var stream = response.GetResponseStream())
{
using (var reader = new StreamReader(stream))
{
string json = reader.ReadToEnd();
var jsonObj = JsonConvert.DeserializeObject(json, new JsonSerializerSettings()
{
Formatting = Formatting.Indented,
TypeNameHandling = TypeNameHandling.Auto,
ContractResolver = new CamelCasePropertyNamesContractResolver(),
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
}) as JObject;
var jsonArray = jsonObj[_ObjectType] as JArray;
foreach (var jsonEmp in jsonArray)
{
var obj = JsonConvert.DeserializeObject<T>(jsonEmp.ToString());
data.Add(obj);
}
}
}
}
return data;
}
此方法是我编写的自定义 class 中的方法,因此有几个变量看起来好像没有定义 - 我会收到一大堆代码。但如您所见,我需要此方法来动态调用任何 Shopify 端点。在这个例子中,第一次进入的_ObjectType变量是"orders."
这是我的订单class定义:
public class Orders : ShopifyObject
{
[JsonProperty(PropertyName = "orders")]
public List<Order> orders;
}
public class Order : ShopifyObject
{
/// <summary>
/// The mailing address associated with the payment method. This address is an optional field that will not be available on orders that do not require one.
/// </summary>
[JsonProperty("billing_address")]
public Address BillingAddress { get; set; }
/// <summary>
/// The IP address of the browser used by the customer when placing the order.
/// </summary>
[JsonProperty("browser_ip")]
public string BrowserIp { get; set; }
/// <summary>
/// Indicates whether or not the person who placed the order would like to receive email updates from the shop.
/// This is set when checking the "I want to receive occasional emails about new products, promotions and other news" checkbox during checkout.
/// </summary>
[JsonProperty("buyer_accepts_marketing")]
public bool? BuyerAcceptsMarketing { get; set; }
/// <summary>
/// The reason why the order was cancelled. If the order was not cancelled, this value is null. Known values are "customer", "fraud", "inventory" and "other".
/// </summary>
[JsonProperty("cancel_reason")]
public string CancelReason { get; set; }
/// <summary>
/// The date and time when the order was cancelled. If the order was not cancelled, this value is null.
/// </summary>
[JsonProperty("cancelled_at")]
public DateTimeOffset? CancelledAt { get; set; }
/// <summary>
/// Unique identifier for a particular cart that is attached to a particular order.
/// </summary>
[JsonProperty("cart_token")]
public string CartToken { get; set; }
/// <summary>
/// A <see cref="ShopifySharp.ClientDetails"/> object containing information about the client.
/// </summary>
[JsonProperty("client_details")]
public ClientDetails ClientDetails { get; set; }
/// <summary>
/// The date and time when the order was closed. If the order was not clsoed, this value is null.
/// </summary>
[JsonProperty("closed_at")]
public DateTimeOffset? ClosedAt { get; set; }
/// <summary>
/// The customer's contact email address.
/// </summary>
[JsonProperty("contact_email"), Obsolete("ContactEmail is not documented by Shopify and will be removed in a future release.")]
public string ContactEmail { get; set; }
/// <summary>
/// The date and time when the order was created in Shopify.
/// </summary>
[JsonProperty("created_at")]
public DateTimeOffset? CreatedAt { get; set; }
/// <summary>
/// The three letter code (ISO 4217) for the currency used for the payment.
/// </summary>
[JsonProperty("currency")]
public string Currency { get; set; }
/// <summary>
/// A <see cref="ShopifySharp.Customer"/> object containing information about the customer. This value may be null if the order was created through Shopify POS.
/// </summary>
[JsonProperty("customer")]
public Customer Customer { get; set; }
/// <summary>
/// Applicable discount codes that can be applied to the order.
/// </summary>
[JsonProperty("discount_codes")]
public IEnumerable<DiscountCode> DiscountCodes { get; set; }
/// <summary>
/// The order's email address. Note: On and after 2015-11-03, you should be using <see cref="ContactEmail"/> to refer to the customer's email address.
/// Between 2015-11-03 and 2015-12-03, updates to an order's email will also update the customer's email. This is temporary so apps can be migrated over to
/// doing customer updates rather than order updates to change the contact email. After 2015-12-03, updating updating an order's email will no longer update
/// the customer's email and apps will have to use the customer update endpoint to do so.
/// </summary>
[JsonProperty("email")]
public string Email { get; set; }
/// <summary>
/// The financial status of an order. Known values are "authorized", "paid", "pending", "partially_paid", "partially_refunded", "refunded" and "voided".
/// </summary>
[JsonProperty("financial_status")]
public string FinancialStatus { get; set; }
/// <summary>
/// An array of <see cref="Fulfillment"/> objects for this order.
/// </summary>
[JsonProperty("fulfillments")]
public IEnumerable<Fulfillment> Fulfillments { get; set; }
/// <summary>
/// The fulfillment status for this order. Known values are 'fulfilled', 'null' and 'partial'.
/// </summary>
[JsonProperty("fulfillment_status")]
public string FulfillmentStatus { get; set; }
/// <summary>
/// Tags are additional short descriptors, commonly used for filtering and searching, formatted as a string of comma-separated values.
/// </summary>
[JsonProperty("tags")]
public string Tags { get; set; }
/// <summary>
/// The URL for the page where the buyer landed when entering the shop.
/// </summary>
[JsonProperty("landing_site")]
public string LandingSite { get; set; }
/// <summary>
/// An array of <see cref="LineItem"/> objects, each one containing information about an item in the order.
/// </summary>
[JsonProperty("line_items")]
public IEnumerable<LineItem> LineItems { get; set; }
/// <summary>
/// The unique numeric identifier for the physical location at which the order was processed. Only present on orders processed at point of sale.
/// </summary>
[JsonProperty("location_id")]
public long? LocationId { get; set; }
/// <summary>
/// The customer's order name as represented by a number, e.g. '#1001'.
/// </summary>
[JsonProperty("name")]
public string Name { get; set; }
/// <summary>
/// The text of an optional note that a shop owner can attach to the order.
/// </summary>
[JsonProperty("note")]
public string Note { get; set; }
/// <summary>
/// Extra information that is added to the order.
/// </summary>
[JsonProperty("note_attributes")]
public IEnumerable<NoteAttribute> NoteAttributes { get; set; }
/// <summary>
/// Numerical identifier unique to the shop. A number is sequential and starts at 1000.
/// </summary>
[JsonProperty("number")]
public int? Number { get; set; }
/// <summary>
/// A unique numeric identifier for the order. This one is used by the shop owner and customer.
/// This is different from the id property, which is also a unique numeric identifier for the order, but used for API purposes.
/// </summary>
[JsonProperty("order_number")]
public int? OrderNumber { get; set; }
/// <summary>
/// The URL pointing to the order status web page. The URL will be null unless the order was created from a checkout.
/// </summary>
[JsonProperty("order_status_url")]
public string OrderStatusUrl { get; set; }
/// <summary>
/// Payment details for this order. May be null if the order was created via API without payment details.
/// </summary>
[JsonProperty("payment_details"), Obsolete("PaymentDetails has been deprecated and will be removed in a future release. This data is now available via the Transaction API.")]
public PaymentDetails PaymentDetails { get; set; }
/// <summary>
/// The list of all payment gateways used for the order.
/// </summary>
[JsonProperty("payment_gateway_names")]
public IEnumerable<string> PaymentGatewayNames { get; set; }
/// <summary>
/// The date that the order was processed at.
/// </summary>
[JsonProperty("processed_at")]
public DateTimeOffset? ProcessedAt { get; set; }
/// <summary>
/// The type of payment processing method. Known values are 'checkout', 'direct', 'manual', 'offsite', 'express', 'free' and 'none'.
/// </summary>
[JsonProperty("processing_method")]
public string ProcessingMethod { get; set; }
/// <summary>
/// The website that the customer clicked on to come to the shop.
/// </summary>
[JsonProperty("referring_site")]
public string ReferringSite { get; set; }
/// <summary>
/// The list of <see cref="Refund"/> objects applied to the order
/// </summary>
[JsonProperty("refunds")]
public IEnumerable<Refund> Refunds { get; set; }
/// <summary>
/// The mailing address to where the order will be shipped. This address is optional and will not be available on orders that do not require one.
/// </summary>
[JsonProperty("shipping_address")]
public Address ShippingAddress { get; set; }
/// <summary>
/// An array of <see cref="ShippingLine"/> objects, each of which details the shipping methods used.
/// </summary>
[JsonProperty("shipping_lines")]
public IEnumerable<ShippingLine> ShippingLines { get; set; }
/// <summary>
/// Where the order originated. May only be set during creation, and is not writeable thereafter.
/// Orders created via the API may be assigned any string of your choice except for "web", "pos", "iphone", and "android".
/// Default is "api".
/// </summary>
[JsonProperty("source_name")]
public string SourceName { get; set; }
/// <summary>
/// Price of the order before shipping and taxes
/// </summary>
[JsonProperty("subtotal_price")]
public decimal? SubtotalPrice { get; set; }
/// <summary>
/// An array of <see cref="TaxLine"/> objects, each of which details the total taxes applicable to the order.
/// </summary>
[JsonProperty("tax_lines")]
public IEnumerable<TaxLine> TaxLines { get; set; }
/// <summary>
/// States whether or not taxes are included in the order subtotal.
/// </summary>
[JsonProperty("taxes_included")]
public bool? TaxesIncluded { get; set; }
/// <summary>
/// Unique identifier for a particular order.
/// </summary>
[JsonProperty("token")]
public string Token { get; set; }
/// <summary>
/// The total amount of the discounts applied to the price of the order.
/// </summary>
[JsonProperty("total_discounts")]
public decimal? TotalDiscounts { get; set; }
/// <summary>
/// The sum of all the prices of all the items in the order.
/// </summary>
[JsonProperty("total_line_items_price")]
public decimal? TotalLineItemsPrice { get; set; }
/// <summary>
/// The sum of all the prices of all the items in the order, with taxes and discounts included (must be positive).
/// </summary>
[JsonProperty("total_price")]
public decimal? TotalPrice { get; set; }
/// <summary>
/// The sum of all the prices of all the items in the order, in USD, with taxes and discounts included (must be positive).
/// </summary>
[JsonProperty("total_price_usd"), Obsolete("TotalPriceUsd is not documented by Shopify and will be removed in a future release.")]
public decimal? TotalPriceUsd { get; set; }
/// <summary>
/// The sum of all the taxes applied to the order (must be positive).
/// </summary>
[JsonProperty("total_tax")]
public decimal? TotalTax { get; set; }
/// <summary>
/// The sum of all the weights of the line items in the order, in grams.
/// </summary>
[JsonProperty("total_weight")]
public long? TotalWeight { get; set; }
/// <summary>
/// The date and time when the order was last modified.
/// </summary>
[JsonProperty("updated_at")]
public DateTimeOffset? UpdatedAt { get; set; }
/// <summary>
/// The unique numerical identifier for the user logged into the terminal at the time the order was processed at. Only present on orders processed at point of sale.
/// </summary>
[JsonProperty("user_id")]
public long? UserId { get; set; }
/// <summary>
/// An array of <see cref="Transaction"/> objects that detail all of the transactions in
/// this order.
/// </summary>
[JsonProperty("transactions")]
public IEnumerable<Transaction> Transactions { get; set; }
}
当它从客户端调用 GetOrders() 时,我似乎收到了上面提到的错误消息:
ProductService.ProductServiceClient productService = new ProductService.ProductServiceClient();
OrderService.OrderServiceClient service = new OrderService.OrderServiceClient();
var orders = service.GetOrders(String.Format("orders.json?created_at_min={0}&created_at_max={1}", min, max));
强文本
我已经在我的客户端应用程序中搜索了所有对 Newtonsoft 的引用,但我没有找到任何暗示它被调用的线索 "recursively." 我已经删除并重新添加了该服务参考,同样的问题。
服务和客户端都是v4.6.1.
有什么想法吗?
本
编辑:出于某种原因我现在无法触发错误,但是当它确实发生时,我将其作为外部异常,然后是主要错误消息和内部异常:
Unhandled Exception: System.ServiceModel.CommunicationException: An error occurred while receiving the HTTP response to http://localhost:3000/OrderService.svc/GetOrders. This could be due to the service endpoint
binding not using the HTTP protocol. This could also be due to an HTTP request context being aborted by the server (possibly due to the service shutting down).
See server logs for more details.
---> System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a receive.
---> System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
---> System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
--- End of inner exception stack trace ---
at System.Net.Sockets.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.PooledStream.Read(Byte[] buffer, Int32 offset, Int32 size)
at System.Net.Connection.SyncRead(HttpWebRequest request, Boolean userRetrievedStream, Boolean probeRead)
--- End of inner exception stack trace ---
at System.Net.HttpWebRequest.GetResponse()
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
--- End of inner exception stack trace ---
Server stack trace:
at System.ServiceModel.Channels.HttpChannelUtilities.ProcessGetResponseWebException(WebException webException, HttpWebRequest request, HttpAbortReason abortReason)
at System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
at System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
Exception rethrown at [0]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at ShopifyServiceClient.OrderService.IOrderService.GetOrders(String query)
at ShopifyServiceClient.OrderService.OrderServiceClient.GetOrders(String query)
at ShopifyServiceClient.Program.Main(String[] args)
再往下....
System.Runtime.Serialization.InvalidDataContractException, System.Runtime.Serialization, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Type 'Newtonsoft.Json.Linq.JToken' is a recursive collection data contract which is not supported. Consider modifying the definition of collection 'Newtonsoft.Json.Linq.JToken' to remove references to itself.
这是我的服务的入口点:
public class OrderService : IOrderService
{
public ReturnContract GetOffset()
{
return new ReturnContract { Offset = new DateTimeOffset(DateTime.Now) };
}
//non-async calls
public List<Order> GetOrders(string query)
{
OrderData orders = new OrderData(query);
return orders.CallOrders();
}
[DataContract]
[KnownType(typeof(DateTimeOffset))]
public class ReturnContract
{
[DataMember]
public DateTimeOffset? Offset { get; set; }
}
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
CallOrders()
实现和 CallService<T>
显示进入方法的类型 Order 的方法:
internal class OrderData
{
private string _shopifyStore = Global.EcomShop;
private string _apiKey = Global.EcomShopAPIKey;
private string _apiPassword = Global.EcomShopAPIPassword;
private string _query;
internal OrderData(string query)
{
_query = query;
}
internal List<Order> CallOrders()
{
var orderService = new ShopifyService(_shopifyStore, _apiKey, _apiPassword, "orders");
var orders = orderService.CallService<Order>(_query);
return orders;
}
}
好吧,在这种情况下,它原来是一个 JSON 反序列化问题。过去发生这种情况时,我收到了 "object reference not set to an instance of an object" 错误。我认为这很奇怪,因为我确实看到 Shopify 对象从服务返回。