ridermansb
ridermansb

Reputation: 11069

Using OData actions

Versions

To use features like $select and $expand upgraded all packages WebApi and OData for pre-release versions (from 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

Controllers

I have a base class for my API controlers:

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);
    }
}

And a User controller

[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();
    }
}

Goals

An action roles retrieve all the roles for a specific user:
The goal is to retrieve all roles of a user with this URL:
/api/usuarios(67)/roles

I configured my API WebApiConfig as follows:

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;

Error

GET: /api/usuarios(67)/role

"This service doesn't support OData requests in the form '~/entityset/key/action'."

Erro WebAPI OData action

Upvotes: 3

Views: 5913

Answers (1)

Kiran
Kiran

Reputation: 57989

ODataActions should always be POST requests. Can you try modifying your code like the following and see if it resolves the issue?

[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();
}

Also, you need not specify the parameter 'key' while building your model as this key is retrieved from the Uri itself. Updated code below:

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

FYI: you can also look at this nice post from Mike about OData actions: http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-actions

Upvotes: 6

Related Questions