Query with OData without exposing ORM models? - c#

In my web api 2 project, if I want to use OData library (which looks awesome and very tempting) for queries over some properties, that would force the client side to know the exact properties of my database models. Is this a good practice? Is there a way to avoid this decouple?
For the following models:
public class LetterEntity
{
public int Id {get; set;}
public string Title {get; set;}
public string Content {get; set;}
public string Source {get; set;}
public DateTime SendingTime {get; set;}
public string AnotherWierdString {get; set;
...
}
public class LetterDTO
{
public int Id {get; set;}
public string Title {get; set;}
public string LetterContent {get; set;}
public string Source {get; set;}
public DateTime SendingTime {get; set;}
}
public class LetterInsideFolderDTO
{
public string Title {get; set;}
public string Source {get; set;}
}
public class LettersController : ApiController
{
// In this approach method, I hate the fact that a LetterEntity must be used for the query.
[HttpGet]
[Route("api/letters")]
[EnableQuery]
public IQueryable<LetterInsideFolderDTO> Get(ODataQueryOptions<LetterEntity> query)
{
IQueryable<Letter> letters = db.Letters;
var afterQuery = query.ApplyTo(letters)
IQueryable<LetterInsideFolderDTO> dtos = afterQuery.ProjectTo<LetterInsideFolderDTO>(afterQuery)
return dtos;
}
// Is there a way to do something like the following?:
[HttpGet]
[Route("api/letters")]
[EnableQuery]
public IQueryable<LetterInsideFolderDTO> Get(ODataQueryOptions<LetterDTO> query)
{
IQueryable<Letter> letters = db.Letters;
// Convert the query to work on the entities somehow? Should I use a mapping between LetterDTO to LetterEntity?
// I only have a map from LetterEntity to LetterDTO
var afterQuery = query.ApplyTo(letters)
IQueryable<LetterInsideFolderDTO> dtos = afterQuery.ProjectTo<LetterInsideFolderDTO>(afterQuery)
return dtos;
}
}
Because of the fact that at the moment I take Entity model directly in the clients query, there is a strong coupling between clients and server.
For example if i want to query and get all the letters that has "abc" inside the Content field, I need to route to the following:
api/letters/?$filter=contains(Content,'abc')
If tomorrow I decide to change that property from "Content" to "LetterContent" all clients code will be broken.
How can I surpass it?
Thanks!
EDIT:
Please give me a concrete example,
I don't understand yet what HATEOAS are (if that helps me solve this issue),
How can documentation service help me? It'll still force clients to change their code if I decide to change my EDM models?

I do believe that exposing your entities directly is a bad practice in most cases. I'd recommend DTOs in almost every case. It allows you to evolve your database and business logic without breaking the API. There are some great use cases for OData for example open data initiatives where the government publishes data as it is.
I had to built an app that was essentially grids over data with all the filtering and sorting options. I wanted to use OData but I did not find a way to do queries over entities but project to DTOs so I built my own library to convert jqgrid filters to IQueryable queries - https://github.com/KodarLtd/WebApiJQGridFilters Note that I do not recommend using this code as it is not full featured library and is not documented at all. I just provide it as evidence how firmly I believe in the DTO approach.
I would like to be proven wrong so I can use OData but return DTOs for my next project.

if I want to use OData library (which looks awesome and very tempting) for queries over some properties, that would force the client side to know the exact properties of my database models. Is this a good practice?
It depends on what do you mean by "would force the client side to know the exact properties". There are two ways:
Use auto-generated proxies made by datasvcutil. Indeed, that would force the client side to know the exact properties since they are hard-coded in client-side. When server side is changed client would be broken - client/server are tightly coupled. In general it's bad, but usually if you need smth to get done quickly - datasvcutil is your tool.
Learn your client to read service document, so that he could dynamically decide what resources he may query. You have everything for it - service document, metadata.
Remember that OData is built on REST architecture which has a set of advantages that are achieved via set of constraints. Several of constraints are Addressability and HATEOAS.
Addressability means that each resource must have its address.
HATEOAS means that in any given moment, client, based on hypermedia in representation of current resource, must have all the information he needs to decide where to transit next.
In order to know where to transit client must
Know how to find resources(URL's) in the stream of data where he may transit. Like you get data with text and URL's - client must know how to find URL's. URL may have different meanings - like several URL's for CRUD operations.
Get that data with resources. In general client must know how to start querying service
First point is resolved via profiles. Profile - allows clients to learn about additional semantic associated with the resource representation (https://www.rfc-editor.org/rfc/rfc6906). Consider it OData documentation. In case of OData your client must know that data in OData is represented via Atom or Json formats. Client must know principles of constructing queries to OData service, of getting specific record and so forth.
If client calls OData root address - smth like ...OData.svc, he would get list of all resources that he can query(service document). That is how second point is resolved.
You may come further and get metadata via $metadata suffix. That would give you all properties of resources.

Related

Viewmodels vs Domain models vs entities [duplicate]

When I use Web (MVC), I always to create a separate classes layer. These classes often the same as DTO classes, but with attributes like [Display(Name = "Street")] and validation. But for web api Display attributes are not necessary, validation can be used by FluentValidation. Should Api controller returns ViewModels classes or DTO classes will be fine too?
the answer, as always is .... it depends.
If your API is serving multiple clients , apps etc, then returning DTOs is a better options.
ViewModels are specific to the MVC client and should already be prepared for display, meaning the data should already be formatted in a specific way, some fields maybe combined, they should satisfy whatever requirements the display pages have. They are called ViewNodels for a reason. The point is that they are rarely exactly the same as the data the API returns, which should be a bit more generic and follow a certain pattern to make sense to its users.
If your ViewModels are exactly the same and you only have one client then it's up to you if you want to create a set of duplicated classed just to avoid having the attributes.
Mapping from DTO to ViewModel and viceversa is not exactly complicated, but the process does introduce one more complication, one more layer.
Don't forget one thing though. API DTOs are supposed to return the data they have on any entity regardless of the requirements of any UI. Requirements can change anyway, new fields added or discarded. You're more than likely to leave the API alone when that happens and simply change your ViewModels.
Your ViewModels are specific to a UI page and should contain only the data required by that page. This means that you can end up with multiple ViewModels for the same data, it's just that the display requirements are different for each.
My vote goes towards keeping the ViewModels and DTOs separate, even if, at this point in time they are exactly the same. Thins always change and this is one of those things you can actually be ready for.
Actually it depends on application's architecture how we want to return response. In this case yes we can return DTO classes but i think that would not be the good approach because we should create a separate Resource classes that will map with DTO and then return. Just see the below example:
public class CustomerDTO
{
public int ID { get; set; }
public string Name { get; set; }
public int DepartmentId { get; set; }
}
public class CustomerResource
{
[JsonObject]
public string Name { get; set; }
[JsonObject]
public string Department { get; set; }
}
Suppose we have CustomerDTO class and we want to return response in the following json format
{
"name":"Abc xyz",
"department":"Testing"
}
So in this case we should we have separate class that will return as a response to the end user as i created CustomerResource. In this scenario we will create a mapper that will map DTO with resource object.
And also with this implementation we can test resources independently

set a value to the attribute at run time

I have a namespace that contains some classes, one of the classes I'm working on contains properties, where each proprty has an attribute associated with it, as the follwing
namespace Local.Business
{
[DynamoDBTable("myTableName")]
public class Business
{
[DynamoDBHashKey("PK")]
public string MunId {get; set;}
[DynamoDBRangeKey("SK")]
public string Id {get; set;}
[DynamoDBProperty("Dba")]
public string Dba {get; set;}
}
}
the string "myTableName" need to be determined at runtime(by calling a function or reading it from other class's property)
How can I achieve that, please?
What you are trying to do is inherently flawed. You kinda can ish change attributes sort of, sometimes, but there's a good chance that whatever is consuming the attributes won't see the change, which makes it entirely pointless.
Basically: you need to find another way of reconfiguring DynamoDB at runtime. This isn't it.
For the "kinda can ish":
you can materialize attributes, and if they're mutable, change the copies you have; but when other code materializes the attributes, they'll get different unrelated versions, which will not have any changes you have made
there is an API that supports this concept (System.ComponentModel), but: most attribute consumers do not use that API - it is mostly just UI binding tools (think PropertyGrid, DataGridView, etc) that would take any notice of it - because they are expecting to work with things like DataTable that require a different approach to metadata and reflection
Set the table name value to empty string in the class file:
[DynamoDBTable("")]
During runtime, use the overloaded functions on DynamoDBMapper to pass DynamoDBMapperConfig configured with TableNameOverride
Actually I deleted the table property and I gave the table name in the query
dynamoDBOperationConfig = new DynamoDBOperationConfig();
dynamoDBOperationConfig.OverrideTableName = "tableName";
string munId = "1";
var search = dynamoDBcontext.QueryAsync<Business>(munId, dynamoDBOperationConfig);
and It works fine, thank you all guys for helping

DDD: guidance on updating multiple properties of entities

So, i decided to learn DDD as it seems to solve some architectural problems i have been facing. While there are lots of videos and sample blogs, i have not encountered one that guides me to solve the following scenario:
Suppose i have the entity
public class EventOrganizer : IEntity
{
public Guid Id { get; }
public string Name { get; }
public PhoneNumber PrimaryPhone { get; }
public PhoneNumber AlternatePhone { get; private set; }
public Email Email { get; private set; }
public EventOrganizer(string name, PhoneNumber primaryPhoneNr)
{
#region validations
if (primaryPhoneNr == null) throw new ArgumentNullException(nameof(primaryPhoneNr));
//validates minimum length, nullity and special characters
Validator.AsPersonName(name);
#endregion
Id = new Guid();
Name = name;
PrimaryPhone = primaryPhoneNr;
}
}
My problem is: suppose this will be converted and fed to a MVC view and the user wants to update the AlternatePhone, the Email and a lot of other properties that make sense to exist within this entity for the given bounded context (not shown for brevity)
I understand that the correct guidance is to have a method for each operation, but (AND I KNOW ITS KINDA OF ANTI-PATTERN) i cant help but wonder if this wont end up triggering multiple update calls on the database.
How is this handled ? somewhere down the line, will there be something that maps my EventOrganizer to something - say DbEventOrganizer and gathers all changes made to the domain entity and apply those in a single go?
DDD is better suited for task-based UIs. What you describe is very CRUD-oriented. In your case, individual properties are treated as independent data fields where one or many of these can be updated by a single generic business operation (update).
You will have to perform a deeper analysis of your domain than this if you want to be successfull with DDD.
Why would someone update all those fields together? What implicit business operation is the user trying to achieve by doing that? Is there a more concrete business process that is expressed by changing PrimaryPhone, AlternatePhone and Email together?
Perhaps that is changing the ContactInformation of an EventOrganizer? If that's the case then you could model a single ChangeContactInformation operation on EventOrganizer. Your UI would then send a ChangeContactInformation command rather than an update command.
As for the persistence of your aggregate roots (AR), this is usually handled by an ORM like NHibernate if you are using a RDBMS. However, there are other ways to persist your ARs like Event Sourcing, NoSQL DBs and even storing JSON or any other data inter-change formats in a RDBMS.
You question is quite broad!
EventOrganizer itself should not be updating anything. You should keep your update code quite separate from the entity. A different class would take an EventOrganizer object and update the DB. This is called 'persistence ignorance' and makes the code a lot more modular and cohesive.
It would be common to create a View Model - a class whose purpose is to provide the View with the exact data it needs in the exact form it needs. You would need to create the View Model from your EventOrganizer, after which the View can update it - programmatically or with binding. When you're ready to save the changes, you'll need to update your EventOrganizer from the View Model and pass it onto the updater. This seems like a layer you don't need when the project is small and simple, but it is becomes invaluable as the complexity builds.

ASP.NET web api how to exclude property from DTO object based on put/get/post/delete

I'm working on a ASP.NET web api (first time!). For every database object I have created a DTO object to flatten the objects. I use automapper to map these objects. I would like to only use one DTO object for all request types (get/put/post/delete).
Simplified example:
public class ProductDB
{
public int ProductId { get; set; }
public string Name { get; set; }
}
public class ProductDTO
{
[JsonIgnore] -- only in case of a put/post/delete request
[XmlIgnore] -- only in case of a put/post/delete request
public int ProductId { get; set; }
public string Name { get; set; }
}
If I perform a HttpGet to get a list of products, I want to include the ProductId in the response. The response type will be IEnumerable ProductDTO including ProductIds.
If I perform a HttpPut, the request will be: https://base-url/products/id with the ProductDTO as body. However, in this case I do not want the ProductId included in the ProductDTO.
I know how to exclude a property, by decorating them with both [JsonIgnore] and [XmlIgnore] attributes. However, this will always exclude them. I would like to exclude them conditionally, based on the request being HttpGet/HttpPost/HttpPut/HttpDelete.
Is this possible? Or is there another way to exclude properties from DTO's based on request type?
If I perform a HttpPut, the request will be: https://base-url/products/id with the ProductDTO as body. However, in this case I do not want the ProductId included in the ProductDTO.
Technically it doesn't need to be, since we're just talking about requests and not responses. Depending on what the client sends. If the client sends this JSON:
{
"Name" : "Some Value"
}
Then as far as the model binder is concerned, that's valid. It would create an instance of ProductDTO with that Name property set. In the server-side code you can then set the ProductId property based on the id in the route, perform the mapping, and you have your domain object.
The client doesn't need to know that they can set a ProductId property in the JSON. (And if they set one anyway, it's just going to be silently overwritten by the route value in your code and basically ignored. Of course, if they had set one when there was no such property on the DTO then it would also have simply been ignored.)
For outgoing DTOs, you want to fine-tune what the serializer includes and what it doesn't. But for incoming DTOs you have a lot more leeway because you're not actually advertising the shape of the DTO to the consuming system in any way.
The only time I've ever seen this be a problem is when using a tool to generate API documentation. Something like Swashbuckle, for example, will include that property in the API docs. Which isn't ideal. In cases like that, I find the shortest path is to create separate DTOs for the separate actions. This isn't uncommon, some MVC frameworks are even designed specifically to match one model to one request.

How do I stop a setter being exposed over web services?

I want to have an class like this,
public class Apple
{
public string Size { get; set;}
public string Colour { get; set;}
public string Shape { get; set;}
public int appleId { get; set;}
}
I want to expose that over web services using some web methods like this,
public void AddApple(Apple apple)
{
}
public Apple GetApple(int appleId)
{
}
So when I add a service reference in visual studio to that webservice I get client proxy objects generated for me allowing me to create an Apple on the client side and send that through to the webservice.
Is there a way for me to make one of those properties read only on the client side? I need the setters there so that I can set the values on the server side, but I want to control which data they can update on the client side.
Any ideas?
What I could do is pass in some of the data in the constructor, and only expose getters on the ones I want to be read only, but I want to use an object mapper on the server side. That means ideally I would want to leave the setters there.
In general, you cannot assume control over proxies generated at client side. So correct way would be to ignore values sent by client (or raise exception if he changes those values). The service documentation has to be explicitly mention such things.
Edit:
Yet another work-around would be to divide your data class into two classes - one non-editable by client (say Apple1) and another editable - say Apple2. So now service update method can only accept Apple2 so that client can know looking at generated proxy code what he can change. On server side, you can have Apple1 inherited from Apple2 to have complete data but I believe that proxy generated at client will/can anyway have two different unrelated classes. Perhaps better way in such case would be to have composite full AppleFull containing Apple1 and Apple2.
Please refer to the following question and its answers, I just skimmed through your question but I believe that it is a simillar problem as I faced -
WCF serialization and Value object pattern in Domain Driven Design
Another way to achieve that would be to share the assembly containing the Apple class (but no server side component) between server and client. Make the setters internal and mark the server side assemblies as friends using the InternalsVisibleTo attribute.
This will allow the server to use the setters but not the client.

Categories

Resources