【问题标题】:Using OData actions使用 OData 操作
【发布时间】:2013-05-15 03:13:50
【问题描述】:

版本

为了使用 $select$expand 等功能,升级了所有软件包 WebApi 和 OData 的预发布版本(来自 aspnetwebstack)。

Microsoft.AspNet.WebApi -> 5.0.0-beta1-130514
Microsoft.AspNet.WebApi.Client -> 5.0.0-beta1-130514
Microsoft.AspNet.WebApi.Core -> 5.0.0-beta1-130514
Microsoft.AspNet.WebApi.OData -> 5.0.0-beta1-130514
Microsoft.AspNet.WebApi.Web... -> 5.0.0-beta1-130514

控制器

我的 API 控制器有一个基类:

public class baseApiController<T> : EntitySetController<T, int>
    where T: class, IEntity, new()
{
    public IRepository Repositorio { get; private set; }
    public baseApiController(IRepository repositorio)
    {
        Repositorio = repositorio;
    }

    [Queryable(AllowedQueryOptions = AllowedQueryOptions.All, PageSize=20)]
    public override IQueryable<T> Get()
    {
        return Repositorio.Query<T>();
    }

    [Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
    protected override T GetEntityByKey(int key)
    {
        return Repositorio.Get<T>(key);
    }
}

还有一个用户控制器

[Authorize]
public class usuariosController : baseApiController<Usuario>
{
    public usuariosController(IRepository repositorio)
        : base(repositorio)
    { }

    [Authorize(Roles="Admin,TI")]
    public HttpResponseMessage post(Usuario usuario)
    {
        var x = WebSecurity.CreateUserAndAccount(usuario.Email, "maisbb", new { Nome = usuario.Nome }); //TODO: Não fixar senha
        Repositorio.Store(usuario);

        return Request.CreateResponse(HttpStatusCode.OK, usuario);
    }

    [HttpGet, Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
    public IQueryable roles([FromODataUri] int key) 
    {
        var usuario = (from u in Repositorio.Query<Usuario>()
                    where u.Id == key
                    select new { u.Email }).SingleOrDefault();
        return Roles.GetRolesForUser(usuario.Email).AsQueryable();
    }
}

目标

动作roles 检索特定用户的所有角色:
目标是使用以下 URL检索用户的所有角色
/api/usuarios(67)/roles

我将我的 API WebApiConfig 配置如下:

modelBuilder.EntitySet<Usuario>("usuarios");
var entityTypeUsuario = modelBuilder.Entity<Usuario>();
var actRoles = entityTypeUsuario.Action("roles");
actRoles.Parameter<int>("key");
actRoles.Returns<string[]>();

...

var model = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute(routeName: "OData", routePrefix: "api", model: model);
config.EnableQuerySupport();
var jsonFormatter = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
var enumConverter = new StringEnumConverter();
jsonFormatter.SerializerSettings.Converters.Add(enumConverter);
config.Formatters.Remove(config.Formatters.XmlFormatter);
var jqueryFormatter = config.Formatters.FirstOrDefault(x => x.GetType() == typeof(JQueryMvcFormUrlEncodedFormatter));
config.Formatters.Remove(config.Formatters.XmlFormatter);
config.Formatters.Remove(config.Formatters.FormUrlEncodedFormatter);
config.Formatters.Remove(jqueryFormatter);
config.Formatters.JsonFormatter.SerializerSettings.DateFormatHandling = DateFormatHandling.IsoDateFormat;

错误

获取:/api/usuarios(67)/role

“此服务不支持 '~/entityset/key/action' 形式的 OData 请求。”

【问题讨论】:

标签: asp.net-web-api odata


【解决方案1】:

ODataActions 应该始终是 POST 请求。您可以尝试如下修改您的代码,看看是否能解决问题?

[HttpPost, Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
public IQueryable roles([FromODataUri] int key, ODataActionParameters parameters) 
{
    var usuario = (from u in Repositorio.Query<Usuario>()
                where u.Id == key
                select new { u.Email }).SingleOrDefault();
    return Roles.GetRolesForUser(usuario.Email).AsQueryable();
}

此外,您需要在构建模型时指定参数“key”,因为此密钥是从 Uri 本身检索的。更新代码如下:

modelBuilder.EntitySet<Usuario>("usuarios");
var entityTypeUsuario = modelBuilder.Entity<Usuario>();
var actRoles = entityTypeUsuario.Action("roles");
actRoles.Returns<string[]>();

仅供参考:您还可以查看 Mike 的这篇关于 OData 操作的精彩帖子:http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-actions

【讨论】:

  • 在这种情况下,使用 POST 是有意义的,因为只检索用户的角色,而不是在 server 上进行更改。如何创建为 GET?
  • 理想情况下,您正在寻找 OData 函数(您可以在其中使用 GET),目前不支持开箱即用。此外,如果您期望操作的任何参数,它们将来自正文,因此您将无法使用 GET。好奇的可以看一下OData中的ActionRoutingConvention,看看我们专门检查POST请求:aspnetwebstack.codeplex.com/SourceControl/latest#src/…
  • 为什么我不能这样做:public string[] GetRoles([FromODataUri] int key) {// Code here}
  • 您可以创建自己的自定义路由约定,类似于我提供的上述链接来实现这一点,但是当服务的元数据被公开时,它指示(通过 FunctionImport 元素)该操作是“IsSideEffecting =true”,这意味着该操作可能会导致副作用,而对于 OData 函数,此值为“假”。因此,看到“IsSideEffecting=true”的客户端很可能会使用“POST”,因为它知道这是一个动作并且它具有副作用并且它可以发布数据以更改状态。
  • 不支持获取!设计:动作将像今天的导航属性一样在有效负载中进行广告,但有两个不同之处:您不能只关注动作的链接;它们有副作用,因此需要 POST。有时动作也需要额外的参数。来自“odata.org/2011/10/actions-in-odata
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多