Skip to content

Instantly share code, notes, and snippets.

@MarcAssmann
Last active July 6, 2016 08:49
Show Gist options
  • Save MarcAssmann/ed732c68702a556c40e68f6aff501783 to your computer and use it in GitHub Desktop.
Save MarcAssmann/ed732c68702a556c40e68f6aff501783 to your computer and use it in GitHub Desktop.
Modified BsonDomWriter to use to log complex data to MongoDB via NLog as outlined in https://github.com/loresoft/NLog.Mongo/issues/5#issuecomment-70413337
#region License
// Copyright (c) 2007 James Newton-King
//
// 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 System;
using System.Collections.Generic;
using System.Globalization;
namespace Newtonsoft.Json.Bson {
/// <summary>
/// Represents a writer that provides a fast, non-cached, forward-only way of generating JSON data.
/// </summary>
public class BsonDomWriter : JsonWriter {
Stack<MongoDB.Bson.BsonValue> _stack = new Stack<MongoDB.Bson.BsonValue>();
private string _propertyName;
public MongoDB.Bson.BsonValue DomRoot {
get {
return _stack.Peek();
}
}
/// <summary>
/// Initializes a new instance of the <see cref="BsonDomWriter"/> class.
/// </summary>
public BsonDomWriter() {
}
/// <summary>
/// Writes the end.
/// </summary>
/// <param name="token">The token.</param>
protected override void WriteEnd(JsonToken token) {
base.WriteEnd(token);
RemoveParent();
}
/// <summary>
/// Writes out a comment <code>/*...*/</code> containing the specified text.
/// </summary>
/// <param name="text">Text to place inside the comment.</param>
public override void WriteComment(string text) {
throw new InvalidOperationException("Cannot write JSON comment as BSON.");
}
/// <summary>
/// Writes the start of a constructor with the given name.
/// </summary>
/// <param name="name">The name of the constructor.</param>
public override void WriteStartConstructor(string name) {
throw new InvalidOperationException("Cannot write JSON constructor as BSON.");
}
/// <summary>
/// Writes raw JSON.
/// </summary>
/// <param name="json">The raw JSON to write.</param>
public override void WriteRaw(string json) {
throw new InvalidOperationException("Cannot write raw JSON as BSON.");
}
/// <summary>
/// Writes raw JSON where a value is expected and updates the writer's state.
/// </summary>
/// <param name="json">The raw JSON to write.</param>
public override void WriteRawValue(string json) {
throw new InvalidOperationException("Cannot write raw JSON as BSON.");
}
/// <summary>
/// Writes the beginning of a Json array.
/// </summary>
public override void WriteStartArray() {
base.WriteStartArray();
AddParent(new MongoDB.Bson.BsonArray());
}
/// <summary>
/// Writes the beginning of a Json object.
/// </summary>
public override void WriteStartObject() {
base.WriteStartObject();
AddParent(new MongoDB.Bson.BsonDocument());
}
/// <summary>
/// Writes the property name of a name/value pair on a Json object.
/// </summary>
/// <param name="name">The name of the property.</param>
public override void WritePropertyName(string name) {
base.WritePropertyName(name);
_propertyName = name;
}
/// <summary>
/// Closes this stream and the underlying stream.
/// </summary>
public override void Close() {
base.Close();
}
private void AddParent(MongoDB.Bson.BsonDocument doc) {
AddToken(doc);
_stack.Push(doc);
}
private void AddParent(MongoDB.Bson.BsonArray array) {
AddToken(array);
_stack.Push(array);
}
private void RemoveParent() {
if (_stack.Count > 1) {
_stack.Pop();
}
}
internal void AddToken(MongoDB.Bson.BsonValue token) {
if (_stack.Count > 0) {
var itemOnStack = _stack.Peek();
if (itemOnStack is MongoDB.Bson.BsonDocument) {
((MongoDB.Bson.BsonDocument)itemOnStack).Add(_propertyName, token);
//_propertyName = null;
} else {
((MongoDB.Bson.BsonArray)itemOnStack).Add(token);
}
} else {
if (!(token is MongoDB.Bson.BsonDocument) && !(token is MongoDB.Bson.BsonArray))
throw new InvalidOperationException("Error writing " + token.BsonType + " value. BSON must start with an Object or Array.");
//_stack.Push(token);
}
}
#region WriteValue methods
/// <summary>
/// Writes a <see cref="Object"/> value.
/// An error will raised if the value cannot be written as a single JSON token.
/// </summary>
/// <param name="value">The <see cref="Object"/> value to write.</param>
public override void WriteValue(object value) {
base.WriteValue(value);
AddToken(MongoDB.Bson.BsonValue.Create(value));
}
/// <summary>
/// Writes a null value.
/// </summary>
public override void WriteNull() {
base.WriteNull();
AddToken(MongoDB.Bson.BsonNull.Value);
}
/// <summary>
/// Writes an undefined value.
/// </summary>
public override void WriteUndefined() {
base.WriteUndefined();
AddToken(MongoDB.Bson.BsonUndefined.Value);
}
/// <summary>
/// Writes a <see cref="String"/> value.
/// </summary>
/// <param name="value">The <see cref="String"/> value to write.</param>
public override void WriteValue(string value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonString(value));
}
/// <summary>
/// Writes a <see cref="Int32"/> value.
/// </summary>
/// <param name="value">The <see cref="Int32"/> value to write.</param>
public override void WriteValue(int value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonInt32(value));
}
/// <summary>
/// Writes a <see cref="UInt32"/> value.
/// </summary>
/// <param name="value">The <see cref="UInt32"/> value to write.</param>
[CLSCompliant(false)]
public override void WriteValue(uint value) {
base.WriteValue(value);
if (value > int.MaxValue)
throw new InvalidOperationException("Value is too large to fit in a signed 32 bit integer. BSON does not support unsigned values.");
AddToken(new MongoDB.Bson.BsonInt32((int)value));
}
/// <summary>
/// Writes a <see cref="Int64"/> value.
/// </summary>
/// <param name="value">The <see cref="Int64"/> value to write.</param>
public override void WriteValue(long value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonInt64(value));
}
/// <summary>
/// Writes a <see cref="UInt64"/> value.
/// </summary>
/// <param name="value">The <see cref="UInt64"/> value to write.</param>
[CLSCompliant(false)]
public override void WriteValue(ulong value) {
base.WriteValue(value);
if (value > long.MaxValue)
throw new InvalidOperationException("Value is too large to fit in a signed 64 bit integer. BSON does not support unsigned values.");
AddToken(new MongoDB.Bson.BsonInt64((long)value));
}
/// <summary>
/// Writes a <see cref="Single"/> value.
/// </summary>
/// <param name="value">The <see cref="Single"/> value to write.</param>
public override void WriteValue(float value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonDouble(value));
}
/// <summary>
/// Writes a <see cref="Double"/> value.
/// </summary>
/// <param name="value">The <see cref="Double"/> value to write.</param>
public override void WriteValue(double value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonDouble(value));
}
/// <summary>
/// Writes a <see cref="Boolean"/> value.
/// </summary>
/// <param name="value">The <see cref="Boolean"/> value to write.</param>
public override void WriteValue(bool value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonBoolean(value));
}
/// <summary>
/// Writes a <see cref="Int16"/> value.
/// </summary>
/// <param name="value">The <see cref="Int16"/> value to write.</param>
public override void WriteValue(short value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonInt32(value));
}
/// <summary>
/// Writes a <see cref="UInt16"/> value.
/// </summary>
/// <param name="value">The <see cref="UInt16"/> value to write.</param>
[CLSCompliant(false)]
public override void WriteValue(ushort value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonInt32(value));
}
/// <summary>
/// Writes a <see cref="Char"/> value.
/// </summary>
/// <param name="value">The <see cref="Char"/> value to write.</param>
public override void WriteValue(char value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonString(value.ToString(CultureInfo.InvariantCulture)));
}
/// <summary>
/// Writes a <see cref="Byte"/> value.
/// </summary>
/// <param name="value">The <see cref="Byte"/> value to write.</param>
public override void WriteValue(byte value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonInt32(value));
}
/// <summary>
/// Writes a <see cref="SByte"/> value.
/// </summary>
/// <param name="value">The <see cref="SByte"/> value to write.</param>
[CLSCompliant(false)]
public override void WriteValue(sbyte value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonInt32(value));
}
/// <summary>
/// Writes a <see cref="Decimal"/> value.
/// </summary>
/// <param name="value">The <see cref="Decimal"/> value to write.</param>
public override void WriteValue(decimal value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonDouble((double)value));
}
/// <summary>
/// Writes a <see cref="DateTime"/> value.
/// </summary>
/// <param name="value">The <see cref="DateTime"/> value to write.</param>
public override void WriteValue(DateTime value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonDateTime(value));
}
/// <summary>
/// Writes a <see cref="DateTimeOffset"/> value.
/// </summary>
/// <param name="value">The <see cref="DateTimeOffset"/> value to write.</param>
public override void WriteValue(DateTimeOffset value) {
base.WriteValue(value);
AddToken(MongoDB.Bson.BsonValue.Create(value));
}
/// <summary>
/// Writes a <see cref="Byte"/>[] value.
/// </summary>
/// <param name="value">The <see cref="Byte"/>[] value to write.</param>
public override void WriteValue(byte[] value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonBinaryData(value));
}
/// <summary>
/// Writes a <see cref="Guid"/> value.
/// </summary>
/// <param name="value">The <see cref="Guid"/> value to write.</param>
public override void WriteValue(Guid value) {
base.WriteValue(value);
byte[] bytes = MongoDB.Bson.GuidConverter.ToBytes(value, MongoDB.Bson.GuidRepresentation.Standard);
AddToken(MongoDB.Bson.BsonValue.Create(bytes));
}
/// <summary>
/// Writes a <see cref="TimeSpan"/> value.
/// </summary>
/// <param name="value">The <see cref="TimeSpan"/> value to write.</param>
public override void WriteValue(TimeSpan value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonString(value.ToString()));
}
/// <summary>
/// Writes a <see cref="Uri"/> value.
/// </summary>
/// <param name="value">The <see cref="Uri"/> value to write.</param>
public override void WriteValue(Uri value) {
base.WriteValue(value);
AddToken(new MongoDB.Bson.BsonString(value.ToString()));
}
#endregion
/// <summary>
/// Writes a <see cref="Byte"/>[] value that represents a BSON object id.
/// </summary>
/// <param name="value">The Object ID value to write.</param>
public void WriteObjectId(byte[] value) {
if (value == null)
throw new ArgumentNullException("value");
if (value.Length != 12)
throw new InvalidOperationException("An object id must be 12 bytes");
AddToken(new MongoDB.Bson.ObjectId(value));
}
/// <summary>
/// Writes a BSON regex.
/// </summary>
/// <param name="pattern">The regex pattern.</param>
/// <param name="options">The regex options.</param>
public void WriteRegex(string pattern, string options) {
if (pattern == null)
throw new ArgumentNullException("pattern");
AddToken(new MongoDB.Bson.BsonRegularExpression(pattern, options));
}
public override void Flush() {
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment