PageRenderTime 44ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/test/System.Web.Http.OData.Test/OData/Formatter/ODataFormatterTests.cs

https://github.com/huyq2002/aspnetwebstack
C# | 601 lines | 474 code | 72 blank | 55 comment | 7 complexity | 170f0e6e682472392db470701fc0a066 MD5 | raw file
Possible License(s): Apache-2.0
  1. // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Net;
  6. using System.Net.Http;
  7. using System.Net.Http.Headers;
  8. using System.Web.Http.OData.Builder;
  9. using System.Web.Http.OData.Extensions;
  10. using System.Web.Http.OData.Formatter.Deserialization;
  11. using System.Web.Http.OData.Formatter.Serialization;
  12. using System.Web.Http.Tracing;
  13. using System.Xml.Linq;
  14. using Microsoft.Data.Edm;
  15. using Microsoft.Data.OData;
  16. using Microsoft.Data.OData.Atom;
  17. using Microsoft.TestCommon;
  18. using Moq;
  19. using Newtonsoft.Json.Linq;
  20. namespace System.Web.Http.OData.Formatter
  21. {
  22. public class ODataFormatterTests
  23. {
  24. private const string baseAddress = "http://localhost:8081/";
  25. [Theory]
  26. [InlineData(true)]
  27. [InlineData(false)]
  28. public void GetEntryInODataAtomFormat(bool tracingEnabled)
  29. {
  30. // Arrange
  31. using (HttpConfiguration configuration = CreateConfiguration(tracingEnabled))
  32. using (HttpServer host = new HttpServer(configuration))
  33. using (HttpClient client = new HttpClient(host))
  34. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("People(10)",
  35. ODataTestUtil.ApplicationAtomMediaTypeWithQuality))
  36. // Act
  37. using (HttpResponseMessage response = client.SendAsync(request).Result)
  38. {
  39. // Assert
  40. AssertODataVersion3AtomResponse(Resources.PersonEntryInAtom, response);
  41. }
  42. }
  43. [Theory]
  44. [InlineData(true)]
  45. [InlineData(false)]
  46. public void PostEntryInODataAtomFormat(bool tracingEnabled)
  47. {
  48. // Arrange
  49. using (HttpConfiguration configuration = CreateConfiguration(tracingEnabled))
  50. using (HttpServer host = new HttpServer(configuration))
  51. using (HttpClient client = new HttpClient(host))
  52. using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, baseAddress + "People"))
  53. {
  54. request.Content = new StringContent(Resources.PersonEntryInAtom);
  55. request.Content.Headers.ContentType = ODataTestUtil.ApplicationAtomMediaTypeWithQuality;
  56. // Act
  57. using (HttpResponseMessage response = client.SendAsync(request).Result)
  58. {
  59. // Assert
  60. AssertODataVersion3AtomResponse(Resources.PersonEntryInAtom, response, HttpStatusCode.Created);
  61. }
  62. }
  63. }
  64. [Fact]
  65. public void GetEntryInODataJsonVerboseFormat()
  66. {
  67. // Arrange
  68. using (HttpConfiguration configuration = CreateConfiguration())
  69. using (HttpServer host = new HttpServer(configuration))
  70. using (HttpClient client = new HttpClient(host))
  71. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("People(10)",
  72. MediaTypeWithQualityHeaderValue.Parse("application/json;odata=verbose")))
  73. // Act
  74. using (HttpResponseMessage response = client.SendAsync(request).Result)
  75. {
  76. // Assert
  77. AssertODataVersion3JsonResponse(Resources.PersonEntryInJsonVerbose, response);
  78. }
  79. }
  80. [Fact]
  81. public void GetEntryInODataJsonFullMetadataFormat()
  82. {
  83. // Arrange
  84. using (HttpConfiguration configuration = CreateConfiguration())
  85. using (HttpServer host = new HttpServer(configuration))
  86. using (HttpClient client = new HttpClient(host))
  87. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("People(10)",
  88. MediaTypeWithQualityHeaderValue.Parse("application/json;odata=fullmetadata")))
  89. // Act
  90. using (HttpResponseMessage response = client.SendAsync(request).Result)
  91. {
  92. // Assert
  93. AssertODataVersion3JsonResponse(Resources.PersonEntryInJsonFullMetadata, response);
  94. }
  95. }
  96. [Fact]
  97. public void GetEntry_UsesRouteModel_ForMultipleModels()
  98. {
  99. // Model 1 only has Name, Model 2 only has Age
  100. ODataModelBuilder builder1 = new ODataModelBuilder();
  101. var personType1 = builder1.Entity<FormatterPerson>().Property(p => p.Name);
  102. builder1.EntitySet<FormatterPerson>("People").HasIdLink(p => "link", false);
  103. var model1 = builder1.GetEdmModel();
  104. ODataModelBuilder builder2 = new ODataModelBuilder();
  105. builder2.Entity<FormatterPerson>().Property(p => p.Age);
  106. builder2.EntitySet<FormatterPerson>("People").HasIdLink(p => "link", false);
  107. var model2 = builder2.GetEdmModel();
  108. var config = new HttpConfiguration();
  109. config.Routes.MapODataServiceRoute("OData1", "v1", model1);
  110. config.Routes.MapODataServiceRoute("OData2", "v2", model2);
  111. using (HttpServer host = new HttpServer(config))
  112. using (HttpClient client = new HttpClient(host))
  113. {
  114. using (HttpResponseMessage response = client.GetAsync("http://localhost/v1/People(10)").Result)
  115. {
  116. Assert.True(response.IsSuccessStatusCode);
  117. JToken json = JToken.Parse(response.Content.ReadAsStringAsync().Result);
  118. // Model 1 has the Name property but not the Age property
  119. Assert.NotNull(json["Name"]);
  120. Assert.Null(json["Age"]);
  121. }
  122. using (HttpResponseMessage response = client.GetAsync("http://localhost/v2/People(10)").Result)
  123. {
  124. Assert.True(response.IsSuccessStatusCode);
  125. JToken json = JToken.Parse(response.Content.ReadAsStringAsync().Result);
  126. // Model 2 has the Age property but not the Name property
  127. Assert.Null(json["Name"]);
  128. Assert.NotNull(json["Age"]);
  129. }
  130. }
  131. }
  132. [Fact]
  133. public void GetFeedInODataJsonFullMetadataFormat()
  134. {
  135. // Arrange
  136. IEdmModel model = CreateModelForFullMetadata(sameLinksForIdAndEdit: false, sameLinksForEditAndRead: false);
  137. using (HttpConfiguration configuration = CreateConfiguration(model))
  138. using (HttpServer host = new HttpServer(configuration))
  139. using (HttpClient client = new HttpClient(host))
  140. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("MainEntity",
  141. MediaTypeWithQualityHeaderValue.Parse("application/json;odata=fullmetadata")))
  142. // Act
  143. using (HttpResponseMessage response = client.SendAsync(request).Result)
  144. {
  145. // Assert
  146. AssertODataVersion3JsonResponse(
  147. Resources.MainEntryFeedInJsonFullMetadata, response);
  148. }
  149. }
  150. [Fact]
  151. public void GetFeedInODataJsonNoMetadataFormat()
  152. {
  153. // Arrange
  154. IEdmModel model = CreateModelForFullMetadata(sameLinksForIdAndEdit: false, sameLinksForEditAndRead: false);
  155. using (HttpConfiguration configuration = CreateConfiguration(model))
  156. using (HttpServer host = new HttpServer(configuration))
  157. using (HttpClient client = new HttpClient(host))
  158. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("MainEntity",
  159. MediaTypeWithQualityHeaderValue.Parse("application/json;odata=nometadata")))
  160. // Act
  161. using (HttpResponseMessage response = client.SendAsync(request).Result)
  162. {
  163. // Assert
  164. AssertODataVersion3JsonResponse(Resources.MainEntryFeedInJsonNoMetadata, response);
  165. }
  166. }
  167. [Fact]
  168. public void SupportOnlyODataAtomFormat()
  169. {
  170. // Arrange #1 and #2
  171. using (HttpConfiguration configuration = CreateConfiguration())
  172. {
  173. foreach (ODataMediaTypeFormatter odataFormatter in
  174. configuration.Formatters.OfType<ODataMediaTypeFormatter>())
  175. {
  176. odataFormatter.SupportedMediaTypes.Remove(ODataMediaTypes.ApplicationJsonODataVerbose);
  177. odataFormatter.SupportedMediaTypes.Remove(ODataMediaTypes.ApplicationJson);
  178. }
  179. using (HttpServer host = new HttpServer(configuration))
  180. using (HttpClient client = new HttpClient(host))
  181. {
  182. // Arrange #1
  183. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("People(10)",
  184. ODataTestUtil.ApplicationAtomMediaTypeWithQuality))
  185. // Act #1
  186. using (HttpResponseMessage response = client.SendAsync(request).Result)
  187. {
  188. // Assert #1
  189. AssertODataVersion3AtomResponse(Resources.PersonEntryInAtom, response);
  190. }
  191. // Arrange #2
  192. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("People(10)",
  193. ODataTestUtil.ApplicationJsonMediaTypeWithQuality))
  194. // Act #2
  195. using (HttpResponseMessage response = client.SendAsync(request).Result)
  196. {
  197. // Assert #2
  198. Assert.NotNull(response);
  199. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  200. Assert.Equal(ODataTestUtil.ApplicationJsonMediaTypeWithQuality.MediaType,
  201. response.Content.Headers.ContentType.MediaType);
  202. ODataTestUtil.VerifyJsonResponse(response.Content, Resources.PersonEntryInPlainOldJson);
  203. }
  204. }
  205. }
  206. }
  207. [Fact]
  208. public void ConditionallySupportODataIfQueryStringPresent()
  209. {
  210. // Arrange #1, #2 and #3
  211. using (HttpConfiguration configuration = CreateConfiguration())
  212. {
  213. foreach (ODataMediaTypeFormatter odataFormatter in
  214. configuration.Formatters.OfType<ODataMediaTypeFormatter>())
  215. {
  216. odataFormatter.SupportedMediaTypes.Clear();
  217. odataFormatter.MediaTypeMappings.Add(new ODataMediaTypeMapping(ODataTestUtil.ApplicationAtomMediaTypeWithQuality));
  218. odataFormatter.MediaTypeMappings.Add(new ODataMediaTypeMapping(ODataTestUtil.ApplicationJsonMediaTypeWithQuality));
  219. }
  220. using (HttpServer host = new HttpServer(configuration))
  221. using (HttpClient client = new HttpClient(host))
  222. {
  223. // Arrange #1 this request should return response in OData atom format
  224. using (HttpRequestMessage request = ODataTestUtil.GenerateRequestMessage(
  225. CreateAbsoluteUri("People(10)?format=odata"), isAtom: true))
  226. // Act #1
  227. using (HttpResponseMessage response = client.SendAsync(request).Result)
  228. {
  229. // Assert #1
  230. AssertODataVersion3AtomResponse(Resources.PersonEntryInAtom, response);
  231. }
  232. // Arrange #2: this request should return response in OData json format
  233. using (HttpRequestMessage requestWithJsonHeader = ODataTestUtil.GenerateRequestMessage(
  234. CreateAbsoluteUri("People(10)?format=odata"), isAtom: false))
  235. // Act #2
  236. using (HttpResponseMessage response = client.SendAsync(requestWithJsonHeader).Result)
  237. {
  238. // Assert #2
  239. AssertODataVersion3JsonResponse(Resources.PersonEntryInJsonVerbose, response);
  240. }
  241. // Arrange #3: when the query string is not present, request should be handled by the regular Json
  242. // Formatter
  243. using (HttpRequestMessage requestWithNonODataJsonHeader = ODataTestUtil.GenerateRequestMessage(
  244. CreateAbsoluteUri("People(10)"), isAtom: false))
  245. // Act #3
  246. using (HttpResponseMessage response = client.SendAsync(requestWithNonODataJsonHeader).Result)
  247. {
  248. // Assert #3
  249. Assert.NotNull(response);
  250. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  251. Assert.Equal(ODataTestUtil.ApplicationJsonMediaTypeWithQuality.MediaType,
  252. response.Content.Headers.ContentType.MediaType);
  253. Assert.Null(ODataTestUtil.GetDataServiceVersion(response.Content.Headers));
  254. ODataTestUtil.VerifyJsonResponse(response.Content, Resources.PersonEntryInPlainOldJson);
  255. }
  256. }
  257. }
  258. }
  259. [Fact]
  260. public void GetFeedInODataAtomFormat_HasSelfLink()
  261. {
  262. // Arrange
  263. using (HttpConfiguration configuration = CreateConfiguration())
  264. using (HttpServer host = new HttpServer(configuration))
  265. using (HttpClient client = new HttpClient(host))
  266. using (HttpRequestMessage request = CreateRequest("People",
  267. ODataTestUtil.ApplicationAtomMediaTypeWithQuality))
  268. // Act
  269. using (HttpResponseMessage response = client.SendAsync(request).Result)
  270. {
  271. // Assert
  272. Assert.NotNull(response);
  273. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  274. XElement xml = XElement.Load(response.Content.ReadAsStreamAsync().Result);
  275. XElement[] links = xml.Elements(XName.Get("link", "http://www.w3.org/2005/Atom")).ToArray();
  276. Assert.Equal("self", links.First().Attribute("rel").Value);
  277. Assert.Equal(baseAddress + "People", links.First().Attribute("href").Value);
  278. }
  279. }
  280. [Fact]
  281. public void GetFeedInODataAtomFormat_LimitsResults()
  282. {
  283. // Arrange
  284. using (HttpConfiguration configuration = CreateConfiguration())
  285. using (HttpServer host = new HttpServer(configuration))
  286. using (HttpClient client = new HttpClient(host))
  287. using (HttpRequestMessage request = CreateRequest("People?$orderby=Name&$inlinecount=allpages",
  288. ODataTestUtil.ApplicationAtomMediaTypeWithQuality))
  289. // Act
  290. using (HttpResponseMessage response = client.SendAsync(request).Result)
  291. {
  292. // Assert
  293. Assert.NotNull(response);
  294. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  295. XElement xml = XElement.Load(response.Content.ReadAsStreamAsync().Result);
  296. XElement[] entries = xml.Elements(XName.Get("entry", "http://www.w3.org/2005/Atom")).ToArray();
  297. XElement nextPageLink = xml.Elements(XName.Get("link", "http://www.w3.org/2005/Atom"))
  298. .Where(link => link.Attribute(XName.Get("rel")).Value == "next")
  299. .SingleOrDefault();
  300. XElement count = xml.Element(XName.Get("count", "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"));
  301. // Assert the PageSize correctly limits three results to two
  302. Assert.Equal(2, entries.Length);
  303. // Assert there is a next page link
  304. Assert.NotNull(nextPageLink);
  305. // Assert the count is included with the number of entities (3)
  306. Assert.Equal("3", count.Value);
  307. }
  308. }
  309. [Fact]
  310. [ReplaceCulture]
  311. public void HttpErrorInODataFormat_GetsSerializedCorrectly()
  312. {
  313. // Arrange
  314. using (HttpConfiguration configuration = CreateConfiguration())
  315. {
  316. configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
  317. using (HttpServer host = new HttpServer(configuration))
  318. using (HttpClient client = new HttpClient(host))
  319. using (HttpRequestMessage request = CreateRequest("People?$filter=abc+eq+null",
  320. MediaTypeWithQualityHeaderValue.Parse("application/xml")))
  321. // Act
  322. using (HttpResponseMessage response = client.SendAsync(request).Result)
  323. {
  324. // Assert
  325. Assert.NotNull(response);
  326. Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
  327. XElement xml = XElement.Load(response.Content.ReadAsStreamAsync().Result);
  328. Assert.Equal("error", xml.Name.LocalName);
  329. Assert.Equal("The query specified in the URI is not valid. Could not find a property named 'abc' on type 'System.Web.Http.OData.Formatter.FormatterPerson'.",
  330. xml.Element(XName.Get("{http://schemas.microsoft.com/ado/2007/08/dataservices/metadata}message")).Value);
  331. XElement innerErrorXml = xml.Element(XName.Get("{http://schemas.microsoft.com/ado/2007/08/dataservices/metadata}innererror"));
  332. Assert.NotNull(innerErrorXml);
  333. Assert.Equal("Could not find a property named 'abc' on type 'System.Web.Http.OData.Formatter.FormatterPerson'.",
  334. innerErrorXml.Element(XName.Get("{http://schemas.microsoft.com/ado/2007/08/dataservices/metadata}message")).Value);
  335. Assert.Equal("Microsoft.Data.OData.ODataException",
  336. innerErrorXml.Element(XName.Get("{http://schemas.microsoft.com/ado/2007/08/dataservices/metadata}type")).Value);
  337. }
  338. }
  339. }
  340. [Fact]
  341. public void CustomSerializerWorks()
  342. {
  343. // Arrange
  344. using (HttpConfiguration configuration = CreateConfiguration())
  345. {
  346. configuration.Formatters.InsertRange(
  347. 0,
  348. ODataMediaTypeFormatters.Create(new CustomSerializerProvider(), new DefaultODataDeserializerProvider()));
  349. using (HttpServer host = new HttpServer(configuration))
  350. using (HttpClient client = new HttpClient(host))
  351. using (HttpRequestMessage request = CreateRequest("People", MediaTypeWithQualityHeaderValue.Parse("application/atom+xml")))
  352. // Act
  353. using (HttpResponseMessage response = client.SendAsync(request).Result)
  354. {
  355. // Assert
  356. Assert.NotNull(response);
  357. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  358. XElement xml = XElement.Load(response.Content.ReadAsStreamAsync().Result);
  359. Assert.Equal("My amazing feed", xml.Elements().Single(e => e.Name.LocalName == "title").Value);
  360. }
  361. }
  362. }
  363. private static void AddDataServiceVersionHeaders(HttpRequestMessage request)
  364. {
  365. request.Headers.Add("DataServiceVersion", "2.0");
  366. request.Headers.Add("MaxDataServiceVersion", "3.0");
  367. }
  368. private static void AssertODataVersion3AtomResponse(string expectedContent, HttpResponseMessage actual)
  369. {
  370. AssertODataVersion3AtomResponse(expectedContent, actual, HttpStatusCode.OK);
  371. }
  372. private static void AssertODataVersion3AtomResponse(string expectedContent, HttpResponseMessage actual, HttpStatusCode statusCode)
  373. {
  374. Assert.NotNull(actual);
  375. Assert.Equal(statusCode, actual.StatusCode);
  376. Assert.Equal(ODataTestUtil.ApplicationAtomMediaTypeWithQuality.MediaType,
  377. actual.Content.Headers.ContentType.MediaType);
  378. Assert.Equal(ODataTestUtil.GetDataServiceVersion(actual.Content.Headers),
  379. ODataTestUtil.Version3NumberString);
  380. ODataTestUtil.VerifyResponse(actual.Content, expectedContent);
  381. }
  382. private static void AssertODataVersion3JsonResponse(string expectedContent, HttpResponseMessage actual)
  383. {
  384. Assert.NotNull(actual);
  385. Assert.Equal(HttpStatusCode.OK, actual.StatusCode);
  386. Assert.Equal(ODataTestUtil.ApplicationJsonMediaTypeWithQuality.MediaType,
  387. actual.Content.Headers.ContentType.MediaType);
  388. Assert.Equal(ODataTestUtil.Version3NumberString,
  389. ODataTestUtil.GetDataServiceVersion(actual.Content.Headers));
  390. ODataTestUtil.VerifyJsonResponse(actual.Content, expectedContent);
  391. }
  392. private static string CreateAbsoluteLink(string relativeUri)
  393. {
  394. return CreateAbsoluteUri(relativeUri).AbsoluteUri;
  395. }
  396. private static Uri CreateAbsoluteUri(string relativeUri)
  397. {
  398. return new Uri(new Uri(baseAddress), relativeUri);
  399. }
  400. private static HttpConfiguration CreateConfiguration(bool tracingEnabled = false)
  401. {
  402. IEdmModel model = ODataTestUtil.GetEdmModel();
  403. HttpConfiguration configuration = CreateConfiguration(model);
  404. if (tracingEnabled)
  405. {
  406. configuration.Services.Replace(typeof(ITraceWriter), new Mock<ITraceWriter>().Object);
  407. }
  408. return configuration;
  409. }
  410. private static HttpConfiguration CreateConfiguration(IEdmModel model)
  411. {
  412. HttpConfiguration configuration = new HttpConfiguration();
  413. configuration.Routes.MapODataServiceRoute(model);
  414. configuration.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create());
  415. return configuration;
  416. }
  417. private static IEdmModel CreateModelForFullMetadata(bool sameLinksForIdAndEdit, bool sameLinksForEditAndRead)
  418. {
  419. ODataModelBuilder builder = new ODataModelBuilder();
  420. EntitySetConfiguration<MainEntity> mainSet = builder.EntitySet<MainEntity>("MainEntity");
  421. Func<EntityInstanceContext<MainEntity>, string> idLinkFactory = (e) =>
  422. CreateAbsoluteLink("/MainEntity/id/" + e.GetPropertyValue("Id").ToString());
  423. mainSet.HasIdLink(idLinkFactory, followsConventions: true);
  424. Func<EntityInstanceContext<MainEntity>, string> editLinkFactory;
  425. if (!sameLinksForIdAndEdit)
  426. {
  427. editLinkFactory = (e) => CreateAbsoluteLink("/MainEntity/edit/" + e.GetPropertyValue("Id").ToString());
  428. mainSet.HasEditLink(editLinkFactory, followsConventions: false);
  429. }
  430. Func<EntityInstanceContext<MainEntity>, string> readLinkFactory;
  431. if (!sameLinksForEditAndRead)
  432. {
  433. readLinkFactory = (e) => CreateAbsoluteLink("/MainEntity/read/" + e.GetPropertyValue("Id").ToString());
  434. mainSet.HasReadLink(readLinkFactory, followsConventions: false);
  435. }
  436. EntityTypeConfiguration<MainEntity> main = mainSet.EntityType;
  437. main.HasKey<int>((e) => e.Id);
  438. main.Property<short>((e) => e.Int16);
  439. NavigationPropertyConfiguration mainToRelated = mainSet.EntityType.HasRequired((e) => e.Related);
  440. main.Action("DoAlways").ReturnsCollectionFromEntitySet<MainEntity>("MainEntity").HasActionLink((c) =>
  441. CreateAbsoluteUri("/MainEntity/DoAlways/" + c.GetPropertyValue("Id")),
  442. followsConventions: true);
  443. main.TransientAction("DoSometimes").ReturnsCollectionFromEntitySet<MainEntity>(
  444. "MainEntity").HasActionLink((c) =>
  445. CreateAbsoluteUri("/MainEntity/DoSometimes/" + c.GetPropertyValue("Id")),
  446. followsConventions: false);
  447. mainSet.HasNavigationPropertyLink(mainToRelated, (c, p) => new Uri("/MainEntity/RelatedEntity/" +
  448. c.GetPropertyValue("Id"), UriKind.Relative), followsConventions: true);
  449. EntitySetConfiguration<RelatedEntity> related = builder.EntitySet<RelatedEntity>("RelatedEntity");
  450. return builder.GetEdmModel();
  451. }
  452. private static HttpRequestMessage CreateRequest(string pathAndQuery, MediaTypeWithQualityHeaderValue accept)
  453. {
  454. HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, CreateAbsoluteUri(pathAndQuery));
  455. request.Headers.Accept.Add(accept);
  456. return request;
  457. }
  458. private static HttpRequestMessage CreateRequestWithDataServiceVersionHeaders(string pathAndQuery,
  459. MediaTypeWithQualityHeaderValue accept)
  460. {
  461. HttpRequestMessage request = CreateRequest(pathAndQuery, accept);
  462. AddDataServiceVersionHeaders(request);
  463. return request;
  464. }
  465. private class CustomFeedSerializer : ODataFeedSerializer
  466. {
  467. public CustomFeedSerializer(ODataSerializerProvider serializerProvider)
  468. : base(serializerProvider)
  469. {
  470. }
  471. public override ODataFeed CreateODataFeed(IEnumerable feedInstance, IEdmCollectionTypeReference feedType,
  472. ODataSerializerContext writeContext)
  473. {
  474. ODataFeed feed = base.CreateODataFeed(feedInstance, feedType, writeContext);
  475. feed.Atom().Title = new AtomTextConstruct { Kind = AtomTextConstructKind.Text, Text = "My amazing feed" };
  476. return feed;
  477. }
  478. }
  479. private class CustomSerializerProvider : DefaultODataSerializerProvider
  480. {
  481. public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType)
  482. {
  483. if (edmType.IsCollection() && edmType.AsCollection().ElementType().IsEntity())
  484. {
  485. return new CustomFeedSerializer(this);
  486. }
  487. return base.GetEdmTypeSerializer(edmType);
  488. }
  489. }
  490. }
  491. public class MainEntity
  492. {
  493. public int Id { get; set; }
  494. public short Int16 { get; set; }
  495. public RelatedEntity Related { get; set; }
  496. }
  497. public class RelatedEntity
  498. {
  499. public int Id { get; set; }
  500. }
  501. public class MainEntityController : ODataController
  502. {
  503. public IEnumerable<MainEntity> Get()
  504. {
  505. MainEntity[] entities = new MainEntity[]
  506. {
  507. new MainEntity
  508. {
  509. Id = 1,
  510. Int16 = -1,
  511. Related = new RelatedEntity
  512. {
  513. Id = 101
  514. }
  515. },
  516. new MainEntity
  517. {
  518. Id = 2,
  519. Int16 = -2,
  520. Related = new RelatedEntity
  521. {
  522. Id = 102
  523. }
  524. }
  525. };
  526. return new PageResult<MainEntity>(entities, new Uri("aa:b"), 3);
  527. }
  528. }
  529. }