I have been studying OData for a while and I am facing a specific requirement which I couldn't find a solution for, which is calling a function in OData with the parameters surrounded by slashes, in other words, I need to accomplish this: /entity/key/functionName/param1/param2/param3/ I have tried using [RoutePrefix("/entity/{key}/functionName/{param1}/{param2}..."]
without any success.
The action was like this:
public IHttpActionResult functionName(int key, int param1, int param2...)
I know that you can have this result by using [RoutePrefix("/entity({key}/functionName(param1={param1}....). But this is not what I want.
Does anybody has any idea if is it accomplishable?
OData is effectively a specification for how to communicate with a webservice. It defines how to sort, select and filter but also how to call functions. What you are suggesting here is to call a function but not in the way that OData specifies so asking whether it can be done in OData doesn't really make any sense. I would either try and achieve it separately from OData, i.e. just using regular Web.API or try use the existing OData format, otherwise you will need to rewrite a large part of the OData library
Related
I have the GET method in my Spring REST controller. This method returns the list of users by the filter.
I have a few ways to implement it:
Add #PathVariable like - /users/{type}/{age}/{name}/...(bad approach in this case)
Add #RequestParam like - /users?type=type,age=age,name=name...(usual approach in this case)
Use RequestDto (the best approach) like
public class UsersRequestDto {
private String type;
private int age;
private String name;
...
}
But I can not use GET method for this. I must use POST method with #RequestBody
And it breaks the rules. My method doesn't change state and doesn't create any entities. It workes as the GET method but in reality, it is POST.
And I have 2 ways:
Use the GET method with many parameters
Use the POST method with DTO which works as the GET method and confuses users.
Which way is better?
Short version: you might be looking for How to bind #RequestParam to object in Spring. (See also: https://stackoverflow.com/a/16942352/54734 )
On the web, we would have an html form with a GET action. When the form is submitted, the browser would process the input controls and create the application/x-www-form-urlencoded representation of the form data. For a GET action, that representation is used as the query string.
Using GET, and encoding all of the information into the query string, allows us to take advantage of general purpose caching of the results.
But the query parameters aren't accessible by themselves - they are actually embedded within the larger context of the HTTP request. We don't usually see that because, once again, general purpose components can do a lot of the heavy lifting.
So we don't see the parser that extracts the target-uri from the request, or the parser that splits the target URI into its separate components, or the parser that splits the query part into a sequence of key value pairs....
In general, what we do is ride the "general purpose" implementation as far as we can, then get off and do the rest of the work ourselves. If the framework offered no better support for object mapping, that could mean implementing that mapping ourselves.
So if our framework lacked the capability to map the query string directly to an object representation, we would hand roll that part of the implementation ourselves (either by copying each parameter "by hand", or writing our own reflection code to do the mapping automagically).
But it seems that Spring has that capability already built into it; and that it is the default option (no annotation required); you just have to be sure that the object implementation provides the interface that Spring needs to execute the mapping.
How many different parameters are you including in your query?
Personally, I prefer the option of a GET method with many different parameters. It has other benefits such as being cacheable as well. Also, compare it to something like a the URL that a Google search generates - lots of query string parameters.
The POST option feels dirty - it's a violation of what a POST should actually do (creating or updating a resource).
See these discussions: https://softwareengineering.stackexchange.com/questions/233164/how-do-searches-fit-into-a-restful-interface and REST API Best practices: Where to put parameters?
1st of all when you are using RequestParam then key will be added with & symbol not with comma(,) .
when you want to filter ( as you have mentioned) something then best approach would be to use RequestParam.
To minimize the code you can opt to "MultiValueMap" or "HttpservletRequest" .
1)HttpServletRequest
#GetMapping("/user")
public List<User> getFilteredUser(HttpServletRequest httpservlet)
httpservlet.getQuesryString() //will return all request param.
2)MultiValueMap
#RequestParam MultiValueMap<String,String> params
NOTE:- Generally POST is for create/update record.
I like OData and I was particularly pleased to its adoption by the ASP.NET Web API.
I've created a few services for internal applications to consume, but never for public consumption. The primary reason is that the open nature of OData seems to make it very hard to make "safe" against abuse.
Most specifically, I'm worried that given the power to run arbitrary queries, a user could express a complex query which stresses the operational system to the point where the experience is bad for all other users.
In a WebApi controller, an OData endpoint is exposed as follows:
public class OrderController
{
[Queryable]
public IQueryable<Orders> Get()
{
// Compose and return the IQueryable<Orders>
}
}
This gives full control over the process of composition and execution of the query, but does so though the complex IQuerable<T> interface. It makes it trivial to give the user a subset of the information, e.g. append a Where to only include the records they have permission to access.
Is there an IQueryable<T> implementation that can wrap an existing IQuerable<T> instance to provide restrictions on the queries a user can run? I'm most interested in restricting the complexity of the query, but I also want to be able to prevent a user traversing associations to resources they shouldn't have access to.
I think you'll be glad to learn that in RTM, we've added options to let you customize what kind of querying you want to expose to users. So you can do this for example:
[Queryable(
AllowedFunctions = AllowedFunctions.AllStringFunctions,
AllowedLogicalOperators = AllowedLogicalOperators.Equal,
AllowedOrderByProperties = "ID")]
and restrict your query in a few common ways. If you want to restrict your query even further, there are validation hooks you can plug into, like ODataQueryValidator or by overriding the ValidateQuery method on the [Queryable] attribute.
You can use our nightly builds to get access to these features, or build the latest bits yourself.
Instead of using the Queryable attribute (which you are missing), you can not use this attribute and instead manually accept the ODataQueryOptions parameter, which gives you access to the various filter, top, etc options to permit validation of them.
Any function being called by a OData query can be passed an argument ODataQueryOptions like:
public IQueryable<T> Get(ODataQueryOptions options)`
{
//Use the following vars to fetch the values, and check if
//they are as you expect them to be. etc.
options.Top.RawValue;
options.Filter.Value;
options.Filter.ApplyTo();
}
In this case you can skip the [Queryable] attribute and use ApplyTo to manually apply the various queries over the result. :)
Is there a Web API equivalent to the MVC ActionMethodSelectorAttribute?
My specific purpose is this: I have, for example, a ResourceController and when I POST to the controller, I'd like to be able to receive a single resource (Resource) or a list (IEnumerable<Resource>).
I was hoping creating two methods with different parameters would cause the deserialization process to do some evaluation but this doesn't seem to be the case (and frankly, I don't think it's efficiently realistic with the combination of content negotiation and the fact that many data formats, like JSON, make it difficult to infer the data type). So I originally had:
public HttpResponseMessage Post(Resource resource) {...}
public HttpResponseMessage Post(IEnumerable<Resource> resources) {...}
...but this gets the "multiple actions" error. So I investigated how to annotate my methods and came across ActionMethodSelectorAttribute but also discovered this is only for MVC routing and not Web API.
So... without requiring a different path for POSTing multiple resources vs. one (which isn't the end of the world), what would I do to differentiate?
My thoughts along the ActionMethodSelectorAttribute were to require a query parameter specifying multiple, which I suppose is no different than a different path. So, I think I just eliminated my current need to do this, but I would still like to know if there is an equivalent ActionMethodSelectorAttribute for Web API :)
I haven't seen a replacement for that method (there is an IActionMethodSelector interface but it is internal to the DLL). One option (although it seems like it might be overdoing it) is to overload the IHttpActionSelector implementation that is used.
But changing gears slightly, why not always expect an IEnumerable<Resource>? My first guess is that the collection method (that takes IEnumerable<Resource>) would simply loop and call the single value (just Resource) function?
I have defined a GenericRepository class which does the db interaction.
protected GenericRepository rep = new GenericRepository();
And in my BLL classes, I can query the db like:
public List<Album> GetVisibleAlbums(int accessLevel)
{
return rep.Find<Album>(a => a.AccessLevel.BinaryAnd(accessLevel)).ToList();
}
BinaryAnd is an extension method which checks two int values bit by bit. e.g. AccessLevel=5 => AccessLevel.BinaryAnd(5) and AccessLevel.binaryAnd(1) both return true.
However I cannot use this extension method in my LINQ queries. I get a runtime error as follows:
LINQ to Entities does not recognize the method 'Boolean BinaryAnd(System.Object, System.Object)' method, and this method cannot be translated into a store expression.
Also tried changing it to a custom method but no luck. What are the workarounds?
Should I get all the albums and then iterate them through a foreach loop and pick those which match the AccessLevels?
I realize this already has an accepted answer, I just thought I'd post this in case someone wanted to try writing a LINQ expression interceptor.
So... here is what I did to make translatable custom extension methods: Code Sample
I don't believe this to be a finished solution, but it should hopefully provide a good starting point for anyone brave enough to see it through to completion.
You can only use the core extension methods and CLR methods defined for your EF provider when using Entity Framework and queries on IQueryable<T>. This is because the query is translated directly to SQL code and run on the server.
You can stream the entire collection (using .ToEnumerable()) then query this locally, or convert this to a method that is translatable directly to SQL by your provider.
That being said, basic bitwise operations are supported:
The bitwise AND, OR, NOT, and XOR operators are also mapped to canonical functions when the operand is a numeric type.
So, if you rewrite this to not use a method, and just do the bitwise operation on the value directly, it should work as needed. Try something like the following:
public List<Album> GetVisibleAlbums(int accessLevel)
{
return rep.Find<Album>(a => (a.AccessLevel & accessLevel > 0)).ToList();
}
(I'm not sure exactly how your current extension method works - the above would check to see if any of the flags come back true, which seems to match your statement...)
There are ways to change the linq query just before EF translates it to SQL, at that moment you'd have to translate your ''foreign'' method into a construct translatable by EF.
See an previous question of mine How to wrap Entity Framework to intercept the LINQ expression just before execution? and mine EFWrappableFields extension which does just this for wrapped fields.
I have a semi complicated question regarding Entity Framework4, Lambda expressions, and Data Transfer Objects (DTO).
So I have a small EF4 project, and following established OO principles, I have a DTO to provide a layer of abstraction between the data consumers (GUI) and the data model.
VideoDTO = DTO with getters/setters, used by the GUI
VideoEntity = Entity generated by EF4
My question revolves around the use of the DTO by the GUI (and not having the GUI use the Entity at all), combined with a need to pass a lambda to the data layer. My data layer is a basic repository pattern with Add. Change, Delete, Get, GetList, etc.
Trying to implement a Find method with a signature like so:
public IEnumerable<VideoDTO> Find(Expression<Func<VideoEntity, bool>> exp)
...
_dataModel.Videos.Where(exp).ToList<Video>()
---
My problem/concern is the "exp" needing to be of type VideoEntity instead of VideoDTO. I want to preserve the separation of concerns so that the GUI does not know about the Entity objects. But if I try to pass in
Func<VideoDTO, bool>
I cannot then do a LINQ Where on that expression using the actual data model.
Is there a way to convert a Func<VideoDTO,bool> to a Func<VideoEntity, bool>
Ideally my method signature would accept Func<VideoDTO, bool> and that way the GUI would have no reference to the underlying data entity.
Is this clear enough? Thanks for your help
Thanks for the repliesto both of you.
I'll try the idea of defining the search criteria in an object and using that in the LINQ expression. Just starting out with both EF4 and L2S, using this as a learning project.
Thanks again!
In architectures like CQRS there isn't need for such a conversion at all cause read & write sides of app are separated.
But in Your case, You can't runaway from translation.
First of all - You should be more specific when defining repositories. Repository signature is thing You want to keep explicit instead of generic.
Common example to show this idea - can You tell what indexes You need in Your database when You look at Your repository signature (maybe looking at repository implementation, but certainly w/o looking at client code)? You can't. Cause it's too generic and client side can search by anything.
In Your example it's a bit better cause expression genericness is tied with dto instead of entity.
This is what I do (using NHibernate.Linq, but the idea remains)
public class Application{
public Project Project {get;set;}
}
public class ApplicationRepository{
public IEnumerable<Application> Search(SearchCriteria inp){
var c=Session.Linq<Application>();
var q=c.AsQueryable();
if(!string.IsNullOrEmpty(inp.Acronym))
q=q.Where(a=>a.Project.Acronym.Contains(inp.Acronym));
/*~20 lines of similar code snipped*/
return q.AsQueryable();
}
}
//used by client
public class SearchCriteria{
public string Acronym{get;set;}
/*some more fields that defines how we can search Applications*/
}
If You do want to keep Your expressions, one way would be to define dictionary manually like this:
var d=new Dictionary<Expression<Func<VideoDTO,object>>,
Expression<Func<VideoEntity,object>>{
{x=>x.DtoPropNumberOne,x=>x.EntityPropNumberOne} /*, {2}, {3}, etc.*/
};
And use it later:
//can You spot it?
//client does not know explicitly what expressions dictionary contains
_dataModel.Videos.Where(d[exp]).ToList<Video>();
//and I'm not 100% sure checking expression equality would actually work
If You don't want to write mapping dictionary manually, You will need some advanced techniques. One idea would be to translate dto expression to string and then back to entity expression. Here are some ideas (sorting related though) that might help. Expressions are quite complicated beasts.
Anyway - as I said, You should avoid this. Otherwise - You will produce really fragile code.
Perhaps your design goal is to prevent propagation of the data model entities to the client tier rather than to prevent a dependency between the presentation layer and data model. If viewed that way then there would be nothing wrong with the query being formed the way you state.
To go further you could expose the searchable fields from VideoEntity via an interface (IVideoEntityQueryFields) and use that as the type in the expression.
If you don't want to add an interface to your entities then the more complicated option is to use a VideoEntityQuery object and something that translates an Expression<Func<VideoEntityQuery,bool>> to an Expression<Func<VideoEntity,bool>>.