// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
using System.Diagnostics.CodeAnalysis;
using System.Diagnostics.Contracts;
using System.IO;
using System.Net.Http.Formatting;
using System.Threading.Tasks;
namespace System.Net.Http
{
///
/// Contains a value as well as an associated that will be
/// used to serialize the value when writing this content.
///
public class ObjectContent : HttpContent
{
private object _value;
private readonly MediaTypeFormatter _formatter;
///
/// Initializes a new instance of the class.
///
/// The type of object this instance will contain.
/// The value of the object this instance will contain.
/// The formatter to use when serializing the value.
public ObjectContent(Type type, object value, MediaTypeFormatter formatter)
: this(type, value, formatter, null)
{
}
///
/// Initializes a new instance of the class.
///
/// The type of object this instance will contain.
/// The value of the object this instance will contain.
/// The formatter to use when serializing the value.
/// The media type to associate with this object.
public ObjectContent(Type type, object value, MediaTypeFormatter formatter, string mediaType)
{
if (type == null)
{
throw new ArgumentNullException("type");
}
if (formatter == null)
{
throw new ArgumentNullException("formatter");
}
_formatter = formatter;
ObjectType = type;
VerifyAndSetObject(value);
_formatter.SetDefaultContentHeaders(type, Headers, mediaType);
}
///
/// Gets the type of object managed by this instance.
///
public Type ObjectType { get; private set; }
///
/// The formatter associated with this content instance.
///
public MediaTypeFormatter Formatter
{
get { return _formatter; }
}
///
/// Gets or sets the value of the current .
///
public object Value
{
get { return _value; }
set { VerifyAndSetObject(value); }
}
///
/// Asynchronously serializes the object's content to the given .
///
/// The to which to write.
/// The associated .
/// A instance that is asynchronously serializing the object's content.
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return _formatter.WriteToStreamAsync(ObjectType, Value, stream, Headers, context);
}
///
/// Computes the length of the stream if possible.
///
/// The computed length of the stream.
/// true if the length has been computed; otherwise false.
protected override bool TryComputeLength(out long length)
{
length = -1;
return false;
}
private static bool IsTypeNullable(Type type)
{
return !type.IsValueType ||
(type.IsGenericType &&
type.GetGenericTypeDefinition() == typeof(Nullable<>));
}
private void VerifyAndSetObject(object value)
{
Contract.Assert(ObjectType != null, "Type cannot be null");
if (value == null)
{
// Null may not be assigned to value types (unless Nullable)
if (!IsTypeNullable(ObjectType))
{
throw new InvalidOperationException(RS.Format(Properties.Resources.CannotUseNullValueType, typeof(ObjectContent).Name, ObjectType.Name));
}
}
else
{
// Non-null objects must be a type assignable to Type
Type objectType = value.GetType();
if (!ObjectType.IsAssignableFrom(objectType))
{
throw new ArgumentException(RS.Format(Properties.Resources.ObjectAndTypeDisagree, objectType.Name, ObjectType.Name), "value");
}
if (!_formatter.CanWriteType(objectType))
{
throw new InvalidOperationException(RS.Format(Properties.Resources.ObjectContent_FormatterCannotWriteType, _formatter.GetType().FullName, objectType.Name));
}
}
_value = value;
}
}
///
/// Generic form of .
///
/// The type of object this class will contain.
[SuppressMessage("Microsoft.StyleCop.CSharp.MaintainabilityRules", "SA1402:FileMayOnlyContainASingleClass", Justification = "Class contains generic forms")]
public class ObjectContent : ObjectContent
{
///
/// Initializes a new instance of the class.
///
/// The value of the object this instance will contain.
/// The formatter to use when serializing the value.
public ObjectContent(T value, MediaTypeFormatter formatter)
: this(value, formatter, null)
{
}
///
/// Initializes a new instance of the class.
///
/// The value of the object this instance will contain.
/// The formatter to use when serializing the value.
/// The media type to associate with this object.
public ObjectContent(T value, MediaTypeFormatter formatter, string mediaType)
: base(typeof(T), value, formatter, mediaType)
{
}
}
}