// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. using System; using System.Diagnostics.Contracts; using System.IO; using System.Net.Http; using System.Net.Http.Formatting; using System.Net.Http.Headers; using System.Threading.Tasks; using System.Web.Http; namespace Microsoft.AspNet.Mvc { /// /// 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, (MediaTypeHeaderValue)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 authoritative value of the content's Content-Type header. Can be null in which case the /// formatter's default content type will be used. public ObjectContent(Type type, object value, MediaTypeFormatter formatter, string mediaType) : this(type, value, formatter, BuildHeaderValue(mediaType)) { } /// /// 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 authoritative value of the content's Content-Type header. Can be null in which case the /// formatter's default content type will be used. public ObjectContent(Type type, object value, MediaTypeFormatter formatter, MediaTypeHeaderValue mediaType) { if (type == null) { throw new ArgumentNullException("type"); } if (formatter == null) { throw new ArgumentNullException("formatter"); } if (!formatter.CanWriteType(type)) { throw new ArgumentNullException(formatter.GetType().FullName + " cannot write " + type.Name); } _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 { _value = value; } } internal static MediaTypeHeaderValue BuildHeaderValue(string mediaType) { return mediaType != null ? new MediaTypeHeaderValue(mediaType) : null; } /// /// 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, System.Net.TransportContext context) { return _formatter.WriteToStreamAsync(ObjectType, Value, stream, this, 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("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("value Resources.ObjectAndTypeDisagree, objectType.Name, ObjectType.Name"); } } _value = value; } } }