Reputation: 13763
I have just started working with Web Api OData and I find myself wanting to do something that I was able to do a standard ApiController, that is get an object from a field other than the Id field. I know it is standard to do this for example when getting an object based on it's Id :
[Queryable]
public SingleResult<Group> GetGroup([FromODataUri] int key)
{
return SingleResult.Create(db.Groups.Where(group => group.GroupId == key));
}
But if I want to get group by groupName field for example, what would I do? I have tried this as something similar worked with an ApiController :
Controller :
public Group GetGroup([FromODataUri] string groupName)
{
var group = _repository.GetGroupByGroupName(groupName);
if (group == null)
{
throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotFound));
}
return group;
}
Repository :
public Group GetGroupByGroupName(string groupName)
{
Group group = (from u in _db.Groups
where u.GroupName == groupName
select u).FirstOrDefault();
return group;
}
My WebApiConfig looks like this :
public static void Register(HttpConfiguration config)
{
config.EnableCors();
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling =
Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);
// OData
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<City>("Cities");
modelBuilder.EntitySet<Stage>("Stages");
modelBuilder.EntitySet<Team>("Teams");
modelBuilder.EntitySet<Fixture>("Fixtures");
modelBuilder.EntitySet<Roster>("Rosters");
modelBuilder.EntitySet<Standing>("Standings");
modelBuilder.EntitySet<Group>("Groups");
var model = modelBuilder.GetEdmModel();
config.Routes.MapODataRoute("ODataRoute", "odata", model);
}
I want to be able to get a group object based on a groupname using odata/Groups/GroupName, but what I currently have does not work. How would I do this, or am I approaching this from totally the wrong direction?
Upvotes: 3
Views: 2347
Reputation: 5995
Let's say you STILL need to call a custom function. OData V4 allows that. The question is a bit old but I believe it is still valid today.
First, you need to specify a Namespace to the ODataConventionModelBuilder since OData V4 needs this for actions and functions:
var builder = new ODataConventionModelBuilder();
builder.Namespace = "Default";
Be aware that this might result in IIS giving 404 because the dot is interpreted by IIS. To prevent this, add the following to your Web.config:
<system.webServer>
<handlers>
<clear/>
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="/*"
verb="*" type="System.Web.Handlers.TransferRequestHandler"
preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>
</system.webServer>
then, you need to declare the function too:
builder.EntitySet<Group>("Groups").EntityType
.Collection
.Function("GetGroupByName")
.ReturnsFromEntitySet<Group>("Groups")
.Parameter<string>("name");
Notice the function is declared on the COLLECTION, so it's bound to it. Then the ODataController method:
[ODataRoute("Groups/Default.GetGroupByName(name={name})")]
[HttpGet]
public IHttpActionResult GetGroupByName([FromODataUri]string name)
{
return Ok(new Group() or whatever);
}
Here the ODataRoute annotation is necessary only if you use a parameter. It defines in order: the entityset, the namespace, the method and the parameters.
You can then use:
http://localhost:xxxx/api/Groups/Default.GetByGroupName(name='sausage')
Also, see this SO answer to pass multiple parameters
Upvotes: 1
Reputation: 15379
You are already using QueryableAttribute
so if you define something like:
[Queryable]
public IQueryable<Group> Get()
{
// Returns all groups as a queryable (do not execute query here!)
}
You can then access this with an ajax request and any odata query, like:
http://server/Api/Group?$filter=GroupName eq 'test'
The query is built on the client, not restricted by server parameters.
Upvotes: 1