From 2d869323f3a5cfdadbc8a6c1ae5772c47747ad52 Mon Sep 17 00:00:00 2001
From: christian <6939810+chkr1011@users.noreply.github.com>
Date: Tue, 11 Jun 2024 20:08:10 +0200
Subject: [PATCH] Address warnings from analyzers
---
Samples/MQTTnet.Samples.csproj | 2 +-
.../MQTTnet.AspTestApp.csproj | 2 +-
.../MQTTnet.AspNetCore.csproj | 2 +-
.../MQTTnet.Benchmarks.csproj | 4 +-
.../MQTTnet.Extensions.Rpc.csproj | 2 +-
.../MQTTnet.Extensions.TopicTemplate.csproj | 2 +-
.../MqttTopicTemplate.cs | 575 +++++++++---------
Source/MQTTnet.Server/MQTTnet.Server.csproj | 2 +-
Source/MQTTnet.TestApp/MQTTnet.TestApp.csproj | 2 +-
Source/MQTTnet.Tests/MQTTnet.Tests.csproj | 2 +-
Source/MQTTnet/MQTTnet.csproj | 1 +
11 files changed, 297 insertions(+), 299 deletions(-)
diff --git a/Samples/MQTTnet.Samples.csproj b/Samples/MQTTnet.Samples.csproj
index 8606285c8..88e39be5e 100644
--- a/Samples/MQTTnet.Samples.csproj
+++ b/Samples/MQTTnet.Samples.csproj
@@ -10,10 +10,10 @@
false
false
1591;NETSDK1138;NU1803;NU1901;NU1902
- true
true
all
true
+ latest-Recommended
diff --git a/Source/MQTTnet.AspTestApp/MQTTnet.AspTestApp.csproj b/Source/MQTTnet.AspTestApp/MQTTnet.AspTestApp.csproj
index 765e90351..b277d7349 100644
--- a/Source/MQTTnet.AspTestApp/MQTTnet.AspTestApp.csproj
+++ b/Source/MQTTnet.AspTestApp/MQTTnet.AspTestApp.csproj
@@ -9,10 +9,10 @@
false
false
1591;NETSDK1138;NU1803;NU1901;NU1902
- true
true
all
true
+ latest-Recommended
diff --git a/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj b/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj
index 4e46db45f..7bfd85cba 100644
--- a/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj
+++ b/Source/MQTTnet.AspnetCore/MQTTnet.AspNetCore.csproj
@@ -32,10 +32,10 @@
true
true
1591;NETSDK1138;NU1803;NU1901;NU1902
- true
true
all
true
+ latest-Recommended
diff --git a/Source/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj b/Source/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj
index 0d2e1857c..f1c414ea5 100644
--- a/Source/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj
+++ b/Source/MQTTnet.Benchmarks/MQTTnet.Benchmarks.csproj
@@ -10,10 +10,10 @@
false
true
1591;NETSDK1138;NU1803;NU1901;NU1902
- true
- true
+ false
all
true
+ latest-Recommended
diff --git a/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj b/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj
index a50a19a6f..b5b8eef92 100644
--- a/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj
+++ b/Source/MQTTnet.Extensions.Rpc/MQTTnet.Extensions.Rpc.csproj
@@ -31,10 +31,10 @@
true
true
1591;NETSDK1138;NU1803;NU1901;NU1902
- true
true
all
true
+ latest-Recommended
diff --git a/Source/MQTTnet.Extensions.TopicTemplate/MQTTnet.Extensions.TopicTemplate.csproj b/Source/MQTTnet.Extensions.TopicTemplate/MQTTnet.Extensions.TopicTemplate.csproj
index e74a41187..5ba711528 100644
--- a/Source/MQTTnet.Extensions.TopicTemplate/MQTTnet.Extensions.TopicTemplate.csproj
+++ b/Source/MQTTnet.Extensions.TopicTemplate/MQTTnet.Extensions.TopicTemplate.csproj
@@ -32,10 +32,10 @@
For release notes please go to MQTTnet release notes (https://www.nuget.org/packages/MQTTnet/).
true
1591;NETSDK1138;NU1803;NU1901;NU1902
- true
true
all
true
+ latest-Recommended
diff --git a/Source/MQTTnet.Extensions.TopicTemplate/MqttTopicTemplate.cs b/Source/MQTTnet.Extensions.TopicTemplate/MqttTopicTemplate.cs
index b193e22c8..3fb7215d7 100644
--- a/Source/MQTTnet.Extensions.TopicTemplate/MqttTopicTemplate.cs
+++ b/Source/MQTTnet.Extensions.TopicTemplate/MqttTopicTemplate.cs
@@ -9,336 +9,333 @@
using System.Threading;
using MQTTnet.Protocol;
-namespace MQTTnet.Extensions.TopicTemplate
+namespace MQTTnet.Extensions.TopicTemplate;
+
+///
+/// A topic template is an MQTT topic filter string that may contain
+/// segments in curly braces called parameters. This well-known
+/// 'moustache' syntax also matches AsyncAPI Channel Address Expressions.
+/// The topic template is designed to support dynamic subscription/publication,
+/// message-topic matching and routing. It is intended to be more convenient
+/// than String.Format() for aforementioned purposes.
+///
+///
+/// topic/subtopic/{parameter}/{otherParameter}
+///
+public sealed class MqttTopicTemplate : IEquatable
{
+ static readonly Regex MoustacheRegex = new("{([^/]+?)}", RegexOptions.Compiled);
+
+ readonly string[] _parameterSegments;
+
+ string _topicFilter;
+
///
- /// A topic template is an MQTT topic filter string that may contain
- /// segments in curly braces called parameters. This well-known
- /// 'moustache' syntax also matches AsyncAPI Channel Address Expressions.
- /// The topic template is designed to support dynamic subscription/publication,
- /// message-topic matching and routing. It is intended to be more convenient
- /// than String.Format() for aforementioned purposes.
+ /// Create a topic template from an mqtt topic filter with moustache placeholders.
///
- ///
- /// topic/subtopic/{parameter}/{otherParameter}
- ///
- public sealed class MqttTopicTemplate : IEquatable
+ ///
+ ///
+ ///
+ ///
+ public MqttTopicTemplate(string topicTemplate)
{
- static readonly Regex MoustacheRegex = new Regex("{([^/]+?)}", RegexOptions.Compiled);
-
- readonly string[] _parameterSegments;
-
- string _topicFilter;
-
- ///
- /// Create a topic template from an mqtt topic filter with moustache placeholders.
- ///
- ///
- ///
- ///
- ///
- public MqttTopicTemplate(string topicTemplate)
+ ArgumentNullException.ThrowIfNull(topicTemplate);
+
+ MqttTopicValidator.ThrowIfInvalidSubscribe(topicTemplate);
+
+ Template = topicTemplate;
+ _parameterSegments = topicTemplate.Split(MqttTopicFilterComparer.LevelSeparator)
+ .Select(segment => MoustacheRegex.Match(segment).Groups[1].Value)
+ .Select(s => s.Length > 0 ? s : null)
+ .ToArray();
+ }
+
+ ///
+ /// Yield the template parameter names.
+ ///
+ public IEnumerable Parameters => _parameterSegments.Where(s => s != null);
+
+ ///
+ /// The topic template string representation, e.g. A/B/{foo}/D.
+ ///
+ public string Template { get; }
+
+ ///
+ /// The topic template as an MQTT topic filter (+ substituted for all parameters). If the template
+ /// ends with a multi-level wildcard (hash), this will be reflected here.
+ ///
+ public string TopicFilter
+ {
+ get
{
- if (topicTemplate == null)
- {
- throw new ArgumentNullException(nameof(topicTemplate));
- }
-
- MqttTopicValidator.ThrowIfInvalidSubscribe(topicTemplate);
-
- Template = topicTemplate;
- _parameterSegments = topicTemplate.Split(MqttTopicFilterComparer.LevelSeparator)
- .Select(segment => MoustacheRegex.Match(segment).Groups[1].Value)
- .Select(s => s.Length > 0 ? s : null)
- .ToArray();
+ LazyInitializer.EnsureInitialized(ref _topicFilter, () => MoustacheRegex.Replace(Template, MqttTopicFilterComparer.SingleLevelWildcard.ToString()));
+ return _topicFilter;
}
-
- ///
- /// Yield the template parameter names.
- ///
- public IEnumerable Parameters => _parameterSegments.Where(s => s != null);
-
- ///
- /// The topic template string representation, e.g. A/B/{foo}/D.
- ///
- public string Template { get; }
-
- ///
- /// The topic template as an MQTT topic filter (+ substituted for all parameters). If the template
- /// ends with a multi-level wildcard (hash), this will be reflected here.
- ///
- public string TopicFilter
+ }
+
+ ///
+ /// Return the topic filter of this template, ending with a multi-level wildcard (hash).
+ ///
+ public string TopicTreeRootFilter
+ {
+ get
{
- get
+ var filter = TopicFilter;
+ // append slash if neccessary
+ if (filter.Length > 0 && !filter.EndsWith(MqttTopicFilterComparer.LevelSeparator) && !filter.EndsWith(MqttTopicFilterComparer.MultiLevelWildcard))
{
- LazyInitializer.EnsureInitialized(ref _topicFilter, () => MoustacheRegex.Replace(Template, MqttTopicFilterComparer.SingleLevelWildcard.ToString()));
- return _topicFilter;
+ filter += MqttTopicFilterComparer.LevelSeparator;
}
- }
-
- ///
- /// Return the topic filter of this template, ending with a multi-level wildcard (hash).
- ///
- public string TopicTreeRootFilter
- {
- get
+
+ // append hash if neccessary
+ if (!filter.EndsWith(MqttTopicFilterComparer.MultiLevelWildcard))
{
- var filter = TopicFilter;
- // append slash if neccessary
- if (filter.Length > 0 && !filter.EndsWith(MqttTopicFilterComparer.LevelSeparator.ToString()) &&
- !filter.EndsWith(MqttTopicFilterComparer.MultiLevelWildcard.ToString()))
- {
- filter += MqttTopicFilterComparer.LevelSeparator;
- }
-
- // append hash if neccessary
- if (!filter.EndsWith(MqttTopicFilterComparer.MultiLevelWildcard.ToString()))
- {
- filter += MqttTopicFilterComparer.MultiLevelWildcard;
- }
-
- return filter;
+ filter += MqttTopicFilterComparer.MultiLevelWildcard;
}
+
+ return filter;
}
-
- public bool Equals(MqttTopicTemplate other)
+ }
+
+ public bool Equals(MqttTopicTemplate other)
+ {
+ return other != null && Template == other.Template;
+ }
+
+ public override bool Equals(object obj)
+ {
+ if (ReferenceEquals(null, obj))
{
- return other != null && Template == other.Template;
+ return false;
}
-
- public override bool Equals(object obj)
+
+ if (ReferenceEquals(this, obj))
{
- if (ReferenceEquals(null, obj))
- {
- return false;
- }
-
- if (ReferenceEquals(this, obj))
- {
- return true;
- }
-
- if (obj.GetType() != GetType())
- {
- return false;
- }
-
- return Equals((MqttTopicTemplate)obj);
+ return true;
}
-
- ///
- /// Determine the shortest common prefix of the given templates. Partial segments
- /// are not returned.
- ///
- ///
- /// topic templates
- ///
- ///
- public static MqttTopicTemplate FindCanonicalPrefix(IEnumerable templates)
+
+ if (obj.GetType() != GetType())
{
- string root = null;
-
- string CommonPrefix(string a, string b)
+ return false;
+ }
+
+ return Equals((MqttTopicTemplate)obj);
+ }
+
+ ///
+ /// Determine the shortest common prefix of the given templates. Partial segments
+ /// are not returned.
+ ///
+ ///
+ /// topic templates
+ ///
+ ///
+ public static MqttTopicTemplate FindCanonicalPrefix(IEnumerable templates)
+ {
+ string root = null;
+
+ string CommonPrefix(string a, string b)
+ {
+ var maxIndex = Math.Min(a.Length, b.Length) - 1;
+ for (var i = 0; i <= maxIndex; i++)
{
- var maxIndex = Math.Min(a.Length, b.Length) - 1;
- for (var i = 0; i <= maxIndex; i++)
+ if (a[i] != b[i])
{
- if (a[i] != b[i])
- {
- return a.Substring(0, i);
- }
+ return a.Substring(0, i);
}
-
- return a.Substring(0, maxIndex+1);
}
-
- foreach (string topic in from template in templates select template.Template)
- {
- root = root == null ? topic : CommonPrefix(root, topic);
- }
-
- if (string.IsNullOrEmpty(root))
- return new MqttTopicTemplate(MqttTopicFilterComparer.MultiLevelWildcard.ToString());
-
- if (root.Contains(MqttTopicFilterComparer.LevelSeparator) &&
- !root.EndsWith(MqttTopicFilterComparer.LevelSeparator.ToString()) &&
- !root.EndsWith("}"))
- {
- root = root.Substring(0, root.LastIndexOf(MqttTopicFilterComparer.LevelSeparator)+1);
- }
-
- if (root.EndsWith(MqttTopicFilterComparer.LevelSeparator.ToString()))
- root += MqttTopicFilterComparer.SingleLevelWildcard;
- return new MqttTopicTemplate(root);
+ return a.Substring(0, maxIndex + 1);
}
-
- public override int GetHashCode()
+
+ foreach (var topic in from template in templates select template.Template)
{
- return Template.GetHashCode();
+ root = root == null ? topic : CommonPrefix(root, topic);
}
-
- ///
- /// Test if this topic template matches a given topic.
- ///
- ///
- /// a fully specified topic
- ///
- ///
- /// true to match including the subtree (multi-level wildcard)
- ///
- /// true iff the topic matches the template's filter
- ///
- ///
- ///
- /// if the topic is invalid
- ///
- public bool MatchesTopic(string topic, bool subtree = false)
+
+ if (string.IsNullOrEmpty(root))
{
- var comparison = MqttTopicFilterComparer.Compare(topic, subtree ? TopicTreeRootFilter : TopicFilter);
- if (comparison == MqttTopicFilterCompareResult.FilterInvalid)
- {
- throw new InvalidOperationException("Invalid filter");
- }
-
- if (comparison == MqttTopicFilterCompareResult.TopicInvalid)
- {
- throw new ArgumentException("Invalid topic", nameof(topic));
- }
-
- return comparison == MqttTopicFilterCompareResult.IsMatch;
+ return new MqttTopicTemplate(MqttTopicFilterComparer.MultiLevelWildcard.ToString());
}
-
- ///
- /// Extract the parameter values from a topic corresponding to the template
- /// parameters. The topic has to match this template.
- ///
- ///
- /// the topic
- ///
- /// an enumeration of (parameter, index, value)
- public IEnumerable<(string parameter, int index, string value)> ParseParameterValues(string topic)
+
+ if (root.Contains(MqttTopicFilterComparer.LevelSeparator) && !root.EndsWith(MqttTopicFilterComparer.LevelSeparator) && !root.EndsWith('}'))
{
- if (!MatchesTopic(topic))
- {
- throw new ArgumentException("the topic has to match this template", nameof(topic));
- }
-
- return parseParameterValuesInternal(topic);
+ root = root.Substring(0, root.LastIndexOf(MqttTopicFilterComparer.LevelSeparator) + 1);
}
-
- ///
- /// Extract the parameter values from the message topic corresponding to the template
- /// parameters. The message topic has to match this topic template.
- ///
- ///
- /// the message
- ///
- /// an enumeration of (parameter, index, value)
- public IEnumerable<(string parameter, int index, string value)> ParseParameterValues(MqttApplicationMessage message)
+
+ if (root.EndsWith(MqttTopicFilterComparer.LevelSeparator))
{
- return ParseParameterValues(message.Topic);
+ root += MqttTopicFilterComparer.SingleLevelWildcard;
}
-
- ///
- /// Try to set a parameter to a given value. If the parameter is not present,
- /// this is returned. The value must not contain slashes.
- ///
- ///
- /// a template parameter
- ///
- ///
- /// a string
- ///
- ///
- public MqttTopicTemplate TrySetParameter(string parameter, string value)
+
+ return new MqttTopicTemplate(root);
+ }
+
+ public override int GetHashCode()
+ {
+ return Template.GetHashCode();
+ }
+
+ ///
+ /// Test if this topic template matches a given topic.
+ ///
+ ///
+ /// a fully specified topic
+ ///
+ ///
+ /// true to match including the subtree (multi-level wildcard)
+ ///
+ /// true iff the topic matches the template's filter
+ ///
+ ///
+ ///
+ /// if the topic is invalid
+ ///
+ public bool MatchesTopic(string topic, bool subtree = false)
+ {
+ var comparison = MqttTopicFilterComparer.Compare(topic, subtree ? TopicTreeRootFilter : TopicFilter);
+ if (comparison == MqttTopicFilterCompareResult.FilterInvalid)
{
- if (parameter != null && _parameterSegments.Contains(parameter))
- {
- return WithParameter(parameter, value);
- }
-
- return this;
+ throw new InvalidOperationException("Invalid filter");
}
-
- ///
- /// Replace the given parameter with a single-level wildcard (plus sign).
- ///
- ///
- /// parameter name
- ///
- /// the topic template (without the parameter)
- public MqttTopicTemplate WithoutParameter(string parameter)
+
+ if (comparison == MqttTopicFilterCompareResult.TopicInvalid)
{
- return WithParameter(parameter, MqttTopicFilterComparer.SingleLevelWildcard.ToString());
+ throw new ArgumentException("Invalid topic", nameof(topic));
}
-
- ///
- /// Substitute a parameter with a given value, thus removing the parameter. If the parameter is not present,
- /// the method trows. The value must not contain slashes.
- ///
- ///
- /// a template parameter
- ///
- ///
- /// a string
- ///
- ///
- /// when the parameter is not present
- ///
- /// the topic template (without the parameter)
- public MqttTopicTemplate WithParameter(string parameter, string value)
+
+ return comparison == MqttTopicFilterCompareResult.IsMatch;
+ }
+
+ ///
+ /// Extract the parameter values from a topic corresponding to the template
+ /// parameters. The topic has to match this template.
+ ///
+ ///
+ /// the topic
+ ///
+ /// an enumeration of (parameter, index, value)
+ public IEnumerable<(string parameter, int index, string value)> ParseParameterValues(string topic)
+ {
+ if (!MatchesTopic(topic))
{
- if (value == null || string.IsNullOrEmpty(parameter) || !_parameterSegments.Contains(parameter) || value.Contains(MqttTopicFilterComparer.LevelSeparator) ||
- value.Contains(MqttTopicFilterComparer.MultiLevelWildcard))
- {
- throw new ArgumentException("parameter must exist and value must not contain slashes.");
- }
-
- var moustache = "{" + parameter + "}";
- return new MqttTopicTemplate(Template.Replace(moustache, value));
+ throw new ArgumentException("the topic has to match this template", nameof(topic));
+ }
+
+ return parseParameterValuesInternal(topic);
+ }
+
+ ///
+ /// Extract the parameter values from the message topic corresponding to the template
+ /// parameters. The message topic has to match this topic template.
+ ///
+ ///
+ /// the message
+ ///
+ /// an enumeration of (parameter, index, value)
+ public IEnumerable<(string parameter, int index, string value)> ParseParameterValues(MqttApplicationMessage message)
+ {
+ return ParseParameterValues(message.Topic);
+ }
+
+ ///
+ /// Try to set a parameter to a given value. If the parameter is not present,
+ /// this is returned. The value must not contain slashes.
+ ///
+ ///
+ /// a template parameter
+ ///
+ ///
+ /// a string
+ ///
+ ///
+ public MqttTopicTemplate TrySetParameter(string parameter, string value)
+ {
+ if (parameter != null && _parameterSegments.Contains(parameter))
+ {
+ return WithParameter(parameter, value);
}
-
- ///
- /// Reuse parameters as they are extracted using another topic template on this template
- /// when the parameter name matches. Useful
- /// for compatibility routing.
- ///
- ///
- ///
- ///
- public MqttTopicTemplate WithParameterValuesFrom(IEnumerable<(string parameter, int index, string value)> parameters)
+
+ return this;
+ }
+
+ ///
+ /// Replace the given parameter with a single-level wildcard (plus sign).
+ ///
+ ///
+ /// parameter name
+ ///
+ /// the topic template (without the parameter)
+ public MqttTopicTemplate WithoutParameter(string parameter)
+ {
+ return WithParameter(parameter, MqttTopicFilterComparer.SingleLevelWildcard.ToString());
+ }
+
+ ///
+ /// Substitute a parameter with a given value, thus removing the parameter. If the parameter is not present,
+ /// the method trows. The value must not contain slashes.
+ ///
+ ///
+ /// a template parameter
+ ///
+ ///
+ /// a string
+ ///
+ ///
+ /// when the parameter is not present
+ ///
+ /// the topic template (without the parameter)
+ public MqttTopicTemplate WithParameter(string parameter, string value)
+ {
+ if (value == null || string.IsNullOrEmpty(parameter) || !_parameterSegments.Contains(parameter) || value.Contains(MqttTopicFilterComparer.LevelSeparator) ||
+ value.Contains(MqttTopicFilterComparer.MultiLevelWildcard))
{
- return parameters.Aggregate(this, (t, p) => t.TrySetParameter(p.parameter, p.value));
+ throw new ArgumentException("parameter must exist and value must not contain slashes.");
}
-
- IEnumerable<(string parameter, int index, string value)> parseParameterValuesInternal(string topic)
+
+ var moustache = "{" + parameter + "}";
+ return new MqttTopicTemplate(Template.Replace(moustache, value));
+ }
+
+ ///
+ /// Reuse parameters as they are extracted using another topic template on this template
+ /// when the parameter name matches. Useful
+ /// for compatibility routing.
+ ///
+ ///
+ ///
+ ///
+ public MqttTopicTemplate WithParameterValuesFrom(IEnumerable<(string parameter, int index, string value)> parameters)
+ {
+ return parameters.Aggregate(this, (t, p) => t.TrySetParameter(p.parameter, p.value));
+ }
+
+ IEnumerable<(string parameter, int index, string value)> parseParameterValuesInternal(string topic)
+ {
+ // because we have a match, we know the segment array is at least the template's length
+ var segments = topic.Split(MqttTopicFilterComparer.LevelSeparator);
+ for (var i = 0; i < _parameterSegments.Length; i++)
{
- // because we have a match, we know the segment array is at least the template's length
- var segments = topic.Split(MqttTopicFilterComparer.LevelSeparator);
- for (var i = 0; i < _parameterSegments.Length; i++)
+ var name = _parameterSegments[i];
+ if (name != null)
{
- var name = _parameterSegments[i];
- if (name != null)
- {
- yield return (name, i, segments[i]);
- }
+ yield return (name, i, segments[i]);
}
}
}
diff --git a/Source/MQTTnet.Server/MQTTnet.Server.csproj b/Source/MQTTnet.Server/MQTTnet.Server.csproj
index faecf048a..514ff8acc 100644
--- a/Source/MQTTnet.Server/MQTTnet.Server.csproj
+++ b/Source/MQTTnet.Server/MQTTnet.Server.csproj
@@ -30,12 +30,12 @@
MIT
true
1591;NETSDK1138;NU1803;NU1901;NU1902
- true
true
all
true
enable
disable
+ latest-Recommended
diff --git a/Source/MQTTnet.TestApp/MQTTnet.TestApp.csproj b/Source/MQTTnet.TestApp/MQTTnet.TestApp.csproj
index 07bfc7444..f5b32a5a9 100644
--- a/Source/MQTTnet.TestApp/MQTTnet.TestApp.csproj
+++ b/Source/MQTTnet.TestApp/MQTTnet.TestApp.csproj
@@ -9,10 +9,10 @@
false
true
1591;NETSDK1138;NU1803;NU1901;NU1902
- true
true
all
true
+ latest-Recommended
diff --git a/Source/MQTTnet.Tests/MQTTnet.Tests.csproj b/Source/MQTTnet.Tests/MQTTnet.Tests.csproj
index 0caa6c33c..90a2e1d89 100644
--- a/Source/MQTTnet.Tests/MQTTnet.Tests.csproj
+++ b/Source/MQTTnet.Tests/MQTTnet.Tests.csproj
@@ -7,10 +7,10 @@
false
true
1591;NETSDK1138;NU1803;NU1901;NU1902
- true
true
all
true
+ latest-Recommended
diff --git a/Source/MQTTnet/MQTTnet.csproj b/Source/MQTTnet/MQTTnet.csproj
index f37be30c1..1d3adc6de 100644
--- a/Source/MQTTnet/MQTTnet.csproj
+++ b/Source/MQTTnet/MQTTnet.csproj
@@ -43,6 +43,7 @@
true
all
true
+ latest-Recommended