Objectives My objective was to send some extra (non-defined) properties with an entity Product. For example in an an AngularJs listing view, I need to show some products as links(accessible) and others not accessible based on the permissions calculated from current user (which I get from session)' data and the productId.
What forces me to have this problem
Now, Odata doesn't allow me to add extra properties while sending a IQueryable result like this.
public IQueryable<Product> GET()
{
return db.Products.AsQueryable<Product>();
}
simply because the returning type is Product and adding extra properties will make it something else, if I try it like this
var result = db.Products.Select(p => new Product
{
ID = p.ID,
Accessible = (code for permission checks),
[other properties...]
}
Solution approached
I approached it with a solution, making OdataController of a new type OdataProduct that has defined properties which I need to send to make a list permission aware. (Do you have any idea how to make lists permissions aware, other than my this solution?)
public class OdataProduct
{
public Product product { get; set; }
public OdataProduct(Product product)
{
this.product = product;
}
//
public void setPermissions(User user, string controller)
{
if (user == null) return;
isAllowed = [permission check code];
}
public bool isAllowed { get; set; }
}
I tried to inherit this OdataProduct
form Product
but faced the problem in downcasting the OdataProduct
to Product
when receiving the POST
requests to save into database. Db.Products.Add();
Now with this ViewModel
and a controller of this type I have successfully sent the permission aware results dependent on current user in session for all Products in the list like this.
public class OdataProductController : ODataController
{
private OfferAssistantDbContext db = new OfferAssistantDbContext();
// GET api/OdataProduct
public IQueryable<OdataProduct> GET()
{
var result = db.Products.AsQueryable<Product>();
var OResult = new List<OdataProduct>();
var currentUser = (User)HttpContext.Current.Session["LoggedUser"];
OdataProduct OProduct;
foreach (var item in result)
{
OProduct = new OdataProduct(item);
OProduct.setPermissions(currentUser, "Product");
OResult.Add(OProduct);
}
return OResult.AsQueryable<OdataProduct>();
}
//other methods of the controller below...
}
Problem I want solution for
When I send a
PATCH
request toOdataProduct
controller, I get aDelta
object that is not Product, if I send a Product in thePayload
and also modify accordingly the Odata parameters ofPATCH
method to receive aProduct
instead ofOdataProduct
it is received as null, while in the default case I am not able to run this command toPATCH
the real entity ofProduct
not theViewModel
. below.var dbProduct = db.Products.Find(key); oDataProduct.Patch((dbProduct); //OdataProduct is not of dbProduct type What is the solution?
Another problem I face is while setting the Permissions of the OdataProduct above
OProduct.setPermissions(currentUser, "Product"); //stepping into thie method the exception line is this.Childs = product.DependantProducts.Where(dp => dp.ParentID == product.ID).Count();
it says the DataReader is already open. Though it is not the main problem but please give some info here too.