Skip to content

Instantly share code, notes, and snippets.

Created October 19, 2016 20:37
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 anonymous/fe97977150b53d542377c32edf66185d to your computer and use it in GitHub Desktop.
Save anonymous/fe97977150b53d542377c32edf66185d to your computer and use it in GitHub Desktop.
/*
* http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/create-an-odata-v4-endpoint
*/
namespace Endpoint.Data.Controllers
{
public abstract class BaseDataController<T> : NavigatableByContextOdataController<T>
where T : BaseEntity
{
[EnableQuery]
public virtual IQueryable<T> Get()
{
return Db.Set<T>();
}
[EnableQuery]
public SingleResult<T> Get([FromODataUri] int key)
{
var result = Db.Set<T>().Where(g => g.Id == key);
return SingleResult.Create(result);
}
public virtual async Task<IHttpActionResult> Post(T entity)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var result = Db.Set<T>().Add(entity);
await Db.CommitAsync();
AfterCreate(result.Id);
return Created(result);
}
public async Task<IHttpActionResult> Patch([FromODataUri] int key, Delta<T> entity)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
var saved = await Db.Set<T>().FindAsync(key);
if (saved == null) return NotFound();
entity.Patch(saved);
try
{
await Db.CommitAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!Exists(key)) return NotFound();
throw;
}
return Updated(saved);
}
public virtual async Task<IHttpActionResult> Put([FromODataUri] int key, T update)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
if (key != update.Id)
{
return BadRequest();
}
Db.Entry(update).State = EntityState.Modified;
try
{
await Db.CommitAsync();
AfterUpdate(key);
}
catch (DbUpdateConcurrencyException)
{
if (!Exists(key)) return NotFound();
throw;
}
return Updated(update);
}
public async Task<IHttpActionResult> Delete([FromODataUri] int key)
{
var entity = await Db.Set<T>().FindAsync(key);
if (entity == null)
{
return NotFound();
}
Db.Set<T>().Remove(entity);
await Db.CommitAsync();
return StatusCode(HttpStatusCode.NoContent);
}
protected IPersister Db { get; }
private bool Exists(int key) => Db.Set<T>().Any(p => p.Id == key);
protected BaseDataController(IPersister context) : base(context) /// do not see here, it is just a persister
{
Db = context;
}
protected override void Dispose(bool disposing)
{
Db.Dispose();
base.Dispose(disposing);
}
protected virtual void AfterCreate(int id) { }
protected virtual void AfterUpdate(int id) { }
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.OData;
/*
* http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-v4/entity-relations-in-odata-v4
*/
namespace MyProject.Odata.Common
{
public abstract class NavigatableOdataController<T>: ODataController
where T: class
{
protected virtual void AddHandler<TNavigationType>(CustomNavigationPropertyHandler<TNavigationType> handler) where TNavigationType : class
{
_handlers[handler.Name] = new Tuple<NavigationPropertyHandler, Type>(handler, typeof(TNavigationType));
}
protected abstract T GetByKey(int key);
protected abstract object GetNavigatuonProperty(int key, Type type);
protected abstract Task CommitAsync();
[AcceptVerbs("POST", "PUT")]
public async Task<IHttpActionResult> CreateRef([FromODataUri] int key, string navigationProperty, [FromBody] Uri link)
{
var entity = GetByKey(key);
if (entity == null) return NotFound();
if (_handlers.ContainsKey(navigationProperty))
{
var relatedKey = UriHelper.GetKeyFromUri<int>(Request, link);
var navigationEntity = GetNavigatuonProperty(relatedKey, _handlers[navigationProperty].Item2);
if (navigationEntity == null)
{
return NotFound();
}
_handlers[navigationProperty].Item1.ForceAdd(entity, navigationEntity);
await CommitAsync();
AfterPropertyChanged(key);
}
else
{
return StatusCode(HttpStatusCode.NotImplemented);
}
return StatusCode(HttpStatusCode.NoContent);
}
[AcceptVerbs("DELETE")]
public async Task<IHttpActionResult> DeleteRef([FromODataUri] int key,
[FromODataUri] string relatedKey, string navigationProperty)
{
var entity = GetByKey(key);
if (entity == null) return NotFound();
if (_handlers.ContainsKey(navigationProperty))
{
var navigationEntity = GetNavigatuonProperty( Convert.ToInt32( relatedKey), _handlers[navigationProperty].Item2);
if (navigationEntity == null)
{
return NotFound();
}
_handlers[navigationProperty].Item1.ForceDel(entity, navigationEntity);
await CommitAsync();
AfterPropertyChanged(key);
}
return StatusCode(HttpStatusCode.NoContent);
}
private readonly Dictionary<string, Tuple<NavigationPropertyHandler, Type>> _handlers = new Dictionary<string, Tuple<NavigationPropertyHandler, Type>>();
#region classes for a help
protected abstract class NavigationPropertyHandler
{
public abstract void ForceAdd(T entity, object navigation);
public abstract void ForceDel(T entity, object navigation);
}
protected class CustomNavigationPropertyHandler<N> : NavigationPropertyHandler
where N: class
{
public CustomNavigationPropertyHandler(string name, Action<T, N> addHandler, Action<T, N> delHandler)
{
Name = name;
_addHandler = addHandler;
_delHandler = delHandler;
}
public string Name { get; private set; }
private readonly Action<T, N> _addHandler;
private readonly Action<T, N> _delHandler;
public override void ForceAdd(T entity, object navigation)
{
var castedEntity = entity as T;
var castedNavigation = navigation as N;
if (castedEntity == null)
{
throw new ArgumentException($"Cannot cast to {typeof(T).ToString()}");
}
if (castedNavigation == null)
{
throw new ArgumentException($"Cannot cast to {typeof(N).ToString()}");
}
_addHandler(castedEntity, castedNavigation);
}
public override void ForceDel(T entity, object navigation)
{
var castedEntity = entity as T;
var castedNavigation = navigation as N;
if (castedEntity == null)
{
throw new ArgumentException($"Cannot cast to {typeof(T).ToString()}");
}
if (castedNavigation == null)
{
throw new ArgumentException($"Cannot cast to {typeof(N).ToString()}");
}
_delHandler(castedEntity, castedNavigation);
}
}
#endregion
protected virtual void AfterPropertyChanged(int id) { }
}
}
{
public class SimpleController : BaseDataController<MyEntity>
{
public SimpleController()
{
InitializeNavigationPropertisOperations();
}
private void InitializeNavigationPropertisOperations()
{
AddHandler(new CustomNavigationPropertyHandler<CollectionProperty>("CollectionProperty", AddCollectionProperty, DelCollectionProperty));
AddHandler(new CustomNavigationPropertyHandler<SingleProperty>("SingleProperty", AddSingleProperty, DelSingleProperty));
}
private static void AddCollectionProperty(MyEntity myEntity, CollectionProperty element)
{
myEntity.CollectionProperty.Add(element);
}
private static void DelCollectionProperty(MyEntity myEntity, CollectionProperty element)
{
myEntity.CollectionProperty.Remove(element);
}
private static void AddSingleProperty(MyEntity myEntity, SingleProperty property)
{
myEntity.SingleProperty = property;
}
private static void DelSingleProperty(MyEntity myEntity, SingleProperty property)
{
myEntity.SingleProperty = null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment