From 48054179f51b4478c06feef8f4cd6991055b71ce Mon Sep 17 00:00:00 2001 From: Ivan Denyssevych Date: Tue, 27 Jan 2026 12:27:31 -0800 Subject: [PATCH 1/4] few updates, framework and NuGet --- MXTires.Microdata.csproj | 8 +-- Products/Product.cs | 2 - Tests/MXTires.Microdata.Tests.csproj | 96 ++++--------------------- Tests/Properties/AssemblyInfo.cs | 36 ---------- Thing.cs | 101 +++++++++++++-------------- 5 files changed, 65 insertions(+), 178 deletions(-) delete mode 100644 Tests/Properties/AssemblyInfo.cs diff --git a/MXTires.Microdata.csproj b/MXTires.Microdata.csproj index 391c6e0..cbd9090 100644 --- a/MXTires.Microdata.csproj +++ b/MXTires.Microdata.csproj @@ -1,7 +1,7 @@  - net461;net472;net48;netcoreapp3.1;net5.0;net6.0 - 1.0.4.5 + net461;net472;net48;net6.0;net8.0 + 1.0.4.6 1010Tires.com Inc. 1010Tires.com Inc. Copyright© 1010Tires.com Inc. 2023. All rights reserved. @@ -13,8 +13,8 @@ true MXTires.MicroData.snk https://github.com/idenys/MXTires.Microdata - 1.0.4.5 - 1.0.4.5 + 1.0.4.6 + 1.0.4.6 MXTires.Microdata README.md latest diff --git a/Products/Product.cs b/Products/Product.cs index 5e5b19a..2321ea7 100644 --- a/Products/Product.cs +++ b/Products/Product.cs @@ -26,8 +26,6 @@ using Newtonsoft.Json; using System; using System.Collections.Generic; -using System.Linq; -using System.Web; using MXTires.Microdata.Intangible; using MXTires.Microdata.Intangible.Enumeration; using Newtonsoft.Json.Converters; diff --git a/Tests/MXTires.Microdata.Tests.csproj b/Tests/MXTires.Microdata.Tests.csproj index 6133a94..fdfba4b 100644 --- a/Tests/MXTires.Microdata.Tests.csproj +++ b/Tests/MXTires.Microdata.Tests.csproj @@ -1,90 +1,22 @@  - + + - Debug - AnyCPU - {E0A5D9F0-0521-4646-A2B7-C4A34B414F71} - Library - Properties - MXTires.Microdata.Tests - MXTires.Microdata.Tests - v4.6.1 - 512 - {3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - 10.0 - $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) - $(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages - False - UnitTest - + net48 + false + + + true - - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - pdbonly - true - bin\Release\ - TRACE - prompt - 4 - - - - - - - - - - - - - - - - + - - + + + + - - {f2a9b387-b954-4895-8ed7-ae95850b1bc1} - MXTires.Microdata - + - - - - - False - - - False - - - False - - - False - - - - - - - + \ No newline at end of file diff --git a/Tests/Properties/AssemblyInfo.cs b/Tests/Properties/AssemblyInfo.cs deleted file mode 100644 index de3b693..0000000 --- a/Tests/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,36 +0,0 @@ -using System.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("MXTires.Microdata.Tests")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("MXTires.Microdata.Tests")] -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("db146b1b-9f14-41bb-a7ea-d9efd4fad7b0")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] -[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Thing.cs b/Thing.cs index 465c60f..e3aa7e1 100644 --- a/Thing.cs +++ b/Thing.cs @@ -25,11 +25,10 @@ using System; using System.Collections.Generic; +using MXTires.Microdata.CreativeWorks; +using MXTires.Microdata.Intangible; using MXTires.Microdata.Validators; using Newtonsoft.Json; -using Newtonsoft.Json.Converters; -using MXTires.Microdata.Intangible; -using MXTires.Microdata.CreativeWorks; namespace MXTires.Microdata { @@ -38,14 +37,30 @@ namespace MXTires.Microdata /// public class Thing { -#pragma warning disable 0414 + private static readonly JsonSerializerSettings SerializerSettings = new JsonSerializerSettings + { + NullValueHandling = NullValueHandling.Ignore + }; + + private static readonly TypeValidator ImageValidator = + new TypeValidator(new List { typeof(string), typeof(ImageObject), typeof(string[]), typeof(ImageObject[]) }); + + private static readonly TypeValidator MainEntityOfPageValidator = + new TypeValidator("MXTires.Microdata.CreativeWorks", null, new List { typeof(string), typeof(WebSite) }); + + private object context = "http://schema.org"; + private object image; + private object mainEntityOfPage; - object context = "http://schema.org"; /// /// Context /// [JsonProperty("@context", Order = 1)] - public virtual object Context { get { return context; } set { context = value; } } + public virtual object Context + { + get { return context; } + set { context = value; } + } /// /// Property for External Extensions @@ -56,7 +71,7 @@ public class Thing /// Type tag /// [JsonProperty("@type", Order = 2)] - public virtual string Type { get { return this.GetType().Name; } } + public virtual string Type { get { return GetType().Name; } } /// /// ID @@ -70,33 +85,31 @@ public class Thing /// 'typeof' attribute - for multiple types. Schema.org tools may have only weaker understanding of extra types, in particular those /// defined externally. /// - [JsonProperty("additionalType")] + [JsonProperty("additionalType", NullValueHandling = NullValueHandling.Ignore)] public string AdditionalType { get; set; } /// /// Text An alias for the item. /// - [JsonProperty("alternateName")] + [JsonProperty("alternateName", NullValueHandling = NullValueHandling.Ignore)] public string AlternateName { get; set; } /// /// Text A short description of the item. /// - [JsonProperty("description")] + [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)] public string Description { get; set; } - object image; /// - /// URL to an image of the item. This can be a URL or a fully described ImageObject. + /// URL to an image of the item. This can be a URL or a fully described ImageObject. /// - [JsonProperty("image")] + [JsonProperty("image", NullValueHandling = NullValueHandling.Ignore)] public object Image { get { return image; } set { - var validator = new TypeValidator(new List(){typeof(String), typeof(ImageObject), typeof(String[]), typeof(ImageObject[])}); - validator.Validate(value); + ImageValidator.Validate(value); image = value; } } @@ -104,30 +117,27 @@ public object Image /// /// Text The name of the item. /// - [JsonProperty("name")] + [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)] public string Name { get; set; } /// /// Action - Indicates a potential Action, which describes an idealized action in which this thing would play an 'object' role. /// - [JsonProperty("potentialAction")] + + [JsonProperty("potentialAction", NullValueHandling = NullValueHandling.Ignore)] public Microdata.Action PotentialAction { get; set; } /// /// URL of a reference Web page that unambiguously indicates the item's identity. E.g. the URL of the item's Wikipedia page, Freebase page, or official website. /// - [JsonProperty("sameAs")] + [JsonProperty("sameAs", NullValueHandling = NullValueHandling.Ignore)] public IList SameAs { get; set; } /// /// URL of the item. /// - [JsonProperty("url")] + [JsonProperty("url", NullValueHandling = NullValueHandling.Ignore)] public string Url { get; set; } - #pragma warning restore 0414 - - private object mainEntityOfPage; - /// /// URL or CreativeWork - Indicates a page (or other CreativeWork) for which this thing is the main entity being described. /// Many (but not all) pages have a fairly clear primary topic, some entity or thing that the page describes. For example a restaurant's home page might be primarily about that Restaurant, or an event listing page might represent a single event. The mainEntity and mainEntityOfPage properties allow you to explicitly express the relationship between the page and the primary entity. @@ -137,14 +147,13 @@ public object Image /// about is similar to mainEntity, with two key differences. First, about can refer to multiple entities/topics, while mainEntity should be used for only the primary one. Second, some pages have a primary entity that itself describes some other entity. For example, one web page may display a news article about a particular person. Another page may display a product review for a particular product. In these cases, mainEntity for the pages should refer to the news article or review, respectively, while about would more properly refer to the person or product. /// Inverse property: mainEntity. /// - [JsonProperty("mainEntityOfPage")] + [JsonProperty("mainEntityOfPage", NullValueHandling = NullValueHandling.Ignore)] public object MainEntityOfPage { get { return mainEntityOfPage; } set { - var validator = new TypeValidator("MXTires.Microdata.CreativeWorks", null, new List(new Type[] { typeof(String), typeof(WebSite) })); - validator.Validate(value); + MainEntityOfPageValidator.Validate(value); mainEntityOfPage = value; } } @@ -157,10 +166,7 @@ public object MainEntityOfPage /// public string ToJson() { - string item = JsonConvert.SerializeObject(this, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - item = item.Replace("Context", "@context"); - if (item.Equals("Type")) item = item.Replace("Type", "@type"); - return ""; + return Serialize(Formatting.None, wrapInScriptTag: true); } /// @@ -170,10 +176,7 @@ public string ToJson() /// public string ToIndentedJson() { - string item = JsonConvert.SerializeObject(this, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - item = item.Replace("Context", "@context"); - if (item.Equals("Type")) item = item.Replace("Type", "@type"); - return ""; + return Serialize(Formatting.Indented, wrapInScriptTag: true); } /// /// Returns Json string that represents current object. @@ -183,29 +186,19 @@ public string ToIndentedJson() /// public override string ToString() { - var item = JsonConvert.SerializeObject(this, Formatting.None, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore }); - item = item.Replace("Context", "@context"); - if (item.Equals("Type")) item = item.Replace("Type", "@type"); - return item; + return Serialize(Formatting.None, wrapInScriptTag: false); } - //#region Delegate and Events - ///// - ///// OnValidateEventHandler delegate to enable injection of custom validation routines - ///// - //public delegate void OnValidateEventHandler(object sender, EventArgs e); - //public delegate void OnValidatedEventHandler(object sender, EventArgs e); - - //public OnValidateEventHandler OnValidate; - //public OnValidatedEventHandler OnValidated; + private string Serialize(Formatting formatting, bool wrapInScriptTag) + { + var json = JsonConvert.SerializeObject(this, formatting, SerializerSettings); - //#endregion - //#region Internal Fields - ///// - ///// The Errors collection to keep the errors. Tthe validation method populates this. - ///// - //public List Errors = new List(); + if (!wrapInScriptTag) + { + return json; + } - //#endregion + return ""; + } } } \ No newline at end of file From 663b3af8cc030d72241c409cfa7458b05b04e9d9 Mon Sep 17 00:00:00 2001 From: Ivan Denyssevych Date: Mon, 23 Feb 2026 10:41:18 -0800 Subject: [PATCH 2/4] Additional properties --- .gitignore | 1 + Thing.cs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) diff --git a/.gitignore b/.gitignore index b426c33..3f4ccbe 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,4 @@ Tools/NuGet/mxtires.microdata.1.0.3.4.nupkg1/lib/net45/MXTires.Microdata.XML Tools/NuGet/mxtires.microdata.1.0.3.4.nupkg1/lib/net461/MXTires.Microdata.XML Tools/NuGet/mxtires.microdata.1.0.3.4.nupkg1/lib/net48/MXTires.Microdata.XML Tools/NuGet/mxtires.microdata.1.0.3.4.nupkg1/package/services/metadata/core-properties/a5ad0c42a2cb49b9b6ac94c92fc9d3d1.psmdcp +.vs/ diff --git a/Thing.cs b/Thing.cs index e3aa7e1..8127969 100644 --- a/Thing.cs +++ b/Thing.cs @@ -28,6 +28,7 @@ using MXTires.Microdata.CreativeWorks; using MXTires.Microdata.Intangible; using MXTires.Microdata.Validators; +using MXTires.Microdata.Intangible.StructuredValues; using Newtonsoft.Json; namespace MXTires.Microdata @@ -48,9 +49,17 @@ public class Thing private static readonly TypeValidator MainEntityOfPageValidator = new TypeValidator("MXTires.Microdata.CreativeWorks", null, new List { typeof(string), typeof(WebSite) }); + private static readonly TypeValidator IdentifierValidator = + new TypeValidator("MXTires.Microdata.Intangible", null, new List { typeof(string), typeof(PropertyValue) }); + + private static readonly TypeValidator SubjectOfValidator = + new TypeValidator("MXTires.Microdata.CreativeWorks", null, new List { typeof(CreativeWork) }); + private object context = "http://schema.org"; + private object identifier; private object image; private object mainEntityOfPage; + private object subjectOf; /// /// Context @@ -100,6 +109,27 @@ public virtual object Context [JsonProperty("description", NullValueHandling = NullValueHandling.Ignore)] public string Description { get; set; } + /// + /// Text - A sub property of description. A short description of the item used to disambiguate from other, similar items. + /// + [JsonProperty("disambiguatingDescription", NullValueHandling = NullValueHandling.Ignore)] + public string DisambiguatingDescription { get; set; } + + /// + /// The identifier property represents any kind of identifier for any kind of Thing, such as ISBNs, GTIN codes, UUIDs etc. + /// Schema.org: PropertyValue | Text | URL + /// + [JsonProperty("identifier", NullValueHandling = NullValueHandling.Ignore)] + public object Identifier + { + get { return identifier; } + set + { + IdentifierValidator.Validate(value); + identifier = value; + } + } + /// /// URL to an image of the item. This can be a URL or a fully described ImageObject. /// @@ -158,6 +188,21 @@ public object MainEntityOfPage } } + /// + /// A CreativeWork or Event about this Thing. + /// Schema.org: CreativeWork | Event + /// + [JsonProperty("subjectOf", NullValueHandling = NullValueHandling.Ignore)] + public object SubjectOf + { + get { return subjectOf; } + set + { + SubjectOfValidator.Validate(value); + subjectOf = value; + } + } + /// /// Returns Json string that represents current object. /// JSON written by the serializer with an option of Formatting.None and NullValueHandling.Ignore. It makes the JSON result small, skipping all unnecessary From 69380f8b53949dbe27c1d9aea56fb52d22fc6701 Mon Sep 17 00:00:00 2001 From: Ivan Denyssevych Date: Mon, 16 Mar 2026 17:42:45 -0700 Subject: [PATCH 3/4] update PriceSpecification to allow lists --- Intangible/Offer.cs | 5 ++++- MXTires.Microdata.csproj | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Intangible/Offer.cs b/Intangible/Offer.cs index 1e2b21c..0db5705 100644 --- a/Intangible/Offer.cs +++ b/Intangible/Offer.cs @@ -40,7 +40,10 @@ public object PriceSpecification get { return priceSpecification; } set { - var validator = new TypeValidator(typeof(PriceSpecification), typeof(IList)); + var validator = new TypeValidator( + "MXTires.Microdata.Intangible.StructuredValues.PriceSpecifications", + null, + new List() { typeof(PriceSpecification), typeof(IList) }); validator.Validate(value); priceSpecification = value; } diff --git a/MXTires.Microdata.csproj b/MXTires.Microdata.csproj index cbd9090..27731b2 100644 --- a/MXTires.Microdata.csproj +++ b/MXTires.Microdata.csproj @@ -38,7 +38,7 @@ - + From c251aa3c950c899c340df00c35544965f6700a11 Mon Sep 17 00:00:00 2001 From: Ivan Denyssevych Date: Mon, 16 Mar 2026 17:58:25 -0700 Subject: [PATCH 4/4] Added public class MemberProgramTier and few properties to PriceSpecification --- Intangible/MemberProgramTier.cs | 43 +++++++++++++++++++++++++++++++++ PriceSpecification.cs | 36 +++++++++++++++++++++++++-- 2 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 Intangible/MemberProgramTier.cs diff --git a/Intangible/MemberProgramTier.cs b/Intangible/MemberProgramTier.cs new file mode 100644 index 0000000..8e592f5 --- /dev/null +++ b/Intangible/MemberProgramTier.cs @@ -0,0 +1,43 @@ +#region License +// Copyright (c) 2026 1010Tires.com +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. +#endregion + +using Newtonsoft.Json; + +namespace MXTires.Microdata.Intangible +{ + /// + /// A membership program tier, for example a club card tier, frequent flyer tier, etc. + /// + public class MemberProgramTier : Thing + { + /// + /// Text - A requirement for a user to join a membership tier, for example: a CreditCard if the tier requires sign up for a credit card, + /// A textual summary of the required threshold or expectations to meet the tier. + /// + /// The tier requirement. + [JsonProperty("tierRequirement")] + public string TierRequirement { get; set; } + } +} diff --git a/PriceSpecification.cs b/PriceSpecification.cs index 9d493c2..72e5781 100644 --- a/PriceSpecification.cs +++ b/PriceSpecification.cs @@ -23,6 +23,7 @@ // OTHER DEALINGS IN THE SOFTWARE. #endregion +using MXTires.Microdata.Intangible; using Newtonsoft.Json; using System; @@ -36,8 +37,22 @@ public class PriceSpecification : Thing #region Properties - //eligibleQuantity QuantitativeValue The interval and unit of measurement of ordering quantities for which the offer or price specification is valid. This allows e.g. specifying that a certain freight charge is valid only for a certain quantity. - //eligibleTransactionVolume PriceSpecification The transaction volume, in a monetary unit, for which the offer or price specification is valid, e.g. for indicating a minimal purchasing volume, to express free shipping above a certain order volume, or to limit the acceptance of credit cards to purchases to a certain minimal amount. + /// + /// QuantitativeValue - The interval and unit of measurement of ordering quantities for which the offer or price specification is valid. + /// This allows e.g. specifying that a certain freight charge is valid only for a certain quantity. + /// + /// The eligible quantity. + [JsonProperty("eligibleQuantity")] + public QuantitativeValue EligibleQuantity { get; set; } + + /// + /// PriceSpecification - The transaction volume, in a monetary unit, for which the offer or price specification is valid, + /// e.g. for indicating a minimal purchasing volume, to express free shipping above a certain order volume, + /// or to limit the acceptance of credit cards to purchases to a certain minimal amount. + /// + /// The eligible transaction volume. + [JsonProperty("eligibleTransactionVolume")] + public PriceSpecification EligibleTransactionVolume { get; set; } /// /// Number The highest price if the price is a range. /// @@ -62,7 +77,24 @@ public class PriceSpecification : Thing /// Text. The currency (in 3-letter ISO 4217 format) of the price or a price component, when attached to PriceSpecification and its subtypes. /// /// The price currency. + [JsonProperty("priceCurrency")] public string PriceCurrency { get; set; } + + /// + /// Number or QuantitativeValue - The number of membership points earned by the member. + /// If necessary, the unitText can be used to express the units the points are issued in. (E.g. stars, miles, etc.) + /// + /// The membership points earned. + [JsonProperty("membershipPointsEarned")] + public QuantitativeValue MembershipPointsEarned { get; set; } + + /// + /// MemberProgramTier - The membership program tier an Offer (or a PriceSpecification, OfferShippingDetails, + /// or MerchantReturnPolicy under an Offer) is valid for. + /// + /// The eligible member tier. + [JsonProperty("eligibleMemberTier")] + public MemberProgramTier EligibleMemberTier { get; set; } /// /// The date when the item becomes valid.