diff --git a/Base/BaseObject.cs b/Base/BaseObject.cs index 0c0336b..09beac1 100644 --- a/Base/BaseObject.cs +++ b/Base/BaseObject.cs @@ -5,13 +5,15 @@ using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; -using WooCommerce.NET.WordPress.v2; namespace WooCommerceNET.Base { [DataContract] public class JsonObject { + [IgnoreDataMember] + public static CultureInfo Culture { get; set; } + [OnSerializing] void OnSerializing(StreamingContext ctx) { @@ -28,13 +30,13 @@ void OnSerializing(StreamingContext ctx) GetType().GetTypeInfo().BaseType.FullName.StartsWith("WooCommerceNET.WooCommerce.v1") || GetType().GetTypeInfo().BaseType.FullName.StartsWith("WooCommerceNET.WooCommerce.v2") || GetType().GetTypeInfo().BaseType.FullName.StartsWith("WooCommerceNET.WooCommerce.v3")) - objValue.SetValue(this, (pi.GetValue(this) as decimal?).Value.ToString(CultureInfo.InvariantCulture)); + objValue.SetValue(this, (pi.GetValue(this) as decimal?).Value.ToString(Culture)); else - objValue.SetValue(this, decimal.Parse(pi.GetValue(this).ToString(), CultureInfo.InvariantCulture)); + objValue.SetValue(this, decimal.Parse(pi.GetValue(this).ToString(), Culture)); } else if (pi.PropertyType == typeof(int?)) { - objValue.SetValue(this, int.Parse(pi.GetValue(this).ToString(), CultureInfo.InvariantCulture)); + objValue.SetValue(this, int.Parse(pi.GetValue(this).ToString(), Culture)); } else if (pi.PropertyType == typeof(DateTime?)) { @@ -58,14 +60,14 @@ void OnDeserialized(StreamingContext ctx) object value = objValue.GetValue(this); if (!(value == null || value.ToString() == string.Empty)) - pi.SetValue(this, decimal.Parse(value.ToString(), CultureInfo.InvariantCulture)); + pi.SetValue(this, decimal.Parse(value.ToString(), Culture)); } else if (pi.PropertyType == typeof(int?)) { object value = objValue.GetValue(this); if (!(value == null || value.ToString() == string.Empty)) - pi.SetValue(this, int.Parse(value.ToString(), CultureInfo.InvariantCulture)); + pi.SetValue(this, int.Parse(value.ToString(), Culture)); } else if (pi.PropertyType == typeof(DateTime?)) { diff --git a/Base/HMAC-SHA256.cs b/Base/HMAC-SHA256.cs index ab8cd6e..a9939a0 100644 --- a/Base/HMAC-SHA256.cs +++ b/Base/HMAC-SHA256.cs @@ -1,8 +1,4 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; namespace WooCommerceNET.Base { diff --git a/Base/SHA1.cs b/Base/SHA1.cs index 417e9ba..64c8d52 100644 --- a/Base/SHA1.cs +++ b/Base/SHA1.cs @@ -1,8 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using System.Text; namespace WooCommerceNET.Base { diff --git a/Changes.md b/Changes.md index 14aa7d1..3c511a8 100644 --- a/Changes.md +++ b/Changes.md @@ -3,6 +3,10 @@ Version History ------------------- +* v0.8.6 update + 1. Fix manage_stock property deserializing issue in Project object. #722 + 2. Add Culture object in WCObject constructor to resolve format issue. #731 + 3. Allow accessing WordPress plugin REST API with WooCommerce secret and key. * v0.8.5 update 1. Change all id field to 64bit integer (unsigned long) to prevent overflow. #560 2. Add WCCustomerItem for get customer by email endpoint. diff --git a/Properties/PublishProfiles/FolderProfile.pubxml b/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..7d5583d --- /dev/null +++ b/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,12 @@ + + + + + Release + Any CPU + bin\Release\netstandard2.0\publish\ + FileSystem + + \ No newline at end of file diff --git a/Properties/PublishProfiles/FolderProfile.pubxml.user b/Properties/PublishProfiles/FolderProfile.pubxml.user new file mode 100644 index 0000000..82d3356 --- /dev/null +++ b/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -0,0 +1,9 @@ + + + + + True|2021-11-20T01:40:11.9243673Z;True|2021-03-17T21:17:35.0713079+13:00; + + \ No newline at end of file diff --git a/Readme.md b/Readme.md index 63a842a..673a3cf 100644 --- a/Readme.md +++ b/Readme.md @@ -14,6 +14,8 @@ WooCommerce.NET is a .NET library for calling WooCommerce/WordPress REST API wit If this project has been helpful for you and you want to support it, please consider [Buying me a coffee](https://www.buymeacoffee.com/YU0SqVyrR):coffee: +**For priority paid support/consulting service, customized REST API implementation and plugins REST API implementation, please email to [James (me:sunglasses:)](mailto:xiaofaye@msn.com)** + Usage (WooCommerce REST API) ------------------- * [How to use JSON.NET in WooCommerce.NET](https://github.com/XiaoFaye/WooCommerce.NET/wiki/How-to-use-JSON.NET-in-WooCommerce.NET) @@ -32,6 +34,9 @@ using WooCommerceNET.WooCommerce.v3.Extension; RestAPI rest = new RestAPI("http://www.yourstore.co.nz/wp-json/wc/v3/", "", " SendHttpClientRequest(string endpoint, Requ if (wc_url.StartsWith("https", StringComparison.OrdinalIgnoreCase) && Version != APIVersion.WordPressAPI && Version != APIVersion.WordPressAPIJWT) { - if (AuthorizedHeader == true) - { - httpWebRequest = (HttpWebRequest)WebRequest.Create(wc_url + GetOAuthEndPoint(method.ToString(), endpoint, parms)); - if (WCAuthWithJWT && JWT_Object != null) - httpWebRequest.Headers["Authorization"] = "Bearer " + JWT_Object.token; - else - httpWebRequest.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(wc_key + ":" + wc_secret)); - } - else + if (AuthorizedHeader == false) { if (parms == null) parms = new Dictionary(); @@ -206,8 +195,22 @@ public virtual async Task SendHttpClientRequest(string endpoint, Requ parms.Add("consumer_key", wc_key); if (!parms.ContainsKey("consumer_secret")) parms.Add("consumer_secret", wc_secret); + } + //Allow accessing WordPress plugin REST API with WooCommerce secret and key. + //Url should be passed to RestAPI as WooCommerce Rest API url, e.g.: https://mystore.com/wp-json/wc/v3 + //Endpoint should be starting with wp-json + if (endpoint.StartsWith("wp-json")) + httpWebRequest = (HttpWebRequest)WebRequest.Create(new Uri(new Uri($"https://{new Uri(wc_url).Host}"), GetOAuthEndPoint(method.ToString(), endpoint, parms))); + else httpWebRequest = (HttpWebRequest)WebRequest.Create(wc_url + GetOAuthEndPoint(method.ToString(), endpoint, parms)); + + if (AuthorizedHeader == true) + { + if (WCAuthWithJWT && JWT_Object != null) + httpWebRequest.Headers["Authorization"] = "Bearer " + JWT_Object.token; + else + httpWebRequest.Headers["Authorization"] = "Basic " + Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(wc_key + ":" + wc_secret)); } } else @@ -220,7 +223,7 @@ public virtual async Task SendHttpClientRequest(string endpoint, Requ // start the stream immediately httpWebRequest.Method = method.ToString(); httpWebRequest.AllowReadStreamBuffering = false; - + if (webRequestFilter != null) webRequestFilter.Invoke(httpWebRequest); @@ -298,27 +301,27 @@ public virtual async Task SendHttpClientRequest(string endpoint, Requ public async Task GetRestful(string endpoint, Dictionary parms = null) { - return await SendHttpClientRequest(endpoint, RequestMethod.GET, string.Empty, parms).ConfigureAwait(false); + return await SendHttpClientRequest(endpoint.ToLower(), RequestMethod.GET, string.Empty, parms).ConfigureAwait(false); } public async Task PostRestful(string endpoint, object jsonObject, Dictionary parms = null) { - return await SendHttpClientRequest(endpoint, RequestMethod.POST, jsonObject, parms).ConfigureAwait(false); + return await SendHttpClientRequest(endpoint.ToLower(), RequestMethod.POST, jsonObject, parms).ConfigureAwait(false); } public async Task PutRestful(string endpoint, object jsonObject, Dictionary parms = null) { - return await SendHttpClientRequest(endpoint, RequestMethod.PUT, jsonObject, parms).ConfigureAwait(false); + return await SendHttpClientRequest(endpoint.ToLower(), RequestMethod.PUT, jsonObject, parms).ConfigureAwait(false); } public async Task DeleteRestful(string endpoint, Dictionary parms = null) { - return await SendHttpClientRequest(endpoint, RequestMethod.DELETE, string.Empty, parms).ConfigureAwait(false); + return await SendHttpClientRequest(endpoint.ToLower(), RequestMethod.DELETE, string.Empty, parms).ConfigureAwait(false); } public async Task DeleteRestful(string endpoint, object jsonObject, Dictionary parms = null) { - return await SendHttpClientRequest(endpoint, RequestMethod.DELETE, jsonObject, parms).ConfigureAwait(false); + return await SendHttpClientRequest(endpoint.ToLower(), RequestMethod.DELETE, jsonObject, parms).ConfigureAwait(false); } protected string GetOAuthEndPoint(string method, string endpoint, Dictionary parms = null) diff --git a/WooCommerce.NET.csproj b/WooCommerce.NET.csproj index 2c47e55..351758d 100644 --- a/WooCommerce.NET.csproj +++ b/WooCommerce.NET.csproj @@ -3,7 +3,7 @@ netstandard2.0 WooCommerceNET - 0.8.5 + 0.8.6 JamesYang@NZ JamesYang@NZ A .NET Wrapper for WooCommerce/WordPress REST API @@ -15,18 +15,19 @@ GitHub: https://github.com/XiaoFaye/WooCommerce.NET Changes Doc: https://github.com/XiaoFaye/WooCommerce.NET/blob/master/Changes.md -* v0.8.5 update - 1. Change all id field to 64bit integer (unsigned long) to prevent overflow. #560 - 2. Add WCCustomerItem for get customer by email endpoint. - 3. Escape all querystrings. +* v0.8.6 update + 1. Fix manage_stock property deserializing issue in Project object. #722 + 2. Add Culture object in WCObject constructor to resolve format issue. #731 + 3. Allow accessing WordPress plugin REST API with WooCommerce secret and key. true - 0.8.5.0 + 0.8.6.0 false sn.key.snk License.md true - 0.8.5.0 + 0.8.6.0 WooCommerce Wordpress Restful API + Readme.md @@ -40,4 +41,11 @@ Changes Doc: https://github.com/XiaoFaye/WooCommerce.NET/blob/master/Changes.md + + + True + \ + + + diff --git a/WooCommerce/v1/Product.cs b/WooCommerce/v1/Product.cs index fcc610b..45341a0 100644 --- a/WooCommerce/v1/Product.cs +++ b/WooCommerce/v1/Product.cs @@ -237,6 +237,8 @@ public class Product : JsonObject /// /// Stock management at product level. Default is false. /// When Manage stock is checked, string value "parent" will be given, otherwise, it will be bool value false. + /// The "parent" should appear in Variation object, however, when getting Products with variation SKU as parameter, + /// variation object with "parent" value returned in product endpoints. That's why we have to set manage_stock type as object in Product object as well. /// [DataMember(EmitDefaultValue = false)] public object manage_stock { get; set; } diff --git a/WooCommerce/v1/WCObject.cs b/WooCommerce/v1/WCObject.cs index 36856e8..7976840 100644 --- a/WooCommerce/v1/WCObject.cs +++ b/WooCommerce/v1/WCObject.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Threading.Tasks; using WooCommerceNET.Base; @@ -28,11 +29,13 @@ public class WCObject GetWebhookDelivery(int webhookid, int deliver public class WCObject : WCObject { - public WCObject(RestAPI api) : base(api) + public WCObject(RestAPI api, CultureInfo culture = null) : base(api, culture) { } } diff --git a/WooCommerce/v2/Product.cs b/WooCommerce/v2/Product.cs index 6ee0598..6160fc9 100644 --- a/WooCommerce/v2/Product.cs +++ b/WooCommerce/v2/Product.cs @@ -252,9 +252,12 @@ public class Product : JsonObject /// /// Stock management at product level. Default is false. + /// When Manage stock is checked, string value "parent" will be given, otherwise, it will be bool value false. + /// The "parent" should appear in Variation object, however, when getting Products with variation SKU as parameter, + /// variation object with "parent" value returned in product endpoints. That's why we have to set manage_stock type as object in Product object as well. /// [DataMember(EmitDefaultValue = false)] - public bool? manage_stock { get; set; } + public object manage_stock { get; set; } [DataMember(EmitDefaultValue = false, Name = "stock_quantity")] protected object stock_quantityValue { get; set; } diff --git a/WooCommerce/v2/WCObject.cs b/WooCommerce/v2/WCObject.cs index d3d37ec..ef7702f 100644 --- a/WooCommerce/v2/WCObject.cs +++ b/WooCommerce/v2/WCObject.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Runtime.Serialization; using System.Threading.Tasks; using WooCommerceNET.Base; @@ -16,11 +17,13 @@ public class WCObject MetaValueProcessor { get; set; } public static Func MetaDisplayValueProcessor { get; set; } - public WCObject(RestAPI api) + public WCObject(RestAPI api, CultureInfo culture = null) { if (api.Version != APIVersion.Version2) throw new Exception("Please use WooCommerce Restful API Version 2 url for this WCObject. e.g.: http://www.yourstore.co.nz/wp-json/wc/v2/"); + JsonObject.Culture = culture ?? CultureInfo.InvariantCulture; + API = api; Coupon = new WCItem(api); @@ -222,7 +225,7 @@ public WCShippingZoneItem(RestAPI api) : base(api) public class WCObject: WCObject { - public WCObject(RestAPI api) : base(api) + public WCObject(RestAPI api, CultureInfo culture = null) : base(api, culture) { } } diff --git a/WooCommerce/v3/Product.cs b/WooCommerce/v3/Product.cs index 36dd510..642a6d4 100644 --- a/WooCommerce/v3/Product.cs +++ b/WooCommerce/v3/Product.cs @@ -252,9 +252,12 @@ public class Product : JsonObject /// /// Stock management at product level. Default is false. + /// When Manage stock is checked, string value "parent" will be given, otherwise, it will be bool value false. + /// The "parent" should appear in Variation object, however, when getting Products with variation SKU as parameter, + /// variation object with "parent" value returned in product endpoints. That's why we have to set manage_stock type as object in Product object as well. /// [DataMember(EmitDefaultValue = false)] - public bool? manage_stock { get; set; } + public object manage_stock { get; set; } [DataMember(EmitDefaultValue = false, Name = "stock_quantity")] protected object stock_quantityValue { get; set; } diff --git a/WooCommerce/v3/WCObject.cs b/WooCommerce/v3/WCObject.cs index 0a918e8..88cf31a 100644 --- a/WooCommerce/v3/WCObject.cs +++ b/WooCommerce/v3/WCObject.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Threading; using System.Threading.Tasks; using WooCommerceNET.Base; @@ -38,11 +39,13 @@ public static Func MetaDisplayValueProcessor } - public WCObject(RestAPI api) + public WCObject(RestAPI api, CultureInfo culture = null) { if (api.Version != APIVersion.Version3 && api.Version != APIVersion.ThirdPartyPlugins) throw new Exception("Please use WooCommerce Restful API Version 3 url for this WCObject. e.g.: http://www.yourstore.co.nz/wp-json/wc/v3/"); + JsonObject.Culture = culture ?? CultureInfo.InvariantCulture; + API = api; Coupon = new WCItem(api); @@ -193,7 +196,7 @@ public WCShippingZoneItem(RestAPI api) : base(api) public class WCObject: WCObject { - public WCObject(RestAPI api) : base(api) + public WCObject(RestAPI api, CultureInfo culture = null) : base(api, culture) { } }