|
2 | 2 | // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. |
3 | 3 |
|
4 | 4 | using System.Collections.Generic; |
5 | | -using System.Linq; |
6 | 5 | using System.Threading.Tasks; |
7 | 6 | using Microsoft.AspNet.Mvc.HeaderValueAbstractions; |
8 | 7 | using Microsoft.Framework.DependencyInjection; |
9 | 8 |
|
10 | 9 | namespace Microsoft.AspNet.Mvc |
11 | 10 | { |
| 11 | + /// <summary> |
| 12 | + /// An action result which formats the given object as JSON. |
| 13 | + /// </summary> |
12 | 14 | public class JsonResult : ActionResult |
13 | 15 | { |
14 | | - private static readonly IList<MediaTypeHeaderValue> _defaultSupportedContentTypes = |
15 | | - new List<MediaTypeHeaderValue>() |
16 | | - { |
17 | | - MediaTypeHeaderValue.Parse("application/json"), |
18 | | - MediaTypeHeaderValue.Parse("text/json"), |
19 | | - }; |
20 | | - private IOutputFormatter _defaultFormatter; |
21 | | - |
22 | | - private ObjectResult _objectResult; |
23 | | - |
24 | | - public JsonResult(object data) : |
25 | | - this(data, null) |
| 16 | + private static readonly MediaTypeHeaderValue[] _defaultSupportedContentTypes = new MediaTypeHeaderValue[] |
26 | 17 | { |
27 | | - } |
| 18 | + MediaTypeHeaderValue.Parse("application/json"), |
| 19 | + MediaTypeHeaderValue.Parse("text/json"), |
| 20 | + }; |
28 | 21 |
|
29 | 22 | /// <summary> |
30 | | - /// Creates an instance of <see cref="JsonResult"/> class. |
| 23 | + /// Creates a new <see cref="JsonResult"/> with the given <paramref name="data"/>. |
31 | 24 | /// </summary> |
32 | | - /// <param name="data"></param> |
33 | | - /// <param name="defaultFormatter">If no matching formatter is found, |
34 | | - /// the response is written to using defaultFormatter.</param> |
35 | | - /// <remarks> |
36 | | - /// The default formatter must be able to handle either application/json |
37 | | - /// or text/json. |
38 | | - /// </remarks> |
39 | | - public JsonResult(object data, IOutputFormatter defaultFormatter) |
| 25 | + /// <param name="value">The value to format as JSON.</param> |
| 26 | + public JsonResult(object value) |
| 27 | + : this(value, null) |
40 | 28 | { |
41 | | - _defaultFormatter = defaultFormatter; |
42 | | - _objectResult = new ObjectResult(data); |
43 | 29 | } |
44 | 30 |
|
45 | | - public object Value |
| 31 | + /// <summary> |
| 32 | + /// Creates a new <see cref="JsonResult"/> with the given <paramref name="data"/>. |
| 33 | + /// </summary> |
| 34 | + /// <param name="value">The value to format as JSON.</param> |
| 35 | + /// <param name="formatter">The formatter to use, or <c>null</c> to choose a formatter dynamically.</param> |
| 36 | + public JsonResult(object value, IOutputFormatter formatter) |
46 | 37 | { |
47 | | - get |
48 | | - { |
49 | | - return _objectResult.Value; |
50 | | - } |
51 | | - set |
52 | | - { |
53 | | - _objectResult.Value = value; |
54 | | - } |
55 | | - } |
| 38 | + Value = value; |
| 39 | + Formatter = formatter; |
56 | 40 |
|
57 | | - public IList<MediaTypeHeaderValue> ContentTypes |
58 | | - { |
59 | | - get |
60 | | - { |
61 | | - return _objectResult.ContentTypes; |
62 | | - } |
63 | | - set |
64 | | - { |
65 | | - _objectResult.ContentTypes = value; |
66 | | - } |
| 41 | + ContentTypes = new List<MediaTypeHeaderValue>(); |
67 | 42 | } |
68 | 43 |
|
| 44 | + /// <summary> |
| 45 | + /// Gets or sets the list of supported Content-Types. |
| 46 | + /// </summary> |
| 47 | + public IList<MediaTypeHeaderValue> ContentTypes { get; set; } |
| 48 | + |
| 49 | + /// <summary> |
| 50 | + /// Gets or sets the formatter. |
| 51 | + /// </summary> |
| 52 | + public IOutputFormatter Formatter { get; set; } |
| 53 | + |
| 54 | + /// <summary> |
| 55 | + /// Gets or sets the value to be formatted. |
| 56 | + /// </summary> |
| 57 | + public object Value { get; set; } |
| 58 | + |
| 59 | + /// <inheritdoc /> |
69 | 60 | public override async Task ExecuteResultAsync([NotNull] ActionContext context) |
70 | 61 | { |
| 62 | + var objectResult = new ObjectResult(Value); |
| 63 | + |
71 | 64 | // Set the content type explicitly to application/json and text/json. |
72 | 65 | // if the user has not already set it. |
73 | 66 | if (ContentTypes == null || ContentTypes.Count == 0) |
74 | 67 | { |
75 | | - ContentTypes = _defaultSupportedContentTypes; |
| 68 | + objectResult.ContentTypes = _defaultSupportedContentTypes; |
| 69 | + } |
| 70 | + else |
| 71 | + { |
| 72 | + objectResult.ContentTypes = ContentTypes; |
76 | 73 | } |
77 | 74 |
|
78 | 75 | var formatterContext = new OutputFormatterContext() |
79 | 76 | { |
80 | | - DeclaredType = _objectResult.DeclaredType, |
81 | 77 | ActionContext = context, |
82 | 78 | Object = Value, |
83 | 79 | }; |
84 | 80 |
|
85 | | - // Need to call this instead of directly calling _objectResult.ExecuteResultAsync |
86 | | - // as that sets the status to 406 if a formatter is not found. |
87 | | - // this can be cleaned up after https://github.com/aspnet/Mvc/issues/941 gets resolved. |
88 | | - var formatter = SelectFormatter(formatterContext); |
| 81 | + var formatter = SelectFormatter(objectResult, formatterContext); |
89 | 82 | await formatter.WriteAsync(formatterContext); |
90 | 83 | } |
91 | 84 |
|
92 | | - private IOutputFormatter SelectFormatter(OutputFormatterContext formatterContext) |
| 85 | + private IOutputFormatter SelectFormatter(ObjectResult objectResult, OutputFormatterContext formatterContext) |
93 | 86 | { |
94 | | - var defaultFormatters = formatterContext.ActionContext |
95 | | - .HttpContext |
96 | | - .RequestServices |
97 | | - .GetRequiredService<IOutputFormattersProvider>() |
98 | | - .OutputFormatters; |
99 | | - |
100 | | - var formatter = _objectResult.SelectFormatter(formatterContext, defaultFormatters); |
101 | | - if (formatter == null) |
| 87 | + if (Formatter == null) |
102 | 88 | { |
103 | | - formatter = _defaultFormatter ?? formatterContext.ActionContext |
104 | | - .HttpContext |
105 | | - .RequestServices |
106 | | - .GetRequiredService<JsonOutputFormatter>(); |
107 | | - } |
| 89 | + // If no formatter was provided, then run Conneg with the formatters configured in options. |
| 90 | + var formatters = formatterContext |
| 91 | + .ActionContext |
| 92 | + .HttpContext |
| 93 | + .RequestServices |
| 94 | + .GetRequiredService<IOutputFormattersProvider>() |
| 95 | + .OutputFormatters; |
| 96 | + |
| 97 | + var formatter = objectResult.SelectFormatter(formatterContext, formatters); |
| 98 | + if (formatter == null) |
| 99 | + { |
| 100 | + // If the available user-configured formatters can't write this type, then fall back to the |
| 101 | + // 'global' one. |
| 102 | + formatter = formatterContext |
| 103 | + .ActionContext |
| 104 | + .HttpContext |
| 105 | + .RequestServices |
| 106 | + .GetRequiredService<JsonOutputFormatter>(); |
| 107 | + |
| 108 | + // Run SelectFormatter again to try to choose a content type that this formatter can do. |
| 109 | + objectResult.SelectFormatter(formatterContext, new[] { formatter }); |
| 110 | + } |
108 | 111 |
|
109 | | - return formatter; |
| 112 | + return formatter; |
| 113 | + } |
| 114 | + else |
| 115 | + { |
| 116 | + // Run SelectFormatter to try to choose a content type that this formatter can do. |
| 117 | + objectResult.SelectFormatter(formatterContext, new[] { Formatter }); |
| 118 | + return Formatter; |
| 119 | + } |
110 | 120 | } |
111 | 121 | } |
112 | 122 | } |
0 commit comments