forked from aspnet/AspNetWebStack
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathObjectContent.cs
More file actions
158 lines (140 loc) · 6.47 KB
/
ObjectContent.cs
File metadata and controls
158 lines (140 loc) · 6.47 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
// 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.Diagnostics.Contracts;
using System.IO;
using System.Net.Http.Formatting;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web.Http;
namespace System.Net.Http
{
/// <summary>
/// Contains a value as well as an associated <see cref="MediaTypeFormatter"/> that will be
/// used to serialize the value when writing this content.
/// </summary>
public class ObjectContent : HttpContent
{
private object _value;
private readonly MediaTypeFormatter _formatter;
/// <summary>
/// Initializes a new instance of the <see cref="ObjectContent"/> class.
/// </summary>
/// <param name="type">The type of object this instance will contain.</param>
/// <param name="value">The value of the object this instance will contain.</param>
/// <param name="formatter">The formatter to use when serializing the value.</param>
public ObjectContent(Type type, object value, MediaTypeFormatter formatter)
: this(type, value, formatter, (MediaTypeHeaderValue)null)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ObjectContent"/> class.
/// </summary>
/// <param name="type">The type of object this instance will contain.</param>
/// <param name="value">The value of the object this instance will contain.</param>
/// <param name="formatter">The formatter to use when serializing the value.</param>
/// <param name="mediaType">The authoritative value of the content's Content-Type header. Can be <c>null</c> in which case the
/// <paramref name="formatter">formatter's</paramref> default content type will be used.</param>
public ObjectContent(Type type, object value, MediaTypeFormatter formatter, string mediaType)
: this(type, value, formatter, BuildHeaderValue(mediaType))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ObjectContent"/> class.
/// </summary>
/// <param name="type">The type of object this instance will contain.</param>
/// <param name="value">The value of the object this instance will contain.</param>
/// <param name="formatter">The formatter to use when serializing the value.</param>
/// <param name="mediaType">The authoritative value of the content's Content-Type header. Can be <c>null</c> in which case the
/// <paramref name="formatter">formatter's</paramref> default content type will be used.</param>
public ObjectContent(Type type, object value, MediaTypeFormatter formatter, MediaTypeHeaderValue mediaType)
{
if (type == null)
{
throw Error.ArgumentNull("type");
}
if (formatter == null)
{
throw Error.ArgumentNull("formatter");
}
if (!formatter.CanWriteType(type))
{
throw Error.InvalidOperation(Properties.Resources.ObjectContent_FormatterCannotWriteType, formatter.GetType().FullName, type.Name);
}
_formatter = formatter;
ObjectType = type;
VerifyAndSetObject(value);
_formatter.SetDefaultContentHeaders(type, Headers, mediaType);
}
/// <summary>
/// Gets the type of object managed by this <see cref="ObjectContent"/> instance.
/// </summary>
public Type ObjectType { get; private set; }
/// <summary>
/// The <see cref="MediaTypeFormatter">formatter</see> associated with this content instance.
/// </summary>
public MediaTypeFormatter Formatter
{
get { return _formatter; }
}
/// <summary>
/// Gets or sets the value of the current <see cref="ObjectContent"/>.
/// </summary>
public object Value
{
get { return _value; }
set { _value = value; }
}
internal static MediaTypeHeaderValue BuildHeaderValue(string mediaType)
{
return mediaType != null ? new MediaTypeHeaderValue(mediaType) : null;
}
/// <summary>
/// Asynchronously serializes the object's content to the given <paramref name="stream"/>.
/// </summary>
/// <param name="stream">The <see cref="Stream"/> to which to write.</param>
/// <param name="context">The associated <see cref="TransportContext"/>.</param>
/// <returns>A <see cref="Task"/> instance that is asynchronously serializing the object's content.</returns>
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
return _formatter.WriteToStreamAsync(ObjectType, Value, stream, this, context);
}
/// <summary>
/// Computes the length of the stream if possible.
/// </summary>
/// <param name="length">The computed length of the stream.</param>
/// <returns><c>true</c> if the length has been computed; otherwise <c>false</c>.</returns>
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<T>)
if (!IsTypeNullable(ObjectType))
{
throw Error.InvalidOperation(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 Error.Argument("value", Properties.Resources.ObjectAndTypeDisagree, objectType.Name, ObjectType.Name);
}
}
_value = value;
}
}
}