PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/WCFWebApi/src/Microsoft.Net.Http.Formatting/System/Net/Http/Formatting/MediaTypeFormatter.cs

#
C# | 619 lines | 414 code | 84 blank | 121 comment | 109 complexity | 4aa6771ffe6a509e4b160df87c0f50ba MD5 | raw file
Possible License(s): CC-BY-SA-3.0, Apache-2.0
  1. // <copyright>
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. // </copyright>
  4. namespace System.Net.Http.Formatting
  5. {
  6. using System;
  7. using System.Collections.Concurrent;
  8. using System.Collections.Generic;
  9. using System.Collections.ObjectModel;
  10. using System.Diagnostics.Contracts;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Net;
  14. using System.Net.Http;
  15. using System.Net.Http.Headers;
  16. using System.Reflection;
  17. using System.Text;
  18. using System.Threading.Tasks;
  19. /// <summary>
  20. /// Base class to handle serializing and deserializing strongly-typed objects using <see cref="ObjectContent"/>.
  21. /// </summary>
  22. public abstract class MediaTypeFormatter
  23. {
  24. private static ConcurrentDictionary<Type, Type> delegatingEnumerableCache = new ConcurrentDictionary<Type, Type>();
  25. private static ConcurrentDictionary<Type, ConstructorInfo> delegatingEnumerableConstructorCache = new ConcurrentDictionary<Type, ConstructorInfo>();
  26. /// <summary>
  27. /// Initializes a new instance of the <see cref="MediaTypeFormatter"/> class.
  28. /// </summary>
  29. protected MediaTypeFormatter()
  30. {
  31. this.SupportedMediaTypes = new MediaTypeHeaderValueCollection();
  32. this.MediaTypeMappings = new Collection<MediaTypeMapping>();
  33. }
  34. /// <summary>
  35. /// Gets the mutable collection of <see cref="MediaTypeHeaderValue"/> elements supported by
  36. /// this <see cref="MediaTypeFormatter"/> instance.
  37. /// </summary>
  38. public Collection<MediaTypeHeaderValue> SupportedMediaTypes { get; private set; }
  39. /// <summary>
  40. /// Gets the mutable collection of <see cref="MediaTypeMapping"/> elements used
  41. /// by this <see cref="MediaTypeFormatter"/> instance to determine the
  42. /// <see cref="MediaTypeHeaderValue"/> of requests or responses.
  43. /// </summary>
  44. public Collection<MediaTypeMapping> MediaTypeMappings { get; private set; }
  45. /// <summary>
  46. /// Gets a value indicating whether this instance is modified from the default settings.
  47. /// </summary>
  48. /// <value>
  49. /// <c>true</c> if this instance is modified; otherwise, <c>false</c>.
  50. /// </value>
  51. internal virtual bool IsModified
  52. {
  53. get
  54. {
  55. return false;
  56. }
  57. }
  58. /// <summary>
  59. /// Gets or sets the <see cref="Encoding"/> to use when reading and writing data.
  60. /// </summary>
  61. /// <value>
  62. /// The <see cref="Encoding"/> to use when reading and writing data.
  63. /// </value>
  64. protected Encoding Encoding { get; set; }
  65. // If the type is IEnumerable<T> or an interface type implementing it, a DelegatingEnumerable<T> type is cached for use at serialization time.
  66. internal static bool TryGetDelegatingTypeForIEnumerableGenericOrSame(ref Type type)
  67. {
  68. if (type != null
  69. && type.IsInterface
  70. && type.IsGenericType
  71. && (type.GetInterface(FormattingUtilities.EnumerableInterfaceGenericType.FullName) != null
  72. || type.GetGenericTypeDefinition().Equals(FormattingUtilities.EnumerableInterfaceGenericType)))
  73. {
  74. type = GetOrAddDelegatingType(type);
  75. return true;
  76. }
  77. return false;
  78. }
  79. // If the type is IQueryable<T> or an interface type implementing it, a DelegatingEnumerable<T> type is cached for use at serialization time.
  80. internal static bool TryGetDelegatingTypeForIQueryableGenericOrSame(ref Type type)
  81. {
  82. if (type != null
  83. && type.IsInterface
  84. && type.IsGenericType
  85. && (type.GetInterface(FormattingUtilities.QueryableInterfaceGenericType.FullName) != null
  86. || type.GetGenericTypeDefinition().Equals(FormattingUtilities.QueryableInterfaceGenericType)))
  87. {
  88. type = GetOrAddDelegatingType(type);
  89. return true;
  90. }
  91. return false;
  92. }
  93. internal static ConstructorInfo GetTypeRemappingConstructor(Type type)
  94. {
  95. ConstructorInfo constructorInfo = null;
  96. delegatingEnumerableConstructorCache.TryGetValue(type, out constructorInfo);
  97. return constructorInfo;
  98. }
  99. internal bool CanReadAs(Type type, HttpContent content)
  100. {
  101. if (type == null)
  102. {
  103. throw new ArgumentNullException("type");
  104. }
  105. if (content == null)
  106. {
  107. throw new ArgumentNullException("content");
  108. }
  109. if (!this.CanReadType(type))
  110. {
  111. return false;
  112. }
  113. // Content type must be set and must be supported
  114. MediaTypeHeaderValue mediaType = content.Headers.ContentType;
  115. MediaTypeMatch mediaTypeMatch = null;
  116. return mediaType == null ? false : this.TryMatchSupportedMediaType(mediaType, out mediaTypeMatch);
  117. }
  118. internal bool CanWriteAs(Type type, HttpContent content, out MediaTypeHeaderValue mediaType)
  119. {
  120. if (type == null)
  121. {
  122. throw new ArgumentNullException("type");
  123. }
  124. if (content == null)
  125. {
  126. throw new ArgumentNullException("content");
  127. }
  128. if (!this.CanWriteType(type))
  129. {
  130. mediaType = null;
  131. return false;
  132. }
  133. // Content type must be set and must be supported
  134. mediaType = content.Headers.ContentType;
  135. MediaTypeMatch mediaTypeMatch = null;
  136. return mediaType != null && this.TryMatchSupportedMediaType(mediaType, out mediaTypeMatch);
  137. }
  138. internal bool CanReadAs(Type type, HttpRequestMessage request)
  139. {
  140. if (type == null)
  141. {
  142. throw new ArgumentNullException("type");
  143. }
  144. if (request == null)
  145. {
  146. throw new ArgumentNullException("request");
  147. }
  148. if (!this.CanReadType(type))
  149. {
  150. return false;
  151. }
  152. // Content type must be set and must be supported
  153. MediaTypeHeaderValue mediaType = request.Content.Headers.ContentType;
  154. MediaTypeMatch mediaTypeMatch = null;
  155. return mediaType != null && this.TryMatchSupportedMediaType(mediaType, out mediaTypeMatch);
  156. }
  157. internal bool CanWriteAs(Type type, HttpRequestMessage request, out MediaTypeHeaderValue mediaType)
  158. {
  159. if (type == null)
  160. {
  161. throw new ArgumentNullException("type");
  162. }
  163. if (request == null)
  164. {
  165. throw new ArgumentNullException("request");
  166. }
  167. mediaType = null;
  168. if (!this.CanWriteType(type))
  169. {
  170. return false;
  171. }
  172. mediaType = request.Content.Headers.ContentType;
  173. MediaTypeMatch mediaTypeMatch = null;
  174. if (mediaType != null)
  175. {
  176. if (this.TryMatchSupportedMediaType(mediaType, out mediaTypeMatch))
  177. {
  178. return true;
  179. }
  180. }
  181. else
  182. {
  183. if (this.TryMatchMediaTypeMapping(request, out mediaTypeMatch))
  184. {
  185. return true;
  186. }
  187. }
  188. mediaType = null;
  189. return false;
  190. }
  191. internal bool CanReadAs(Type type, HttpResponseMessage response)
  192. {
  193. if (type == null)
  194. {
  195. throw new ArgumentNullException("type");
  196. }
  197. if (response == null)
  198. {
  199. throw new ArgumentNullException("response");
  200. }
  201. if (!this.CanReadType(type))
  202. {
  203. return false;
  204. }
  205. // Content type must be set and must be supported
  206. MediaTypeHeaderValue mediaType = response.Content.Headers.ContentType;
  207. MediaTypeMatch mediaTypeMatch = null;
  208. return mediaType != null && this.TryMatchSupportedMediaType(mediaType, out mediaTypeMatch);
  209. }
  210. internal ResponseMediaTypeMatch SelectResponseMediaType(Type type, HttpResponseMessage response)
  211. {
  212. if (type == null)
  213. {
  214. throw new ArgumentNullException("type");
  215. }
  216. if (response == null)
  217. {
  218. throw new ArgumentNullException("response");
  219. }
  220. MediaTypeHeaderValue mediaType = null;
  221. MediaTypeMatch mediaTypeMatch = null;
  222. if (!this.CanWriteType(type))
  223. {
  224. return null;
  225. }
  226. mediaType = response.Content == null ? null : response.Content.Headers.ContentType;
  227. if (mediaType != null && this.TryMatchSupportedMediaType(mediaType, out mediaTypeMatch))
  228. {
  229. return new ResponseMediaTypeMatch(
  230. mediaTypeMatch,
  231. ResponseFormatterSelectionResult.MatchOnResponseContentType);
  232. }
  233. HttpRequestMessage request = response.RequestMessage;
  234. if (request != null)
  235. {
  236. IEnumerable<MediaTypeWithQualityHeaderValue> acceptHeaderMediaTypes = request.Headers.Accept.OrderBy((m) => m, MediaTypeHeaderValueComparer.Comparer);
  237. if (this.TryMatchSupportedMediaType(acceptHeaderMediaTypes, out mediaTypeMatch))
  238. {
  239. return new ResponseMediaTypeMatch(
  240. mediaTypeMatch,
  241. ResponseFormatterSelectionResult.MatchOnRequestAcceptHeader);
  242. }
  243. if (this.TryMatchMediaTypeMapping(response, out mediaTypeMatch))
  244. {
  245. return new ResponseMediaTypeMatch(
  246. mediaTypeMatch,
  247. ResponseFormatterSelectionResult.MatchOnRequestAcceptHeaderWithMediaTypeMapping);
  248. }
  249. HttpContent requestContent = request.Content;
  250. if (requestContent != null)
  251. {
  252. MediaTypeHeaderValue requestContentType = requestContent.Headers.ContentType;
  253. if (requestContentType != null && this.TryMatchSupportedMediaType(requestContentType, out mediaTypeMatch))
  254. {
  255. return new ResponseMediaTypeMatch(
  256. mediaTypeMatch,
  257. ResponseFormatterSelectionResult.MatchOnRequestContentType);
  258. }
  259. }
  260. }
  261. mediaType = this.SupportedMediaTypes.FirstOrDefault();
  262. if (mediaType != null && this.Encoding != null)
  263. {
  264. mediaType = (MediaTypeHeaderValue)((ICloneable)mediaType).Clone();
  265. mediaType.CharSet = this.Encoding.WebName;
  266. }
  267. return new ResponseMediaTypeMatch(
  268. new MediaTypeMatch(mediaType),
  269. ResponseFormatterSelectionResult.MatchOnCanWriteType);
  270. }
  271. internal Task<object> ReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders)
  272. {
  273. Contract.Assert(type != null, "type cannot be null.");
  274. Contract.Assert(stream != null, "stream cannot be null.");
  275. Contract.Assert(contentHeaders != null, "contentHeaders cannot be null.");
  276. return this.OnReadFromStreamAsync(type, stream, contentHeaders);
  277. }
  278. internal Task WriteToStreamAsync(Type type, object instance, Stream stream, HttpContentHeaders contentHeaders, TransportContext context)
  279. {
  280. Contract.Assert(type != null, "type cannot be null.");
  281. Contract.Assert(stream != null, "stream cannot be null.");
  282. Contract.Assert(contentHeaders != null, "contentHeaders cannot be null.");
  283. return this.OnWriteToStreamAsync(type, instance, stream, contentHeaders, context);
  284. }
  285. internal object ReadFromStream(Type type, Stream stream, HttpContentHeaders contentHeaders)
  286. {
  287. Contract.Assert(type != null, "type cannot be null.");
  288. Contract.Assert(stream != null, "stream cannot be null.");
  289. Contract.Assert(contentHeaders != null, "contentHeaders cannot be null.");
  290. // TODO: CSDMain 235646 Introduce new MediaTypeFormatter exception that should be thrown from MediaTypeFormatter.WriteToStream and MediaTypeFormatter.ReadFromStream
  291. return this.OnReadFromStream(type, stream, contentHeaders);
  292. }
  293. internal void WriteToStream(Type type, object instance, Stream stream, HttpContentHeaders contentHeaders, TransportContext context)
  294. {
  295. Contract.Assert(type != null, "type cannot be null.");
  296. Contract.Assert(stream != null, "stream cannot be null.");
  297. Contract.Assert(contentHeaders != null, "contentHeaders cannot be null.");
  298. // TODO: CSDMain 235646 Introduce new MediaTypeFormatter exception that should be thrown from MediaTypeFormatter.WriteToStream and MediaTypeFormatter.ReadFromStream
  299. this.OnWriteToStream(type, instance, stream, contentHeaders, context);
  300. }
  301. internal bool TryMatchSupportedMediaType(MediaTypeHeaderValue mediaType, out MediaTypeMatch mediaTypeMatch)
  302. {
  303. Contract.Assert(mediaType != null, "mediaType cannot be null.");
  304. foreach (MediaTypeHeaderValue supportedMediaType in this.SupportedMediaTypes)
  305. {
  306. if (MediaTypeHeaderValueEqualityComparer.EqualityComparer.Equals(supportedMediaType, mediaType))
  307. {
  308. // If the incoming media type had an associated quality factor, propagate it to the match
  309. MediaTypeWithQualityHeaderValue mediaTypeWithQualityHeaderValue = mediaType as MediaTypeWithQualityHeaderValue;
  310. double quality = mediaTypeWithQualityHeaderValue != null && mediaTypeWithQualityHeaderValue.Quality.HasValue
  311. ? mediaTypeWithQualityHeaderValue.Quality.Value
  312. : MediaTypeMatch.Match;
  313. MediaTypeHeaderValue effectiveMediaType = supportedMediaType;
  314. if (this.Encoding != null)
  315. {
  316. effectiveMediaType = (MediaTypeHeaderValue)((ICloneable)supportedMediaType).Clone();
  317. effectiveMediaType.CharSet = this.Encoding.WebName;
  318. }
  319. mediaTypeMatch = new MediaTypeMatch(effectiveMediaType, quality);
  320. return true;
  321. }
  322. }
  323. mediaTypeMatch = null;
  324. return false;
  325. }
  326. internal bool TryMatchSupportedMediaType(IEnumerable<MediaTypeHeaderValue> mediaTypes, out MediaTypeMatch mediaTypeMatch)
  327. {
  328. Contract.Assert(mediaTypes != null, "mediaTypes cannot be null.");
  329. foreach (MediaTypeHeaderValue mediaType in mediaTypes)
  330. {
  331. if (this.TryMatchSupportedMediaType(mediaType, out mediaTypeMatch))
  332. {
  333. return true;
  334. }
  335. }
  336. mediaTypeMatch = null;
  337. return false;
  338. }
  339. internal bool TryMatchMediaTypeMapping(HttpRequestMessage request, out MediaTypeMatch mediaTypeMatch)
  340. {
  341. Contract.Assert(request != null, "request cannot be null.");
  342. foreach (MediaTypeMapping mapping in this.MediaTypeMappings)
  343. {
  344. // Collection<T> is not protected against null, so avoid them
  345. double quality;
  346. if (mapping != null && ((quality = mapping.TryMatchMediaType(request)) > 0.0))
  347. {
  348. mediaTypeMatch = new MediaTypeMatch(mapping.MediaType, quality);
  349. return true;
  350. }
  351. }
  352. mediaTypeMatch = null;
  353. return false;
  354. }
  355. internal bool TryMatchMediaTypeMapping(HttpResponseMessage response, out MediaTypeMatch mediaTypeMatch)
  356. {
  357. Contract.Assert(response != null, "response cannot be null.");
  358. foreach (MediaTypeMapping mapping in this.MediaTypeMappings)
  359. {
  360. // Collection<T> is not protected against null, so avoid them
  361. double quality;
  362. if (mapping != null && ((quality = mapping.TryMatchMediaType(response)) > 0.0))
  363. {
  364. mediaTypeMatch = new MediaTypeMatch(mapping.MediaType, quality);
  365. return true;
  366. }
  367. }
  368. mediaTypeMatch = null;
  369. return false;
  370. }
  371. internal IEnumerable<KeyValuePair<string, string>> GetResponseHeaders(Type objectType, string mediaType, HttpResponseMessage responseMessage)
  372. {
  373. return this.OnGetResponseHeaders(objectType, mediaType, responseMessage);
  374. }
  375. /// <summary>
  376. /// Called from <see cref="GetResponseHeaders"/> to retrieve the response headers.
  377. /// </summary>
  378. /// <param name="objectType">The type of the object. See <see cref="ObjectContent"/>.</param>
  379. /// <param name="mediaType">The media type.</param>
  380. /// <param name="responseMessage">The <see cref="HttpResponseMessage"/>.</param>
  381. /// <returns>The collection of response header key value pairs.</returns>
  382. protected virtual IEnumerable<KeyValuePair<string, string>> OnGetResponseHeaders(Type objectType, string mediaType, HttpResponseMessage responseMessage)
  383. {
  384. return null;
  385. }
  386. /// <summary>
  387. /// Determines whether this <see cref="MediaTypeFormatter"/> can deserialize
  388. /// an object of the specified type.
  389. /// </summary>
  390. /// <remarks>
  391. /// The base class unconditionally returns <c>true</c>. Derived classes must
  392. /// override this to exclude types they cannot deserialize.
  393. /// </remarks>
  394. /// <param name="type">The type of object that will be deserialized.</param>
  395. /// <returns><c>true</c> if this <see cref="MediaTypeFormatter"/> can deserialize an object of that type; otherwise <c>false</c>.</returns>
  396. protected virtual bool CanReadType(Type type)
  397. {
  398. if (type == null)
  399. {
  400. throw new ArgumentNullException("type");
  401. }
  402. return true;
  403. }
  404. /// <summary>
  405. /// Determines whether this <see cref="MediaTypeFormatter"/> can serialize
  406. /// an object of the specified type.
  407. /// </summary>
  408. /// <remarks>
  409. /// The base class unconditionally returns <c>true</c>. Derived classes must
  410. /// override this to exclude types they cannot serialize.
  411. /// </remarks>
  412. /// <param name="type">The type of object that will be serialized.</param>
  413. /// <returns><c>true</c> if this <see cref="MediaTypeFormatter"/> can serialize an object of that type; otherwise <c>false</c>.</returns>
  414. protected virtual bool CanWriteType(Type type)
  415. {
  416. if (type == null)
  417. {
  418. throw new ArgumentNullException("type");
  419. }
  420. return true;
  421. }
  422. /// <summary>
  423. /// Called to read an object from the <paramref name="stream"/> asynchronously.
  424. /// Derived classes may override this to do custom deserialization.
  425. /// </summary>
  426. /// <param name="type">The type of the object to read.</param>
  427. /// <param name="stream">The <see cref="Stream"/> from which to read.</param>
  428. /// <param name="contentHeaders">The content headers from the respective request or response.</param>
  429. /// <returns>A <see cref="Task"/> that will yield an object instance when it completes.</returns>
  430. protected virtual Task<object> OnReadFromStreamAsync(Type type, Stream stream, HttpContentHeaders contentHeaders)
  431. {
  432. // Base implementation provides only a Task wrapper over the synchronous operation.
  433. // More intelligent derived formatters should override.
  434. return Task.Factory.StartNew<object>(() => this.OnReadFromStream(type, stream, contentHeaders));
  435. }
  436. /// <summary>
  437. /// Called to write an object to the <paramref name="stream"/> asynchronously.
  438. /// </summary>
  439. /// <param name="type">The type of object to write.</param>
  440. /// <param name="value">The object instance to write.</param>
  441. /// <param name="stream">The <see cref="Stream"/> to which to write.</param>
  442. /// <param name="contentHeaders">The content headers from the respective request or response.</param>
  443. /// <param name="context">The <see cref="TransportContext"/>.</param>
  444. /// <returns>A <see cref="Task"/> that will write the object to the stream asynchronously.</returns>
  445. protected virtual Task OnWriteToStreamAsync(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext context)
  446. {
  447. // Base implementation provides only a Task wrapper over the synchronous operation.
  448. // More intelligent derived formatters should override.
  449. return Task.Factory.StartNew(() => this.OnWriteToStream(type, value, stream, contentHeaders, context));
  450. }
  451. /// <summary>
  452. /// Called to read an object from the <paramref name="stream"/>.
  453. /// Derived classes may override this to do custom deserialization.
  454. /// </summary>
  455. /// <param name="type">The type of the object to read.</param>
  456. /// <param name="stream">The <see cref="Stream"/> from which to read.</param>
  457. /// <param name="contentHeaders">The content headers from the respective request or response.</param>
  458. /// <returns>The object instance read from the <paramref name="stream"/>.</returns>
  459. protected abstract object OnReadFromStream(Type type, Stream stream, HttpContentHeaders contentHeaders);
  460. /// <summary>
  461. /// Called to write an object to the <paramref name="stream"/>.
  462. /// </summary>
  463. /// <param name="type">The type of object to write.</param>
  464. /// <param name="value">The object instance to write.</param>
  465. /// <param name="stream">The <see cref="Stream"/> to which to write.</param>
  466. /// <param name="contentHeaders">The content headers from the respective request or response.</param>
  467. /// <param name="context">The <see cref="TransportContext"/>.</param>
  468. protected abstract void OnWriteToStream(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext context);
  469. private static Type GetOrAddDelegatingType(Type type)
  470. {
  471. return delegatingEnumerableCache.GetOrAdd(
  472. type,
  473. (typeToRemap) =>
  474. {
  475. // The current method is called by methods that already checked the type for is not null, is generic and is or implements IEnumerable<T>
  476. // This retrieves the T type of the IEnumerable<T> interface.
  477. Type elementType;
  478. if (typeToRemap.GetGenericTypeDefinition().Equals(FormattingUtilities.EnumerableInterfaceGenericType))
  479. {
  480. elementType = typeToRemap.GetGenericArguments()[0];
  481. }
  482. else
  483. {
  484. elementType = typeToRemap.GetInterface(FormattingUtilities.EnumerableInterfaceGenericType.FullName).GetGenericArguments()[0];
  485. }
  486. Type delegatingType = FormattingUtilities.DelegatingEnumerableGenericType.MakeGenericType(elementType);
  487. ConstructorInfo delegatingConstructor = delegatingType.GetConstructor(new Type[] { FormattingUtilities.EnumerableInterfaceGenericType.MakeGenericType(elementType) });
  488. delegatingEnumerableConstructorCache.TryAdd(delegatingType, delegatingConstructor);
  489. return delegatingType;
  490. });
  491. }
  492. /// <summary>
  493. /// Collection class that validates it contains only <see cref="MediaTypeHeaderValue"/> instances
  494. /// that are not null and not media ranges.
  495. /// </summary>
  496. internal class MediaTypeHeaderValueCollection : Collection<MediaTypeHeaderValue>
  497. {
  498. private static readonly Type mediaTypeHeaderValueType = typeof(MediaTypeHeaderValue);
  499. /// <summary>
  500. /// Inserts the <paramref name="item"/> into the collection at the specified <paramref name="index"/>.
  501. /// </summary>
  502. /// <param name="index">The zero-based index at which item should be inserted.</param>
  503. /// <param name="item">The object to insert. It cannot be <c>null</c>.</param>
  504. protected override void InsertItem(int index, MediaTypeHeaderValue item)
  505. {
  506. ValidateMediaType(item);
  507. base.InsertItem(index, item);
  508. }
  509. /// <summary>
  510. /// Replaces the element at the specified <paramref name="index"/>.
  511. /// </summary>
  512. /// <param name="index">The zero-based index of the item that should be replaced.</param>
  513. /// <param name="item">The new value for the element at the specified index. It cannot be <c>null</c>.</param>
  514. protected override void SetItem(int index, MediaTypeHeaderValue item)
  515. {
  516. ValidateMediaType(item);
  517. base.SetItem(index, item);
  518. }
  519. private static void ValidateMediaType(MediaTypeHeaderValue item)
  520. {
  521. if (item == null)
  522. {
  523. throw new ArgumentNullException("item");
  524. }
  525. ParsedMediaTypeHeaderValue parsedMediaType = new ParsedMediaTypeHeaderValue(item);
  526. if (parsedMediaType.IsAllMediaRange || parsedMediaType.IsSubTypeMediaRange)
  527. {
  528. throw new ArgumentException(
  529. SR.CannotUseMediaRangeForSupportedMediaType(mediaTypeHeaderValueType.Name, item.MediaType),
  530. "item");
  531. }
  532. }
  533. }
  534. }
  535. }