PageRenderTime 48ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

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

https://github.com/huyq2002/aspnetwebstack
C# | 750 lines | 596 code | 93 blank | 61 comment | 5 complexity | cc44af3dabe44e1b9b9fa1dcd27c2588 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;
  9. using System.Web.Http.Tracing;
  10. using System.Web.OData.Builder;
  11. using System.Web.OData.Builder.TestModels;
  12. using System.Web.OData.Extensions;
  13. using System.Web.OData.Formatter.Deserialization;
  14. using System.Web.OData.Formatter.Serialization;
  15. using System.Web.OData.Query;
  16. using System.Web.OData.TestCommon;
  17. using Microsoft.OData.Core;
  18. using Microsoft.OData.Edm;
  19. using Microsoft.TestCommon;
  20. using Moq;
  21. using Newtonsoft.Json.Linq;
  22. namespace System.Web.OData.Formatter
  23. {
  24. public class ODataFormatterTests
  25. {
  26. private const string baseAddress = "http://localhost:8081/";
  27. [Theory]
  28. [InlineData("application/json;odata.metadata=none", "PersonEntryInJsonLightNoMetadata.json")]
  29. [InlineData("application/json;odata.metadata=minimal", "PersonEntryInJsonLightMinimalMetadata.json")]
  30. [InlineData("application/json;odata.metadata=full", "PersonEntryInJsonLightFullMetadata.json")]
  31. public void GetEntryInODataJsonLightFormat(string metadata, string expect)
  32. {
  33. // Arrange
  34. using (HttpConfiguration configuration = CreateConfiguration())
  35. using (HttpServer host = new HttpServer(configuration))
  36. using (HttpClient client = new HttpClient(host))
  37. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("People(10)",
  38. MediaTypeWithQualityHeaderValue.Parse(metadata)))
  39. // Act
  40. using (HttpResponseMessage response = client.SendAsync(request).Result)
  41. {
  42. // Assert
  43. AssertODataVersion4JsonResponse(Resources.GetString(expect), response);
  44. }
  45. }
  46. [Theory]
  47. [InlineData("application/json;odata.metadata=none", "PresidentInJsonLightNoMetadata.json")]
  48. [InlineData("application/json;odata.metadata=minimal", "PresidentInJsonLightMinimalMetadata.json")]
  49. [InlineData("application/json;odata.metadata=full", "PresidentInJsonLightFullMetadata.json")]
  50. public void GetSingletonInODataJsonLightFormat(string metadata, string expect)
  51. {
  52. // Arrange
  53. using (HttpConfiguration configuration = CreateConfiguration())
  54. using (HttpServer host = new HttpServer(configuration))
  55. using (HttpClient client = new HttpClient(host))
  56. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("President",
  57. MediaTypeWithQualityHeaderValue.Parse(metadata)))
  58. // Act
  59. using (HttpResponseMessage response = client.SendAsync(request).Result)
  60. {
  61. // Assert
  62. AssertODataVersion4JsonResponse(Resources.GetString(expect), response);
  63. }
  64. }
  65. [Fact]
  66. public void GetEntry_UsesRouteModel_ForMultipleModels()
  67. {
  68. // Model 1 only has Name, Model 2 only has Age
  69. ODataModelBuilder builder1 = new ODataModelBuilder();
  70. var personType1 = builder1.EntityType<FormatterPerson>();
  71. personType1.HasKey(p => p.PerId);
  72. personType1.Property(p => p.Name);
  73. builder1.EntitySet<FormatterPerson>("People").HasIdLink(p => new Uri("http://link/"), false);
  74. var model1 = builder1.GetEdmModel();
  75. ODataModelBuilder builder2 = new ODataModelBuilder();
  76. var personType2 = builder2.EntityType<FormatterPerson>();
  77. personType2.HasKey(p => p.PerId);
  78. personType2.Property(p => p.Age);
  79. builder2.EntitySet<FormatterPerson>("People").HasIdLink(p => new Uri("http://link/"), false);
  80. var model2 = builder2.GetEdmModel();
  81. var config = new[] { typeof(PeopleController) }.GetHttpConfiguration();
  82. config.MapODataServiceRoute("OData1", "v1", model1);
  83. config.MapODataServiceRoute("OData2", "v2", model2);
  84. using (HttpServer host = new HttpServer(config))
  85. using (HttpClient client = new HttpClient(host))
  86. {
  87. using (HttpResponseMessage response = client.GetAsync("http://localhost/v1/People(10)").Result)
  88. {
  89. Assert.True(response.IsSuccessStatusCode);
  90. JToken json = JToken.Parse(response.Content.ReadAsStringAsync().Result);
  91. // Model 1 has the Name property but not the Age property
  92. Assert.NotNull(json["Name"]);
  93. Assert.Null(json["Age"]);
  94. }
  95. using (HttpResponseMessage response = client.GetAsync("http://localhost/v2/People(10)").Result)
  96. {
  97. Assert.True(response.IsSuccessStatusCode);
  98. JToken json = JToken.Parse(response.Content.ReadAsStringAsync().Result);
  99. // Model 2 has the Age property but not the Name property
  100. Assert.Null(json["Name"]);
  101. Assert.NotNull(json["Age"]);
  102. }
  103. }
  104. }
  105. [Fact]
  106. public void GetFeedInODataJsonFullMetadataFormat()
  107. {
  108. // Arrange
  109. IEdmModel model = CreateModelForFullMetadata(sameLinksForIdAndEdit: false, sameLinksForEditAndRead: false);
  110. using (HttpConfiguration configuration = CreateConfiguration(model))
  111. using (HttpServer host = new HttpServer(configuration))
  112. using (HttpClient client = new HttpClient(host))
  113. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("MainEntity",
  114. MediaTypeWithQualityHeaderValue.Parse("application/json;odata.metadata=full")))
  115. // Act
  116. using (HttpResponseMessage response = client.SendAsync(request).Result)
  117. {
  118. // Assert
  119. AssertODataVersion4JsonResponse(
  120. Resources.MainEntryFeedInJsonFullMetadata, response);
  121. }
  122. }
  123. [Fact]
  124. public void GetFeedInODataJsonNoMetadataFormat()
  125. {
  126. // Arrange
  127. IEdmModel model = CreateModelForFullMetadata(sameLinksForIdAndEdit: false, sameLinksForEditAndRead: false);
  128. using (HttpConfiguration configuration = CreateConfiguration(model))
  129. using (HttpServer host = new HttpServer(configuration))
  130. using (HttpClient client = new HttpClient(host))
  131. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("MainEntity",
  132. MediaTypeWithQualityHeaderValue.Parse("application/json;odata.metadata=none")))
  133. // Act
  134. using (HttpResponseMessage response = client.SendAsync(request).Result)
  135. {
  136. // Assert
  137. AssertODataVersion4JsonResponse(Resources.MainEntryFeedInJsonNoMetadata, response);
  138. }
  139. }
  140. [Fact]
  141. public void SupportOnlyODataFormat()
  142. {
  143. // Arrange
  144. using (HttpConfiguration configuration = CreateConfiguration())
  145. {
  146. foreach (ODataMediaTypeFormatter odataFormatter in
  147. configuration.Formatters.OfType<ODataMediaTypeFormatter>())
  148. {
  149. odataFormatter.SupportedMediaTypes.Remove(ODataMediaTypes.ApplicationJson);
  150. }
  151. using (HttpServer host = new HttpServer(configuration))
  152. using (HttpClient client = new HttpClient(host))
  153. {
  154. using (HttpRequestMessage request = CreateRequestWithDataServiceVersionHeaders("People(10)",
  155. ODataTestUtil.ApplicationJsonMediaTypeWithQuality))
  156. // Act
  157. using (HttpResponseMessage response = client.SendAsync(request).Result)
  158. {
  159. // Assert
  160. Assert.NotNull(response);
  161. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  162. Assert.Equal(ODataTestUtil.ApplicationJsonMediaTypeWithQuality.MediaType,
  163. response.Content.Headers.ContentType.MediaType);
  164. ODataTestUtil.VerifyResponse(response.Content, Resources.PersonEntryInPlainOldJson);
  165. }
  166. }
  167. }
  168. }
  169. [Fact]
  170. public void ConditionallySupportODataIfQueryStringPresent()
  171. {
  172. // Arrange #1, #2 and #3
  173. using (HttpConfiguration configuration = CreateConfiguration())
  174. {
  175. foreach (ODataMediaTypeFormatter odataFormatter in
  176. configuration.Formatters.OfType<ODataMediaTypeFormatter>())
  177. {
  178. odataFormatter.SupportedMediaTypes.Clear();
  179. odataFormatter.MediaTypeMappings.Add(new ODataMediaTypeMapping(ODataTestUtil.ApplicationJsonMediaTypeWithQuality));
  180. }
  181. using (HttpServer host = new HttpServer(configuration))
  182. using (HttpClient client = new HttpClient(host))
  183. {
  184. // Arrange #1: this request should return response in OData json format
  185. using (HttpRequestMessage requestWithJsonHeader = ODataTestUtil.GenerateRequestMessage(
  186. CreateAbsoluteUri("People(10)?$format=application/json")))
  187. // Act #1
  188. using (HttpResponseMessage response = client.SendAsync(requestWithJsonHeader).Result)
  189. {
  190. // Assert #1
  191. AssertODataVersion4JsonResponse(Resources.PersonEntryInJsonLight, response);
  192. }
  193. // Arrange #2: when the query string is not present, request should be handled by the regular Json
  194. // Formatter
  195. using (HttpRequestMessage requestWithNonODataJsonHeader = ODataTestUtil.GenerateRequestMessage(
  196. CreateAbsoluteUri("People(10)")))
  197. // Act #2
  198. using (HttpResponseMessage response = client.SendAsync(requestWithNonODataJsonHeader).Result)
  199. {
  200. // Assert #2
  201. Assert.NotNull(response);
  202. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  203. Assert.Equal(ODataTestUtil.ApplicationJsonMediaTypeWithQuality.MediaType,
  204. response.Content.Headers.ContentType.MediaType);
  205. Assert.Null(ODataTestUtil.GetDataServiceVersion(response.Content.Headers));
  206. ODataTestUtil.VerifyResponse(response.Content, Resources.PersonEntryInPlainOldJson);
  207. }
  208. // Arrange #3: this request should return response in OData json format
  209. using (HttpRequestMessage requestWithJsonHeader = ODataTestUtil.GenerateRequestMessage(
  210. CreateAbsoluteUri("President?$format=application/json")))
  211. // Act #3
  212. using (HttpResponseMessage response = client.SendAsync(requestWithJsonHeader).Result)
  213. {
  214. // Assert #3
  215. AssertODataVersion4JsonResponse(Resources.GetString("PresidentInJsonLightMinimalMetadata.json"),
  216. response);
  217. }
  218. }
  219. }
  220. }
  221. [Fact]
  222. public void GetFeedInODataJsonFormat_LimitsResults()
  223. {
  224. // Arrange
  225. using (HttpConfiguration configuration = CreateConfiguration())
  226. using (HttpServer host = new HttpServer(configuration))
  227. using (HttpClient client = new HttpClient(host))
  228. using (HttpRequestMessage request = CreateRequest("People?$orderby=Name&$count=true",
  229. ODataTestUtil.ApplicationJsonMediaTypeWithQuality))
  230. // Act
  231. using (HttpResponseMessage response = client.SendAsync(request).Result)
  232. {
  233. // Assert
  234. Assert.NotNull(response);
  235. Assert.Equal(HttpStatusCode.OK, response.StatusCode);
  236. string result = response.Content.ReadAsStringAsync().Result;
  237. dynamic json = JToken.Parse(result);
  238. // Assert the PageSize correctly limits three results to two
  239. Assert.Equal(2, json["value"].Count);
  240. // Assert there is a next page link
  241. Assert.NotNull(json["@odata.nextLink"]);
  242. Assert.Equal("http://localhost:8081/People?$orderby=Name&$count=true&$skip=2", json["@odata.nextLink"].Value);
  243. // Assert the count is included with the number of entities (3)
  244. Assert.Equal(3, json["@odata.count"].Value);
  245. }
  246. }
  247. [Fact]
  248. [ReplaceCulture]
  249. public void HttpErrorInODataFormat_GetsSerializedCorrectly()
  250. {
  251. // Arrange
  252. using (HttpConfiguration configuration = CreateConfiguration())
  253. {
  254. configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
  255. using (HttpServer host = new HttpServer(configuration))
  256. using (HttpClient client = new HttpClient(host))
  257. using (HttpRequestMessage request = CreateRequest("People?$filter=abc+eq+null",
  258. MediaTypeWithQualityHeaderValue.Parse("application/json")))
  259. // Act
  260. using (HttpResponseMessage response = client.SendAsync(request).Result)
  261. {
  262. // Assert
  263. Assert.NotNull(response);
  264. Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
  265. string result = response.Content.ReadAsStringAsync().Result;
  266. dynamic json = JToken.Parse(result);
  267. Assert.Equal("The query specified in the URI is not valid. " +
  268. "Could not find a property named 'abc' on type 'System.Web.OData.Formatter.FormatterPerson'.",
  269. json["error"]["message"].Value);
  270. Assert.Equal("Could not find a property named 'abc' on type 'System.Web.OData.Formatter.FormatterPerson'.",
  271. json["error"]["innererror"]["message"].Value);
  272. Assert.Equal("Microsoft.OData.Core.ODataException",
  273. json["error"]["innererror"]["type"].Value);
  274. }
  275. }
  276. }
  277. [Fact]
  278. public void CustomSerializerWorks()
  279. {
  280. // Arrange
  281. using (HttpConfiguration configuration = CreateConfiguration())
  282. {
  283. configuration.Formatters.InsertRange(
  284. 0,
  285. ODataMediaTypeFormatters.Create(new CustomSerializerProvider(), new DefaultODataDeserializerProvider()));
  286. using (HttpServer host = new HttpServer(configuration))
  287. using (HttpClient client = new HttpClient(host))
  288. using (HttpRequestMessage request = CreateRequest("People", MediaTypeWithQualityHeaderValue.Parse("application/json")))
  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. string payload = response.Content.ReadAsStringAsync().Result;
  296. // Change DoesNotContain() as Contain() after fix https://aspnetwebstack.codeplex.com/workitem/1880
  297. Assert.DoesNotContain("\"@Custom.Int32Annotation\":321", payload);
  298. Assert.DoesNotContain("\"@Custom.StringAnnotation\":\"My amazing feed\"", payload);
  299. }
  300. }
  301. }
  302. [Fact]
  303. public void EnumTypeRoundTripTest()
  304. {
  305. // Arrange
  306. ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
  307. builder.EntitySet<EnumCustomer>("EnumCustomers");
  308. IEdmModel model = builder.GetEdmModel();
  309. var controllers = new[] { typeof(EnumCustomersController) };
  310. using (HttpConfiguration configuration = controllers.GetHttpConfiguration())
  311. {
  312. configuration.MapODataServiceRoute("odata", routePrefix: null, model: model);
  313. using (HttpServer host = new HttpServer(configuration))
  314. using (HttpClient client = new HttpClient(host))
  315. using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/EnumCustomers"))
  316. {
  317. request.Content = new StringContent(
  318. string.Format(@"{{'@odata.type':'#System.Web.OData.Formatter.EnumCustomer',
  319. 'ID':0,'Color':'Green, Blue','Colors':['Red','Red, Blue']}}"));
  320. request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
  321. request.Headers.Accept.ParseAdd("application/json");
  322. // Act
  323. using (HttpResponseMessage response = client.SendAsync(request).Result)
  324. {
  325. // Assert
  326. response.EnsureSuccessStatusCode();
  327. var customer = response.Content.ReadAsAsync<JObject>().Result;
  328. Assert.Equal(0, customer["ID"]);
  329. Assert.Equal(Color.Green | Color.Blue, Enum.Parse(typeof(Color), customer["Color"].ToString()));
  330. var colors = customer["Colors"].Select(c => Enum.Parse(typeof(Color), c.ToString()));
  331. Assert.Equal(2, colors.Count());
  332. Assert.Contains(Color.Red, colors);
  333. Assert.Contains(Color.Red | Color.Blue, colors);
  334. }
  335. }
  336. }
  337. }
  338. [Fact]
  339. public void EnumSerializer_HasODataType_ForFullMetadata()
  340. {
  341. // Arrange & Act
  342. string acceptHeader = "application/json;odata.metadata=full";
  343. HttpResponseMessage response = GetEnumResponse(acceptHeader);
  344. // Assert
  345. response.EnsureSuccessStatusCode();
  346. JObject customer = response.Content.ReadAsAsync<JObject>().Result;
  347. Assert.Equal("#System.Web.OData.Builder.TestModels.Color",
  348. customer.GetValue("Color@odata.type"));
  349. Assert.Equal("#Collection(System.Web.OData.Builder.TestModels.Color)",
  350. customer.GetValue("Colors@odata.type"));
  351. }
  352. [Theory]
  353. [InlineData("application/json;odata.metadata=minimal")]
  354. [InlineData("application/json;odata.metadata=none")]
  355. public void EnumSerializer_HasNoODataType_ForNonFullMetadata(string acceptHeader)
  356. {
  357. // Arrange & Act
  358. HttpResponseMessage response = GetEnumResponse(acceptHeader);
  359. // Assert
  360. response.EnsureSuccessStatusCode();
  361. JObject customer = response.Content.ReadAsAsync<JObject>().Result;
  362. Assert.False(customer.Values().Contains("Color@odata.type"));
  363. Assert.False(customer.Values().Contains("Colors@odata.type"));
  364. }
  365. private HttpResponseMessage GetEnumResponse(string acceptHeader)
  366. {
  367. ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
  368. builder.EntitySet<EnumCustomer>("EnumCustomers");
  369. IEdmModel model = builder.GetEdmModel();
  370. HttpConfiguration configuration = new[] { typeof(EnumCustomersController) }.GetHttpConfiguration();
  371. configuration.MapODataServiceRoute("odata", routePrefix: null, model: model);
  372. HttpServer host = new HttpServer(configuration);
  373. HttpClient client = new HttpClient(host);
  374. HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/EnumCustomers");
  375. request.Content = new StringContent(
  376. string.Format(@"{{'@odata.type':'#System.Web.OData.Formatter.EnumCustomer',
  377. 'ID':0,'Color':'Green, Blue','Colors':['Red','Red, Blue']}}"));
  378. request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
  379. request.Headers.Accept.ParseAdd(acceptHeader);
  380. HttpResponseMessage response = client.SendAsync(request).Result;
  381. return response;
  382. }
  383. [Fact]
  384. public void EnumSerializer_HasMetadataType()
  385. {
  386. // Arrange
  387. ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
  388. builder.EntitySet<EnumCustomer>("EnumCustomers");
  389. IEdmModel model = builder.GetEdmModel();
  390. var controllers = new[] { typeof(EnumCustomersController) };
  391. using (HttpConfiguration configuration = controllers.GetHttpConfiguration())
  392. {
  393. configuration.MapODataServiceRoute("odata", routePrefix: null, model: model);
  394. using (HttpServer host = new HttpServer(configuration))
  395. using (HttpClient client = new HttpClient(host))
  396. using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/EnumCustomers"))
  397. {
  398. request.Content = new StringContent(
  399. string.Format(@"{{'@odata.type':'#System.Web.OData.Formatter.EnumCustomer',
  400. 'ID':0,'Color':'Green, Blue','Colors':['Red','Red, Blue']}}"));
  401. request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json");
  402. request.Headers.Accept.ParseAdd("application/json;odata.metadata=full");
  403. // Act
  404. using (HttpResponseMessage response = client.SendAsync(request).Result)
  405. {
  406. // Assert
  407. response.EnsureSuccessStatusCode();
  408. dynamic payload = JToken.Parse(response.Content.ReadAsStringAsync().Result);
  409. Assert.Equal("#System.Web.OData.Formatter.EnumCustomer", payload["@odata.type"].Value);
  410. Assert.Equal("#System.Web.OData.Builder.TestModels.Color", payload["Color@odata.type"].Value);
  411. Assert.Equal("#Collection(System.Web.OData.Builder.TestModels.Color)", payload["Colors@odata.type"].Value);
  412. }
  413. }
  414. }
  415. }
  416. [Fact]
  417. public void RequestProperty_HasCorrectContextUrl()
  418. {
  419. // Arrange
  420. ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
  421. builder.EntitySet<EnumCustomer>("EnumCustomers");
  422. IEdmModel model = builder.GetEdmModel();
  423. var controllers = new[] { typeof(EnumCustomersController) };
  424. using (HttpConfiguration configuration = controllers.GetHttpConfiguration())
  425. {
  426. configuration.MapODataServiceRoute("odata", routePrefix: null, model: model);
  427. using (HttpServer host = new HttpServer(configuration))
  428. using (HttpClient client = new HttpClient(host))
  429. // Act
  430. using (HttpResponseMessage response = client.GetAsync("http://localhost/EnumCustomers(5)/Color").Result)
  431. {
  432. // Assert
  433. response.EnsureSuccessStatusCode();
  434. JObject payload = JObject.Parse(response.Content.ReadAsStringAsync().Result);
  435. Assert.Equal("http://localhost/$metadata#EnumCustomers(5)/Color", payload.GetValue("@odata.context"));
  436. }
  437. }
  438. }
  439. [Fact]
  440. public void ODataCollectionSerializer_SerializeIQueryableOfIEdmEntityObject()
  441. {
  442. // Arrange
  443. ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
  444. builder.EntitySet<CollectionSerializerCustomer>("CollectionSerializerCustomers");
  445. IEdmModel model = builder.GetEdmModel();
  446. var controllers = new[] { typeof(CollectionSerializerCustomersController) };
  447. using (HttpConfiguration configuration = controllers.GetHttpConfiguration())
  448. {
  449. configuration.MapODataServiceRoute("odata", routePrefix: null, model: model);
  450. using (HttpServer host = new HttpServer(configuration))
  451. using (HttpClient client = new HttpClient(host))
  452. using (HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/CollectionSerializerCustomers?$select=ID"))
  453. {
  454. // Act
  455. using (HttpResponseMessage response = client.SendAsync(request).Result)
  456. {
  457. // Assert
  458. response.EnsureSuccessStatusCode();
  459. }
  460. }
  461. }
  462. }
  463. public class EnumCustomer
  464. {
  465. public int ID { get; set; }
  466. public Color Color { get; set; }
  467. public List<Color> Colors { get; set; }
  468. }
  469. public class EnumCustomersController : ODataController
  470. {
  471. public IHttpActionResult Post(EnumCustomer customer)
  472. {
  473. return Ok(customer);
  474. }
  475. public IHttpActionResult GetColor(int key)
  476. {
  477. return Ok(Color.Green);
  478. }
  479. }
  480. public class CollectionSerializerCustomer
  481. {
  482. public int ID { get; set; }
  483. public string Name { get; set; }
  484. }
  485. public class CollectionSerializerCustomersController : ODataController
  486. {
  487. public IHttpActionResult Get(ODataQueryOptions<CollectionSerializerCustomer> options)
  488. {
  489. IQueryable<CollectionSerializerCustomer> customers = new[]
  490. {
  491. new CollectionSerializerCustomer{ID = 1, Name = "Name 1"},
  492. new CollectionSerializerCustomer{ID = 2, Name = "Name 2"},
  493. new CollectionSerializerCustomer{ID = 3, Name = "Name 3"},
  494. }.AsQueryable();
  495. IQueryable<IEdmEntityObject> appliedCustomers = options.ApplyTo(customers) as IQueryable<IEdmEntityObject>;
  496. return Ok(appliedCustomers);
  497. }
  498. }
  499. private static void AddDataServiceVersionHeaders(HttpRequestMessage request)
  500. {
  501. request.Headers.Add("OData-Version", "4.0");
  502. request.Headers.Add("OData-MaxVersion", "4.0");
  503. }
  504. private static void AssertODataVersion4JsonResponse(string expectedContent, HttpResponseMessage actual)
  505. {
  506. Assert.NotNull(actual);
  507. Assert.Equal(HttpStatusCode.OK, actual.StatusCode);
  508. Assert.Equal(ODataTestUtil.ApplicationJsonMediaTypeWithQuality.MediaType,
  509. actual.Content.Headers.ContentType.MediaType);
  510. Assert.Equal(ODataTestUtil.Version4NumberString,
  511. ODataTestUtil.GetDataServiceVersion(actual.Content.Headers));
  512. ODataTestUtil.VerifyResponse(actual.Content, expectedContent);
  513. }
  514. private static Uri CreateAbsoluteUri(string relativeUri)
  515. {
  516. return new Uri(new Uri(baseAddress), relativeUri);
  517. }
  518. private static HttpConfiguration CreateConfiguration(bool tracingEnabled = false)
  519. {
  520. IEdmModel model = ODataTestUtil.GetEdmModel();
  521. HttpConfiguration configuration = CreateConfiguration(model);
  522. if (tracingEnabled)
  523. {
  524. configuration.Services.Replace(typeof(ITraceWriter), new Mock<ITraceWriter>().Object);
  525. }
  526. return configuration;
  527. }
  528. private static HttpConfiguration CreateConfiguration(IEdmModel model)
  529. {
  530. HttpConfiguration configuration =
  531. new[]
  532. {
  533. typeof(MainEntityController), typeof(PeopleController), typeof(EnumCustomersController),
  534. typeof(CollectionSerializerCustomersController), typeof(PresidentController)
  535. }.GetHttpConfiguration();
  536. configuration.MapODataServiceRoute(model);
  537. configuration.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create());
  538. return configuration;
  539. }
  540. private static IEdmModel CreateModelForFullMetadata(bool sameLinksForIdAndEdit, bool sameLinksForEditAndRead)
  541. {
  542. ODataModelBuilder builder = ODataModelBuilderMocks.GetModelBuilderMock<ODataModelBuilder>();
  543. EntitySetConfiguration<MainEntity> mainSet = builder.EntitySet<MainEntity>("MainEntity");
  544. Func<EntityInstanceContext<MainEntity>, Uri> idLinkFactory = (e) =>
  545. CreateAbsoluteUri("/MainEntity/id/" + e.GetPropertyValue("Id").ToString());
  546. mainSet.HasIdLink(idLinkFactory, followsConventions: true);
  547. if (!sameLinksForIdAndEdit)
  548. {
  549. Func<EntityInstanceContext<MainEntity>, Uri> editLinkFactory =
  550. (e) => CreateAbsoluteUri("/MainEntity/edit/" + e.GetPropertyValue("Id").ToString());
  551. mainSet.HasEditLink(editLinkFactory, followsConventions: false);
  552. }
  553. if (!sameLinksForEditAndRead)
  554. {
  555. Func<EntityInstanceContext<MainEntity>, Uri> readLinkFactory =
  556. (e) => CreateAbsoluteUri("/MainEntity/read/" + e.GetPropertyValue("Id").ToString());
  557. mainSet.HasReadLink(readLinkFactory, followsConventions: false);
  558. }
  559. EntityTypeConfiguration<MainEntity> main = mainSet.EntityType;
  560. main.HasKey<int>((e) => e.Id);
  561. main.Property<short>((e) => e.Int16);
  562. NavigationPropertyConfiguration mainToRelated = mainSet.EntityType.HasRequired((e) => e.Related);
  563. main.Action("DoAlways").ReturnsCollectionFromEntitySet<MainEntity>("MainEntity").HasActionLink((c) =>
  564. CreateAbsoluteUri("/MainEntity/DoAlways/" + c.GetPropertyValue("Id")),
  565. followsConventions: true);
  566. main.TransientAction("DoSometimes").ReturnsCollectionFromEntitySet<MainEntity>(
  567. "MainEntity").HasActionLink((c) =>
  568. CreateAbsoluteUri("/MainEntity/DoSometimes/" + c.GetPropertyValue("Id")),
  569. followsConventions: false);
  570. mainSet.HasNavigationPropertyLink(mainToRelated, (c, p) => new Uri("/MainEntity/RelatedEntity/" +
  571. c.GetPropertyValue("Id"), UriKind.Relative), followsConventions: true);
  572. EntitySetConfiguration<RelatedEntity> related = builder.EntitySet<RelatedEntity>("RelatedEntity");
  573. return builder.GetEdmModel();
  574. }
  575. private static HttpRequestMessage CreateRequest(string pathAndQuery, MediaTypeWithQualityHeaderValue accept)
  576. {
  577. HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, CreateAbsoluteUri(pathAndQuery));
  578. request.Headers.Accept.Add(accept);
  579. return request;
  580. }
  581. private static HttpRequestMessage CreateRequestWithDataServiceVersionHeaders(string pathAndQuery,
  582. MediaTypeWithQualityHeaderValue accept)
  583. {
  584. HttpRequestMessage request = CreateRequest(pathAndQuery, accept);
  585. AddDataServiceVersionHeaders(request);
  586. return request;
  587. }
  588. private class CustomFeedSerializer : ODataFeedSerializer
  589. {
  590. public CustomFeedSerializer(ODataSerializerProvider serializerProvider)
  591. : base(serializerProvider)
  592. {
  593. }
  594. public override ODataFeed CreateODataFeed(IEnumerable feedInstance, IEdmCollectionTypeReference feedType,
  595. ODataSerializerContext writeContext)
  596. {
  597. ODataFeed feed = base.CreateODataFeed(feedInstance, feedType, writeContext);
  598. // Int32
  599. ODataPrimitiveValue intValue = new ODataPrimitiveValue(321);
  600. feed.InstanceAnnotations.Add(new ODataInstanceAnnotation("Custom.Int32Annotation", intValue));
  601. // String
  602. ODataPrimitiveValue stringValue = new ODataPrimitiveValue("My amazing feed");
  603. feed.InstanceAnnotations.Add(new ODataInstanceAnnotation("Custom.StringAnnotation", stringValue));
  604. return feed;
  605. }
  606. }
  607. private class CustomSerializerProvider : DefaultODataSerializerProvider
  608. {
  609. public override ODataEdmTypeSerializer GetEdmTypeSerializer(IEdmTypeReference edmType)
  610. {
  611. if (edmType.IsCollection() && edmType.AsCollection().ElementType().IsEntity())
  612. {
  613. return new CustomFeedSerializer(this);
  614. }
  615. return base.GetEdmTypeSerializer(edmType);
  616. }
  617. }
  618. }
  619. public class MainEntity
  620. {
  621. public int Id { get; set; }
  622. public short Int16 { get; set; }
  623. public RelatedEntity Related { get; set; }
  624. }
  625. public class RelatedEntity
  626. {
  627. public int Id { get; set; }
  628. }
  629. public class MainEntityController : ODataController
  630. {
  631. public IEnumerable<MainEntity> Get()
  632. {
  633. MainEntity[] entities = new MainEntity[]
  634. {
  635. new MainEntity
  636. {
  637. Id = 1,
  638. Int16 = -1,
  639. Related = new RelatedEntity
  640. {
  641. Id = 101
  642. }
  643. },
  644. new MainEntity
  645. {
  646. Id = 2,
  647. Int16 = -2,
  648. Related = new RelatedEntity
  649. {
  650. Id = 102
  651. }
  652. }
  653. };
  654. return new PageResult<MainEntity>(entities, new Uri("aa:b"), 3);
  655. }
  656. }
  657. }