Skip to content

Instantly share code, notes, and snippets.

@raghuramn
Created March 4, 2013 19:13
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save raghuramn/5084608 to your computer and use it in GitHub Desktop.
Save raghuramn/5084608 to your computer and use it in GitHub Desktop.
Sample showing how to implement ~/entityset/key/property kind of url support in web API OData. Run and try the url http://localhost:8080/customers(42)/ID or http://localhost:8080/customers(42)/Name for a demo.
using System;
using System.Linq;
using System.Linq.Expressions;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.ServiceModel;
using System.Web.Http;
using System.Web.Http.OData;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Formatter;
using System.Web.Http.OData.Routing;
using System.Web.Http.SelfHost;
using Microsoft.Data.Edm;
namespace ODataTests
{
class Program
{
static void Main(string[] args)
{
HttpSelfHostConfiguration config = new HttpSelfHostConfiguration("http://localhost:8080");
config.HostNameComparisonMode = HostNameComparisonMode.Exact;
config.Routes.MapODataRoute("default", "", GetEdmModel());
config.Formatters.Clear();
config.Formatters.InsertRange(0, ODataMediaTypeFormatters.Create());
HttpSelfHostServer server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
Console.WriteLine("started..");
Console.ReadKey();
}
private static IEdmModel GetEdmModel()
{
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<Customer>("customers");
return builder.GetEdmModel();
}
}
public class CustomersController : ODataController
{
[AcceptVerbs("GET", "POST", "PUT", "POST", "PATCH", "MERGE")]
public HttpResponseMessage HandleUnmappedRequest(ODataPath odataPath)
{
// Handle property GET.
if (Request.Method == HttpMethod.Get &&
(odataPath.PathTemplate == "~/entityset/key/property" ||
odataPath.PathTemplate == "~/entityset/key/cast/property"))
{
string propertyName = (odataPath.Segments.Last() as PropertyAccessPathSegment).PropertyName;
string key = (odataPath.Segments[1] as KeyValuePathSegment).Value;
// replace with code to get the entity by key.
var customer = new Customer { ID = 42 };
// use reflection to get the property. replace with code specific to your provider.
PropertyInfo property = customer.GetType().GetProperty(propertyName);
object propertyValue = property.GetValue(customer);
// use the custom CreateResponse overload.
return Request.CreateResponse(HttpStatusCode.OK, property.PropertyType, propertyValue);
}
throw new HttpResponseException(HttpStatusCode.BadRequest);
}
}
public static class HttpRequestMessageExtensions
{
private static MethodInfo _createResponse = InitCreateResponse();
private static MethodInfo InitCreateResponse()
{
Expression<Func<HttpRequestMessage, HttpResponseMessage>> expr =
(request) => request.CreateResponse<object>(HttpStatusCode.OK, default(object));
return (expr.Body as MethodCallExpression).Method.GetGenericMethodDefinition();
}
// Content negotiation doesn't use the runtime type of the object. This helper method is CreateResponse overload that passes
// the specified type to content negotiation.
public static HttpResponseMessage CreateResponse(this HttpRequestMessage request, HttpStatusCode status, Type type, object value)
{
return _createResponse.MakeGenericMethod(type).Invoke(null, new[] { request, status, value }) as HttpResponseMessage;
}
}
public class Customer
{
public int ID { get; set; }
public string Name { get; set; }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment