Foreign Keys in Web API 2 - Best practices? - entity-framework

Basically I'm writing an API using Web API 2 and Entity Framework on the backend.
The thing I'm unsure about is what to do in regards to foreign keys on my models.
Say I got a person property with a foreign key to an order property.
Sometimes the client needs the person property, sometimes it does not. How should I go about this?
Should I create 2 methods:
/api/person/1 <-- returns person without order
/api/personwithorder/1 <-- returns person with order
Seems like an awful lot of methods in my opinion.
I know the queryable attribute exists as well which provides support for the client to use the $extend argument to include properties at will - however I would rather not use the queryable attribute if I can avoid it.
What are your suggestions?

Off the top of my head, here are some options.
Option 1
Multiple methods in API
public Person GetPerson() { ... }
public Person GetPersonWithOrders() { ... }
Option 2
Pass a flag to the method:
public Person GetPerson(bool getOrders) { ... }
Option 3
You could use OData to allow the caller to query the data.

To expand on DavidG's option 3 of using OData, here is how you'd do it:
Install-package Microsoft.AspNet.WebApi.OData
Create a PeopleController inheriting from ODataController
Configure the Web API OData model like so:
modelBuilder.EntitySet<Person>("People");
Define your Get method as returning an IQueryable<Person>
In your calling code, add the expand clause to the URL to specify the child object you would like to expose, like this: /api/People(1)?$expand=Orders
There's a little bit more to it around registering the OData route, but this is all standard configuration that you can find in any sample project.
OData is really very flexible and takes care of tonnes of issues about how you should build your URLs.

Related

Odd JSON Property Name With Combination of Spring Data Web Support, Pageables, Projections, and HATEOAS

I'm having an issue with the HAL output that I get when combining Spring Data Web Support, Pageables, Projections, and HATEOAS.
I have a JPA entity, with an interface projection. I have a JPA repository with a findAllProjectedBy(Pageable).
public interface FeatureRepository extends JpaRepository<Feature, Long> {
Page<FeatureDataLoad> findAllProjectedBy(Pageable pageable);
}
I have a REST controller like this.
#GetMapping("/features")
public ResponseEntity<PagedResources<Resource<FeatureDataLoad>>> exportFeatures(
Pageable pageable,
PagedResourcesAssembler<FeatureDataLoad> assembler) {
Page<FeatureDataLoad> page = featureRepository.findAllProjectedBy(pageable);
PagedResources<Resource<FeatureDataLoad>> resource = assembler.toResource(page);
return new ResponseEntity<PagedResources<Resource<FeatureDataLoad>>>(resource, HttpStatus.OK);
}
This works well and is surprisingly easily, but when combining all of these features, I get something odd in the HAL rendering.
{
"_embedded": {
"tupleBackedMapList": [
{
"property": "value" /* etc. */
}
]
},
"_links": { /* standard links */ },
"page": { /* standard pagination info */ }
}
Pretty amazing, given the amount of extra work I had to do to get HAL and REST support for my existing entities. But, what's up with "tupleBackedMapList"? Without the projection, I get what I expected, "featureList".
I can't find how I would either fix this, or "customize" the generation of that part.
I seems minor, but I'm trying to "sell" the organization of adopting HAL and I'm this seems too weird.
I'm not wanting to drop the projection because the Feature entity has a computed column that I need for the rest of the app, but it almost doubles the query time.
For what it's worth, I'm on Spring Boot 2.1.6.RELEASE.
Edit
After some experimentation, found that if I make the entity class implement the projection interface, I get what I want. The documentation for Spring Data doesn't say you should put the interface on the entity, but I'm OK with that.
(It looks OK if I implement the interface, but it ignores the projection.)
Also, for what it's worth, I tried using #Relation to name the collection and that didn't help, but it did make the property name change. Oddly enough, if I use the #Relation annotation, it turns the property name to content which is what documentation says it should be.
Maybe I'll make a feature request to honor HATEOAS metadata annotations.
Edit 2
I worked around this by putting the common attributes in a #MappedSuperclass that I called FeatureBase and then made a Feature that extended that super class and added the expensive column computation and made a FeatureDataLoad that just extended the base. It was annoying, so I'd still like a real solution because projections are too easy otherwise.
And again, if this was the third or fourth service in HAL, I'd probably not worry too much about it, but since this is the first and I'm trying to drive adoption, I felt that this was important enough to spend the time on.
FeatureDataLoad is not an entity, so PagedResourceAssembler cannot create links for it. (And cannot find out the name for it).
But if FeatureDataLoad is a projection for Feature, then - in theory - you can use PagedResourcesAssembler<Feature> assembler in your method. (Instead of PagedResourcesAssembler<FeatureDataLoad>)

