This repository has been archived by the owner on Aug 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added generic Service Bus serializer (#70)
Added `BrokedMessageSerializer`, a JSON serializer that enforces versioned schemas. Updated the `PackageValidationMessageData` serializer to use this new serializer. This will be used by `PackageSigningValidator` and `PackageCertificatesValidator` to queue messages to their downstream validation jobs. NOTE: The `BrokedMessageSerializer` does not gracefully handle messages with a different version that what is expected. This will have to be added in later.
- Loading branch information
1 parent
2b04171
commit 6506885
Showing
11 changed files
with
336 additions
and
84 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
src/NuGet.Services.ServiceBus/BrokeredMessageSerializer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using Newtonsoft.Json; | ||
|
||
namespace NuGet.Services.ServiceBus | ||
{ | ||
/// <summary> | ||
/// Serializes objects into Service Bus <see cref="IBrokeredMessage"/>. This serializer will | ||
/// throw <see cref="FormatException"/> if the message does not contain a message with the expected | ||
/// type and schema version. | ||
/// </summary> | ||
/// <typeparam name="TMessage">A type decorated with a <see cref="SchemaAttribute"/>.</typeparam> | ||
public class BrokeredMessageSerializer<TMessage> | ||
{ | ||
private const string SchemaNameKey = "SchemaName"; | ||
private const string SchemaVersionKey = "SchemaVersion"; | ||
|
||
private static readonly string SchemaName; | ||
private static readonly int SchemaVersion; | ||
|
||
static BrokeredMessageSerializer() | ||
{ | ||
var attributes = typeof(TMessage).GetCustomAttributes(typeof(SchemaAttribute), inherit: false); | ||
|
||
if (attributes.Length != 1) | ||
{ | ||
throw new InvalidOperationException($"{typeof(TMessage)} must have exactly one {nameof(SchemaAttribute)}"); | ||
} | ||
|
||
var schemaAttribute = (SchemaAttribute)attributes[0]; | ||
|
||
SchemaName = schemaAttribute.Name; | ||
SchemaVersion = schemaAttribute.Version; | ||
} | ||
|
||
public IBrokeredMessage Serialize(TMessage message) | ||
{ | ||
var json = JsonConvert.SerializeObject(message); | ||
var brokeredMessage = new BrokeredMessageWrapper(json); | ||
|
||
brokeredMessage.Properties[SchemaNameKey] = SchemaName; | ||
brokeredMessage.Properties[SchemaVersionKey] = SchemaVersion; | ||
|
||
return brokeredMessage; | ||
} | ||
|
||
public TMessage Deserialize(IBrokeredMessage message) | ||
{ | ||
AssertTypeAndSchemaVersion(message, SchemaName, SchemaVersion); | ||
|
||
return JsonConvert.DeserializeObject<TMessage>(message.GetBody()); | ||
} | ||
|
||
private static void AssertTypeAndSchemaVersion(IBrokeredMessage message, string type, int schemaVersion) | ||
{ | ||
if (GetType(message) != type) | ||
{ | ||
throw new FormatException($"The provided message should have {SchemaNameKey} property '{type}'."); | ||
} | ||
|
||
if (GetSchemaVersion(message) != schemaVersion) | ||
{ | ||
throw new FormatException($"The provided message should have {SchemaVersionKey} property '{schemaVersion}'."); | ||
} | ||
} | ||
|
||
private static int GetSchemaVersion(IBrokeredMessage message) | ||
{ | ||
return GetProperty<int>(message, SchemaVersionKey, "an integer"); | ||
} | ||
|
||
private static string GetType(IBrokeredMessage message) | ||
{ | ||
return GetProperty<string>(message, SchemaNameKey, "a string"); | ||
} | ||
|
||
private static T GetProperty<T>(IBrokeredMessage message, string key, string typeLabel) | ||
{ | ||
object value; | ||
if (!message.Properties.TryGetValue(key, out value)) | ||
{ | ||
throw new FormatException($"The provided message does not have a {key} property."); | ||
} | ||
|
||
if (!(value is T)) | ||
{ | ||
throw new FormatException($"The provided message contains a {key} property that is not {typeLabel}."); | ||
} | ||
|
||
return (T)value; | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
// Copyright (c) .NET Foundation. All rights reserved. | ||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. | ||
|
||
using System; | ||
|
||
namespace NuGet.Services.ServiceBus | ||
{ | ||
/// <summary> | ||
/// The attribute used to define a schema. | ||
/// </summary> | ||
public class SchemaAttribute : Attribute | ||
{ | ||
/// <summary> | ||
/// The name of a message's schema. This should NEVER change for a single message. | ||
/// </summary> | ||
public string Name { get; set; } | ||
|
||
/// <summary> | ||
/// The schema's version. This should be bumped whenever a schema's property | ||
/// is added, removed, or modified. | ||
/// </summary> | ||
public int Version { get; set; } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.