From 68e14c40bd26bdcea4ae402ffce9f113aca43450 Mon Sep 17 00:00:00 2001 From: mirsking Date: Mon, 12 Sep 2016 10:42:36 +0800 Subject: [PATCH] add support --- .../Controllers/PeopleController.cs | 206 ++++++++++++++++++ .../Controllers/TrippinController.cs | 53 ----- .../Helpers.cs | 126 +++++++++++ ...Data.Service.Sample.TrippinInMemory.csproj | 3 +- 4 files changed, 334 insertions(+), 54 deletions(-) create mode 100644 test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/PeopleController.cs delete mode 100644 test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/TrippinController.cs create mode 100644 test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Helpers.cs diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/PeopleController.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/PeopleController.cs new file mode 100644 index 00000000..ce953a48 --- /dev/null +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/PeopleController.cs @@ -0,0 +1,206 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net; +using System.Web.Http; +using System.Web.OData; +using System.Web.OData.Extensions; +using System.Web.OData.Routing; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.OData.Edm; +using Microsoft.OData.Service.Sample.TrippinInMemory.Api; +using Microsoft.OData.Service.Sample.TrippinInMemory.Models; +using Microsoft.Restier.Core; + +namespace Microsoft.OData.Service.Sample.TrippinInMemory.Controllers +{ + public class PeopleController : ODataController + { + private TrippinApi _api; + private TrippinApi Api + { + get + { + if (_api == null) + { + _api = (TrippinApi)this.Request.GetRequestContainer().GetService(); + } + + return _api; + } + } + + /// + /// Restier only supports put and post entity set. + /// Use property name to simulate the bound action. + /// + /// Key of people entity set, parsed from uri. + /// The value of last name to be updated. + /// + [HttpPut] + [ODataRoute("People({key})/LastName")] + public IHttpActionResult UpdatePersonLastName([FromODataUri]string key, [FromBody] string name) + { + var person = Api.People.Single(p => p.UserName == key); + if (Api.UpdatePersonLastName(person, name)) + { + return Ok(); + } + else + { + return NotFound(); + } + } + + [HttpGet] + [ODataRoute("People({key})/Friends/$ref")] + public IHttpActionResult GetRefToFriendsFromPeople([FromODataUri]string key) + { + var entity = Api.People.FirstOrDefault(p => p.UserName == key); + if (entity == null) + { + return NotFound(); + } + + var friends = entity.Friends; + if (friends == null) + { + return NotFound(); + } + + var serviceRootUri = Helpers.GetServiceRootUri(Request); + IList uris = new List(); + foreach (var friend in friends) + { + uris.Add(new Uri(string.Format("{0}/People('{1}')", serviceRootUri, friend.UserName))); + } + + return Ok(uris); + } + + [HttpGet] + [ODataRoute("People({key})/Friends({key2})/$ref")] + public IHttpActionResult GetRefToOneFriendFromPeople([FromODataUri]string key, [FromODataUri]string key2) + { + var entity = Api.People.FirstOrDefault(p => p.UserName == key); + if (entity == null) + { + return NotFound(); + } + + var friends = entity.Friends; + if (friends == null) + { + return NotFound(); + } + + var serviceRootUri = Helpers.GetServiceRootUri(Request); + if (friends.All(t => t.UserName != key2)) + { + return NotFound(); + } + + return Ok(new Uri(string.Format("{0}/People('{1}')", serviceRootUri, key2))); + } + + [HttpPost] + [ODataRoute("People({key})/Friends/$ref")] + public IHttpActionResult CreateRefForFriendsToPeople([FromODataUri]string key, [FromBody] Uri link) + { + var entity = Api.People.FirstOrDefault(p => p.UserName == key); + if (entity == null) + { + return NotFound(); + } + + var relatedKey = Helpers.GetKeyFromUri(Request, link); + var friend = Api.People.SingleOrDefault(t => t.UserName == relatedKey); + if (friend == null) + { + return NotFound(); + } + + entity.Friends.Add(friend); + return StatusCode(HttpStatusCode.NoContent); + } + + [HttpDelete] + [ODataRoute("People({key})/Friends({relatedKey})/$ref")] + public IHttpActionResult DeleteRefToFriendsFromPeople([FromODataUri]string key, [FromODataUri]string relatedKey) + { + var entity = Api.People.FirstOrDefault(p => p.UserName == key); + if (entity == null) + { + return NotFound(); + } + + var friend = entity.Friends.SingleOrDefault(t => t.UserName == relatedKey); + if (friend == null) + { + return NotFound(); + } + + entity.Friends.Remove(friend); + return StatusCode(HttpStatusCode.NoContent); + } + + [HttpGet] + [ODataRoute("People({key})/BestFriend/$ref")] + public IHttpActionResult GetRefToBestFriendFromPeople([FromODataUri]string key) + { + var entity = Api.People.FirstOrDefault(p => p.UserName == key); + if (entity == null) + { + return NotFound(); + } + + var friend = entity.BestFriend; + if (friend == null) + { + return NotFound(); + } + + var serviceRootUri = Helpers.GetServiceRootUri(Request); + var uri = new Uri(string.Format("{0}/People('{1}')", serviceRootUri, friend.UserName)); + return Ok(uri); + } + + [HttpPut] + [ODataRoute("People({key})/BestFriend/$ref")] + public IHttpActionResult CreateRefForBestFriendToPeople([FromODataUri]string key, [FromBody] Uri link) + { + var entity = Api.People.FirstOrDefault(p => p.UserName == key); + if (entity == null) + { + return NotFound(); + } + + var relatedKey = Helpers.GetKeyFromUri(Request, link); + var friend = Api.People.SingleOrDefault(t => t.UserName == relatedKey); + if (friend == null) + { + return NotFound(); + } + + entity.BestFriend = friend; + return StatusCode(HttpStatusCode.NoContent); + } + + [HttpDelete] + [ODataRoute("People({key})/BestFriend/$ref")] + public IHttpActionResult DeleteRefToBestFriendFromPeople([FromODataUri]string key) + { + var entity = Api.People.FirstOrDefault(p => p.UserName == key); + if (entity == null) + { + return NotFound(); + } + + entity.BestFriend = null; + return StatusCode(HttpStatusCode.NoContent); + } + } +} \ No newline at end of file diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/TrippinController.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/TrippinController.cs deleted file mode 100644 index 6b7433cd..00000000 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/TrippinController.cs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System.Linq; -using System.Web.Http; -using System.Web.OData; -using System.Web.OData.Extensions; -using System.Web.OData.Routing; -using Microsoft.Extensions.DependencyInjection; -using Microsoft.OData.Service.Sample.TrippinInMemory.Api; -using Microsoft.Restier.Core; - -namespace Microsoft.OData.Service.Sample.TrippinInMemory.Controllers -{ - public class TrippinController : ODataController - { - private TrippinApi _api; - private TrippinApi Api - { - get - { - if (_api == null) - { - _api = (TrippinApi)this.Request.GetRequestContainer().GetService(); - } - - return _api; - } - } - - /// - /// Restier only supports put and post entity set. - /// Use property name to simulate the bound action. - /// - /// Key of people entity set, parsed from uri. - /// The value of last name to be updated. - /// - [HttpPut] - [ODataRoute("People({key})/LastName")] - public IHttpActionResult UpdatePersonLastName([FromODataUri]string key, [FromBody] string name) - { - var person = Api.People.Single(p => p.UserName == key); - if (Api.UpdatePersonLastName(person, name)) - { - return Ok(); - } - else - { - return NotFound(); - } - } - } -} \ No newline at end of file diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Helpers.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Helpers.cs new file mode 100644 index 00000000..babd6443 --- /dev/null +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Helpers.cs @@ -0,0 +1,126 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Net.Http; +using System.Text.RegularExpressions; +using System.Web; +using System.Web.Http.Routing; +using System.Web.OData.Extensions; +using System.Web.OData.Routing; +using Microsoft.OData.UriParser; + +namespace Microsoft.OData.Service.Sample.TrippinInMemory +{ + public static class Helpers + { + public static TKey GetKeyFromUri(HttpRequestMessage request, Uri uri) + { + if (uri == null) + { + throw new ArgumentNullException("uri"); + } + + string serviceRoot = GetServiceRootUri(request); + uri = RebuildUri(uri, serviceRoot); + var pathHandler = (IODataPathHandler)request.GetRequestContainer().GetService(typeof(IODataPathHandler)); + var odataPath = pathHandler.Parse(serviceRoot, uri.LocalPath, request.GetRequestContainer()); + + var keySegment = odataPath.Segments.OfType().FirstOrDefault(); + if (keySegment == null) + { + throw new InvalidOperationException("The link does not contain a key."); + } + + var value = keySegment.Keys.FirstOrDefault().Value; + return (TKey)value; + } + + public static string GetSessionIdFromString(string str) + { + var match = Regex.Match(str, @"/\(S\((\w+)\)\)"); + if (match.Success) + { + return match.Groups[1].Value; + } + + return default(string); + } + + public static string GetServiceRootUri(HttpRequestMessage request) + { + var urlHelper = request.GetUrlHelper() ?? new UrlHelper(request); + var pathHandler = (IODataPathHandler)request.GetRequestContainer().GetService(typeof(IODataPathHandler)); + string serviceRoot = urlHelper.CreateODataLink( + request.ODataProperties().RouteName, + pathHandler, new List()); + return serviceRoot; + } + + public static Uri RebuildUri(Uri original, string serviceRoot) + { + var serviceRootSessionId = GetSessionIdFromString(serviceRoot); + if (serviceRootSessionId == null) + { + throw new ArgumentNullException("Key in request URI is null."); + } + + var originalSessionId = GetSessionIdFromString(original.ToString()); + if (originalSessionId == null) + { + var uri = default(Uri); + var builder = new UriBuilder(original.Scheme, original.Host, original.Port, + HttpContext.Current.Request.ApplicationPath); + var beforeSessionSegement = new Uri(builder.ToString(), UriKind.Absolute).AbsoluteUri; + var afterSessionSegment = original.AbsoluteUri.Substring(beforeSessionSegement.Length); + + var sessionSegment = string.Format("(S({0}))", HttpContext.Current.Session.SessionID); + var path = CombineUriPaths(beforeSessionSegement, sessionSegment); + path = CombineUriPaths(path, afterSessionSegment); + uri = new Uri(path); + + var uriBuilder = new UriBuilder(uri); + var baseAddressUri = new Uri(serviceRoot, UriKind.Absolute); + uriBuilder.Host = baseAddressUri.Host; + uri = new Uri(uriBuilder.ToString()); + + return uri; + } + + if (originalSessionId.Equals(serviceRootSessionId)) + { + return original; + } + + throw new InvalidOperationException( + String.Format( + CultureInfo.InvariantCulture, + "Key '{0}' in request is not the same with that '{1}' in service root URI.", + originalSessionId, + serviceRootSessionId)); + } + + private static string CombineUriPaths(string path1, string path2) + { + if (path1.EndsWith("/", StringComparison.OrdinalIgnoreCase)) + { + if (path2.StartsWith("/", StringComparison.OrdinalIgnoreCase)) + { + path2 = path2.Substring(1); + } + } + else + { + if (!path2.StartsWith("/", StringComparison.OrdinalIgnoreCase)) + { + path2 = "/" + path2; + } + } + + return path1 + path2; + } + } +} \ No newline at end of file diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Microsoft.OData.Service.Sample.TrippinInMemory.csproj b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Microsoft.OData.Service.Sample.TrippinInMemory.csproj index 5602c7ce..06247f3c 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Microsoft.OData.Service.Sample.TrippinInMemory.csproj +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Microsoft.OData.Service.Sample.TrippinInMemory.csproj @@ -103,10 +103,11 @@ - + Global.asax +