Multiple payloads in MVC core rest api

I am developing a rest api on .Net core 2.2 following MVC pattern.
I have a controller with a post method like this...
// POST: api/Todo
[HttpPost]
public async Task<ActionResult<TodoItem>> PostTodoItem(string param, [FromBody] TodoItem item)
{
// some work...
return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item);
}
And it works fine.
The customer asked to have an api on the same route, but the Json body could have 2 different structures, bearing the same data on different schemas.
I considered using
PostTodoItem(string param, [FromBody] Object item)
{
// TryCast item to one of the possible POCO classes then work with the correct one.
}
Do you know a better way, maybe with some advanced routing and filtering option?
This is not really possible nor desirable. Pretty much the core tenant of REST is a URI uniquely represents a particular resource. If you've got a URI like POST /todo, then the post body should be a "todo" and it should create a new "todo" based on that. Here, that is a TodoItem, so that is all that should ever be posted.
REST aside, this just won't work. When your action is activated, the modelbinder attempts to bind the post body to the param(s) that the action accepts. It basically just news up whatever type the param is, and then attempts to find something from the post body to bind to the various properties on that type. This is an intentionally simplistic description of what's happening; the important part is that the type of the param informs how the post body is bound. If you bind to an object (which has no members) or even a base type, then the only members of the post body that will be bound are those that are present on that type, not derived types thereof. Anything that cannot be bound is discarded.
Long and short, you need a unique route for each type of thing you're working with. Under the hood, you can share or otherwise reuse code by factoring out common functionality into private methods, employing inheritance, etc., but you need a distinct action and route to handle each case.

Entity Framework & WPF Application Design Guidance

Entity Framework Layer Guidance
I'm in the design stage of a WPF business application. The first stage of this application will be a WPF/Desktop application. Later iterations may include a browser based mini version.
I envision creating a dll or 2 that contain the domain model & dbcontext that all applications(Desktop or Browser) will use.
My intention is to ride or die with EF. I'm not worried about using DI/Repository patterns etc for flexibility. The benefits of using them don't outweigh the added complexity in my opinion for this project. My plan is to use a model, and a derived dbcontext.
Having said that, I'm looking for input on where to put certain types of method code.
An example will hopefully make my question more clear:
Let's say I have the following two entities..
Entity: Employee
Entity: PermissionToken
Inside of these two entities I have a ManyToMany relationship resulting in me creating another entity for the relationship:
EmployeesPermissionTokens
For clarity, the PermissionToken Entity's Primary Key is an Enum representing the permission..
In the application, lets say the current user is Administering Employees and wants to grant a permission to an Employee.
In the app, I could certainly code this as:
var e = dbcontext.Employees.Find(1);
var pt = new PermissionToken
{
PermissionID=PermissionTypeEnum.DELETEUSER";
...
}
e.PermissionTokens.Add(pt)
But it seems to me that it would be more convenient to wrap that code in a method so that one line of code could perform those actions from whatever application chooses to do so. Where would a method like that live in all of this?
I've thought about adding a static method to the EF Entity:
In The employee class:
public static void GrantPermission(PermissionToken token)
{
e.PermissionTokens.Add(token);
}
Going further, what would be really convenient for the app would be the ability to write a line like this:
Permissions.GrantToEmployee(EmployeeID employeeId, PermissionTypeEnum
permissionId);
Of course that means that the method would have to be able to access the DbContext to grab the Employee Object and the PermissionObject by ID to do its work. I really want to avoid my entities knowing about/calling DbContext because I feel long term the entities get stuffed full of dbcontext code which in my opinion shouldn't even be in the Model classes.
So Where would a method like this go?
My gut tells me to put these sorts of code in my derived DbContext since in order to do these sorts of things, the method is going to need access to a DbContext anyway.
Does this make sense, or am I missing something? I hate to write oodles of code and then figure out 3 months later that I went down the wrong road to start with. Where should these types of methods live? I know there is probably a purist answer to this, but I'm looking for a clean, real world solution.
First of all you are making a good decision to not abstract EF behind a repository.
With the EF Context you have a class supporting the Unit Of Work pattern which is handling your data access needs.No need to wrap it up in repository.
However this does not mean you should call the Context directly from your controller or viewmodel.
You could indeed just extend the DbContext however I suggest to use services to mediate between your controllers/view models and your dbcontext.
If e.g. in your controller you are handling a user request (e.g. the user has clicked a button) then your controller should call a service to archive what ever "Use Case" is behind the button.
In your case this could be a PermissionService, the PermissionService would be the storage for all operations concerning permission.
public class PermissionService
{
PermissionService(DbContext context)
{
}
public bool AddPermission(Employee e, PermissionType type) { }
public bool RemovePermission(Employee e, PermissionType type) {}
}
Your service ofcourse needs access to the DbContext.
It makes sense to use DI here and register the DbContext with a DI Container.
Thus the context will be injected into all your services. This is pretty straight forward and I do not see any extra complexity here.
However, if you don't want to do this you can simply new up up the Db Context inside your services. Of course this is harder / impossible to mock for testing.

