AFAIK, встроенные соглашения о маршрутизации не включают соглашение о доступе к свойствам. Вам потребуется добавить много действий для каждого доступа к свойству.
Однако, основываясь на этом ресурсе здесь , не так уж сложно добавить пользовательское соглашение о маршрутизации для обработки доступа к свойству шаблон пути: ~/entityset/key/property
Вот соглашение о пользовательской маршрутизации, адаптированное из ссылки, которую я поделился выше
Используемая сборка: Microsoft.As pNet .OData 7.4.1 - подход будет таким же для любой другой библиотеки OData Web API, которую вы можете использовать
Класс, используемый для иллюстрации
public class Product
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
Добавить соглашение о маршрутизации для доступа к свойствам
// Usings
using Microsoft.AspNet.OData.Routing;
using Microsoft.AspNet.OData.Routing.Conventions;
using System;
using System.Linq;
using System.Web.Http.Controllers;
// ...
public class CustomPropertyRoutingConvention : NavigationSourceRoutingConvention
{
private const string ActionName = "GetProperty";
public override string SelectAction(ODataPath odataPath, HttpControllerContext controllerContext, ILookup<string, HttpActionDescriptor> actionMap)
{
if (odataPath == null || controllerContext == null || actionMap == null)
{
return null;
}
if (odataPath.PathTemplate == "~/entityset/key/property" ||
odataPath.PathTemplate == "~/entityset/key/cast/property" ||
odataPath.PathTemplate == "~/singleton/property" ||
odataPath.PathTemplate == "~/singleton/cast/property")
{
var segment = odataPath.Segments.OfType<Microsoft.OData.UriParser.PropertySegment>().LastOrDefault();
if (segment != null)
{
string actionName = FindMatchingAction(actionMap, ActionName);
if (actionName != null)
{
if (odataPath.PathTemplate.StartsWith("~/entityset/key", StringComparison.Ordinal))
{
var keySegment = odataPath.Segments.OfType<Microsoft.OData.UriParser.KeySegment>().FirstOrDefault();
if (keySegment == null || !keySegment.Keys.Any())
throw new InvalidOperationException("This link does not contain a key.");
controllerContext.RouteData.Values[ODataRouteConstants.Key] = keySegment.Keys.First().Value;
}
controllerContext.RouteData.Values["propertyName"] = segment.Property.Name;
return actionName;
}
}
}
return null;
}
public static string FindMatchingAction(ILookup<string, HttpActionDescriptor> actionMap, params string[] targetActionNames)
{
foreach (string targetActionName in targetActionNames)
{
if (actionMap.Contains(targetActionName))
{
return targetActionName;
}
}
return null;
}
}
Добавьте единственный метод в свой контроллер для обработки запроса любого свойства
public class ProductsController : ODataController
{
// ...
[HttpGet]
public IHttpActionResult GetProperty(int key, string propertyName)
{
var product = _db.Products.FirstOrDefault(d => d.Id.Equals(key));
if (product == null)
{
return NotFound();
}
PropertyInfo info = typeof(Product).GetProperty(propertyName);
object value = info.GetValue(product);
return Ok(value, value.GetType());
}
private IHttpActionResult Ok(object content, Type type)
{
var resultType = typeof(OkNegotiatedContentResult<>).MakeGenericType(type);
return Activator.CreateInstance(resultType, content, this) as IHttpActionResult;
}
// ...
}
В вашем WebApiConfig.cs (или аналогичном месте, где вы настраиваете службу)
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<Product>("Products");
var routingConventions = ODataRoutingConventions.CreateDefaultWithAttributeRouting("odata", configuration);
routingConventions.Insert(0, new CustomPropertyRoutingConvention());
configuration.MapODataServiceRoute("odata", "odata", modelBuilder.GetEdmModel(), new DefaultODataPathHandler(), routingConventions);
configuration.Count().Filter().OrderBy().Expand().Select().MaxTop(null);
configuration.EnsureInitialized();
Запрос на свойство Name: /Products(1)/Name
Запрос на свойство Id: /Products(1)/Id