Adding run-time only collection to OData list - c#

I'm new to OData and I have a working solution for complex requests of my domain data, which is great. The bit I'm looking for help with is using this data and sending the entire list to another API to append additional data to the OData response for a particular object type.
I don't mind losing the ability to further query the appended collection, this can be done later in my front end. I'm looking for some help in identifying the right architecture for my solution.
I've seen a few possible answers that would be to create a custom serializer or use AutoMapper to populate the DTO but this would send the requests to the other API one at a time. I'm looking to send the entire list as the performance is improved rather than one at a time as there can be 20,000+ items in the response.
Here's my current schema.
Domain
public class InventoryItem
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string DeviceName { get; set; }
}
DTO
public class InventoryItem
{
public virtual Guid Id { get; set; }
public virtual string Name { get; set; }
public virtual string DeviceName { get; set; }
public IList<ReadingDto> Readings { get; set; } = new List<ReadingDto>();
}
public class ReadingDto
{
public double? Value { get; set; }
}
As the ReadingDto is obtained from another API, this shouldn't be present in my domain model. It would never be populated.
The ideal solution would be to utilise a service within my project which would send the list over to the other API whilst maintaining the flexibility of using OData. Whether this is in a custom serializer, middleware or filters, I'm just not sure what would be best.

Related

Store ObjectId instead of full object

How can I Store ChatRoom with only the SiteId instance of full object ?
thanks
public class ChatRoom
{
public ObjectId Id { get; set; }
public DateTime StartDate { get; set; }
public **Site** **Site** { get; set; }
}
That's pretty straightforward if you're willing to change the model:
public class ChatRoom
{
public ObjectId Id { get; set; }
public DateTime StartDate { get; set; }
public ObjectId SiteId { get; set; }
}
However, that means that you need to ensure referential integrity yourself. For instance, if the Site you want to refer to hasn't been stored yet, you will first have to store the Site in the database, then store the ChatRoom with the SiteId set to the Id of the referenced Site - otherwise, there's no Id to refer to.
More importantly, that means you're no longer working with an object graph, or domain model in your code. This has impact on your entire code architecture.
For example, you can't build expressions like MyUser.ChatRoom.Site.Owner.Address.Street. That has disadvantages, because you effectively can't implement a domain model at all, but it also comes with advantages because it's unclear when the freight trains actually would talk to the database.
However, these 'freight trains' are often dangerous, because it's unclear when the respective elements are loaded from the database.

Exposing EF6 model subsets via WebAPI