What and when can "Target" be instead of an Entity and should I check its logical name when working on a single entity type?

I'm a newbie in developing in CRM, so I want to get some things clear. And you first you need to know the reason why you have to do something in order to fully understand it. So lets get to the question.
I know you have to do this when making a plugin:
var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext));
if (context.InputParameters.Contains("Target") && context.InputParameters.["Target"] is Entity)
{
var entity = (Entity)context.InputParameters["Target"];
if(entity.LogicalName == "myEntity")
{
//Do something with your entity
}
}
Now, in the PluginRegistration Tool, you can set up that your plugin will be fired on the defined Message and which entities (and specific attributes from them) will be affected by it, besides other stuff.
I can see the validations are very useful when manipulating several entities with a single plugin.
Now, let's suppose you only are updating a single entity with your plugin. Why should I check if the entity that's on "Target" is the entity I want to work on, if I already know because I set it up for that entity in particular? What can an Entity be otherwise in that scenario?
Also, in what cases "Target" is NOT an Entity (in the current context)?
Thanks in advance, and sorry if this is a silly question.
See this answer: Is Target always an Entity or can it be EntityReference?
Per the SDK (https://msdn.microsoft.com/en-us/library/gg309673.aspx):
Note that not all requests contain a Target property that is of type
Entity, so you have to look at each request or response. For example,
DeleteRequest has a Target property, but its type is
EntityReference.
The bottom line is that you need to look at the request (all plugin's fire on an OrganizationRequest) of which there are many derived types (https://msdn.microsoft.com/en-us/library/microsoft.xrm.sdk.organizationrequest.aspx) to determine the type for the Target property.
As Nicknow said, the Input Parameters will change depending on the Message being executed.
You can get that information from the MSDN (every request will list the Input Parameters under the Properties section, for instance the CreateRequest) or using the ParameterBrowser.
There's also a really nice alternative to deal with this in a type-safe approach (intellisense included) described in the following blog article: mktange's blog.

Combining URL and POST variables in ServiceStack

I am trying to convert an existing wcf rest api to ServiceStack, and having issues right out of the gate:
[Route("foo/{userId}","POST")]
public class MyInputModel : IReturnVoid
{
public string userId { get; set; }
public SomeOtherObject properties { get; set; }
}
The intention here is that I would provide the userId in the url, and an instance of SomeOtherObject in the post body. The error I get is
<Message>Could not deserialize 'application/xml' request using MyInputModel'
Error: System.Runtime.Serialization.SerializationException:
Error in line 1 position 42. Expecting element 'MyInputModel'
from namespace 'blahblahblah'.. Encountered 'Element' with name
'SomeOtherObject', namespace 'http://blahblahblah'.
The only things I can think of are to wrap my xml in a MyInputModel to make the serializer happy. This is not really an option for backwards compatibility.
I could also modify SomeOtherObject to be the top level input model, and put a UserId property in there, but this also feels suboptimal since it is an object used throughout the api, and is really not tied to a user id. It is also already published independently, so it would be painful to make changes there.
Is there any way to indicate that the root element of the posted data will be a SomeOtherObject insted of a MyInputModel? In WebApi this would be with the [FromBody] attributes and whatnot. Does servicestack have anything similar?
The purpose of a DTO is to auto-generate the wire format which is why ServiceStack requires the Request DTO to match the shape of the incoming request. Part of what makes ServiceStack so productive is that it's a code-first web service framework which encourages starting from C# and projecting out, i.e. your clients should bind to your web service outputs and not the other way round of mapping code-first models to existing schema inputs.
Having said that, the Serialization / Deserialization wiki page lists the different ways to override ServiceStack's default request binding with your own.
Access HTTP Request variables in any Service or Filter
Not everything needs to be mapped to a DTO as any HTTP Variable can still be accessed from the IHttpRequest available from any service or filter, i.e:
base.Request.QueryString
base.Request.FormData
base.Request.Headers[name]
base.Request.PathInfo
base.Request.AbsoluteUri