For example, I have a EF6 model like this:
class User
{
public int Id { get; set; }
public string Email { get; set; }
public string Name { get; set; }
public virtual ICollection<ProfileProperty> Properties { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
class Book
{
public int Id { get; set }
public int Name { get; set }
public DateTime CreationDate { get; set }
public long Size { get; set }
public string ContentPath { get; set }
}
And now I want to create a WebAPI that allows to:
Create a new user
Update user's name
Modify the list of user's books
However, here are a few tricks to it which don't let me use tutorials right off:
Some fields are either irrelevant or confidential and must not be exposed via WebAPI, for example: User.Id, User.Properties, and nested User.Books[x].ContentPath.
Only a small subset of fields is editable (in the example, User.Name).
Only a small subset of operations (CRUD) is available, therefore it's not a REST service.
The first thing that comes to mind is create extra classes for each exposed model. However, maintaining them and writing code that converts data from database models to those WebAPI-friendly classes and back is too bothersome. Is there a more simple and automated way?
The ideal approach would be one which requires writing as little redundant code as possible. Maybe there is a set of attributes to mark fields with?
You're right in thinking you should create more classes. For each exposed action (change name, create user, etc...) you should create a ViewModel that exposes only the fields you need.
public class ChangeUserNameViewModel
{
public int UserId { get; set; }
public string NewName { get; set; }
}
It's easy to convert your view model to your domain model and back again using something like AutoMapper.

Sending and receiving different models over json with webapi and entity framework

I'm very new to entity framework and web api so please excuse me if what I'm trying to do doesn't make much sense! Is it possible to send one model on a post and receive a different model on a get? My example.
I have a very simple companies model:
public class Company
{
[Required]
public string companyName { get; set; }
public virtual List<Branch> branches { get; set; }
}
public class Branch
{
public int companyID { get; set; }
public string branchName { get; set; }
public string address { get; set; }
public string postcode { get; set;}
public string phoneNumber { get; set; }
public virtual Company company { get; set; }
}
When I post to myapp/api/companies I want to be able to include a list of branches to add alongside the company, this is currently working perfectly however, my front end designer has requested that the companies come back without the branches attached. I have tried [jsonIgnore] against the branches and this works for the GET but it also stops the branches from writing on a post. Is there some way to apply the jsonIgnore on the controller perhaps?
Should I try and convince my front-end guy to just ignore the branch data or is there some way I could omit it in the response?
Thanks
Chris
The way I finally managed to do this was to use eager loading instead of lazy loading. To achieve that remove virtual from each of the relations. This stops EF from getting the relations automatically then in any code that returns the object use .Include() to include any relations you want back in that return.

Should I be using a DTO when passing data from my server to clients?

I feel like I've gone and over-complicated my design by using DTOs, but I'm looking for a second opinion.
My structure is:
User <- One-to-Many -> Playlist <- One-to-Many -> PlaylistItem <- One-to-One -> Video
As such, a PlaylistItem domain object looks like:
public class PlaylistItem
{
public virtual Guid Id { get; set; }
public virtual Playlist Playlist { get; set; }
public virtual int Sequence { get; set; }
public virtual string Title { get; set; }
public virtual Video Video { get; set; }
// Not written to the database. Used for client to tell who is who after a save.
public virtual string Cid { get; set; }
}
and a PlaylistItem DTO looks like:
[DataContract]
public class PlaylistItemDto
{
[DataMember(Name = "playlistId")]
public Guid PlaylistId { get; set; }
[DataMember(Name = "id")]
public Guid Id { get; set; }
[DataMember(Name = "sequence")]
public int Sequence { get; set; }
[DataMember(Name = "title")]
public string Title { get; set; }
[DataMember(Name = "video")]
public VideoDto Video { get; set; }
[DataMember(Name = "cid")]
public string Cid { get; set; }
}
The only change is that I have broken the circular-referential structure by replacing the Playlist reference with a PlaylistId.
The default JSON serializer in C# .NET MVC was unable to handle circular structures. I've since updated to using the JSON.NET serializer which is capable of handling circular structures. I'm now re-evaluating why I even need my DTO.
Are there any benefits of a DTO that I should be aware of / considering here? Is it bad practice to JSONize a circular reference and send it across the wire?
JSON, being a hierarchical format, is going to work best when representing data in a hierarchical fashion. JSON isn't a node graph, so trying to serialize graph-like data is going to prove difficult, I think. I think your solution of converting an object (Playlist) to a form of "reference" (PlaylistId) is the correct one. The code receiving and processing this JSON can reconstruct the circular reference, if necessary, since you have your "foreign key" (PlaylistId) in place.
Most of the time I would rather have an extra DTO than none at all. DTOs insulate you from change--in this case, insulate your API from change. PlaylistId is unlikely to change its schema in the future, but the actual Playlist might.
Are there any benefits of a DTO that I should be aware of / considering here?
Design. THis is a public API and you want to make sure it is sable, while the internal objects are / can change without a lot of review. Changes in data types are a lot more problematic if this is an "out of the server" style interface and you do not want to force API updates (client updates) every time you do a minor change.
As such, having API level definition objects (DTO) separately defined helps with this part of not changing a public interface.

How does one design his various architecture/business models?

I'm currently learning about various application design approaches and there's one thing I can't really get my head around.
Let's say I have a physical device in my network, an IP surveillance camera. I need a model that represents 'IP surveillance cameras' to work with them in my application, which might look like this:
public class IPCamera {
public string Token { get; set; }
public IPAddress IPAddress { get; set; }
public string RtspUri { get; set; }
}
Now, if I want to store the IPCamera into a database (e.g. with Entity Framework), I need maybe other/additional properties and thus, another model with:
public int Id { get; set; }
Oh.. I want to access my application with via a WCF service. I can't use the object "IPAddress" here because it's not very serialization friendly, hence I need another model with a custom IP class that stores the IP address as string.
And last, an Android clients wants to access my data. I design a RESTful API using WebApi2. The client isn't interested in the cameras RTSPUri, but wants to know about the current state (is online, is offline).
I'm wondering: How to name all these models that they don't come in conflict? Should I design a model per each purpose/layer/service? And how to link/map them? With the adapter pattern?
I would include everything in your entity and then create view models that only expose the properties that matter to the domain you're accessing your entities through.
Your entity:
public class IpCamera
{
public int Id { get; set; }
public string Token { get; set; }
public IPAddress IPAddress { get; set; }
public string RtspUri { get; set; }
public bool IsOnline { get; set; }
}
In your WCF service:
public class IpCameraViewModel
{
public int Id { get; set; }
public string IpAddress { get; set; }
public string Token { get; set; }
public string RtspUri { get; set; }
}
In your api project:
public class IpCameraViewModel
{
public int Id { get; set; }
public string IpAddress { get; set; }
public string Token { get; set; }
public bool IsOnline { get; set; }
}
And you can just set the IpAddress as a string to send to a receiving client. You can shed away any properties you don't want to expose. Or you can add properties that don't belong to the IpCamera entity and just add them to your view model from another entity.
As #Smith.h.Neil suggested, you should create one base normalized model (entity if you will) to store and several view models (projections).
You can easily map to/from view models using tools like AutoMapper.
As for the naming, I wouldn't use technical suffixes (like *ViewModel) in API layer. Think hard and figure out correct domain (business oriented) name of each projection. Like IpCameraStatus or perhaps just IpCamera (but in another namespace).

Categories