How does one design his various architecture/business models? - c#

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).

Related

Adding run-time only collection to OData list

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.

Deriving a database model for view model in ASP.MVC

I am creating some view models for my ASP MVC web app.
I created "code first" models for database. Is it a good way to derive view models from database models?
Example database model:
public class Project
{
[Key]
public int Id { get; set; }
public int? CustomerId { get; set; }
public int TypeId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
View model:
public class ViewModelProject : Project
{
[NotMapped]
public DateTime? Start { get; set; }
[NotMapped]
public DateTime? End { get; set; }
[NotMapped]
public string Manager { get; set; }
}
Is this the right way or is it completely false?
EDIT (subquestion):
I have some very simple database models like ProjectType, which only contains i.e. two properties. Should I also fragment those models in model view or can I make it that way:
Simple database model:
public class ProjectType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int? Code { get; set; }
}
Can I use it like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public ProjectType Type { get; set; }
}
Or does it have to be fragmented like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public string Type { get; set; }
public int TypeCode { get; set; }
}
I would not recommend doing it this way. I (and many others) have tried it and it doesn't work well. You will inadvertedly run into troubles, since an MVC model has to be tailored to the view and what you get from the DB rarely fits. Sure, you can hammer it into place, but the code quickly gets messy and store-related and UI code starts to mangle together. This even shows in your example, since you have to put the NotMappedAttribute (which is related to data storage), to ViewModelProject (a class at UI level).
There are many other examples to show this problem, but an especially good one I find when you want to serialize a model object to JSON and send it to a JavaScript client. The JSON serializer takes the values of all public properties and adds them to the JSON. If you want to exclude a property, you have to mark it with a ScriptIgnoreAttribute, which you would also have to apply to the base class, which breaks separation between UI and store-related code.
The better way to go is to keep the staorage model and the MVC model separated and to map the data from one to the other (there are already pre-existing frameworks that help you with that, such as Automapper). This comes with additional advantages, for example better testability, since you are now not dependent on a specific data store to create model instances.

Good practices for creating a Web API 2 & EF based system

I am creating a Web API 2 application based on Entity Framework. My questions are about good practices involved in creating Web API 2 & EF based system.
Suppose that I have class Payment containing class Address.
public class Payment()
{
public string Id { get; set; }
public string Name { get; set; }
public decimal Amount { get; set; }
public Address PaymentAddress{ get; set; }
}
public class Address ()
{
public string StreetName{ get; set; }
public string City{ get; set; }
}
Question 1:
Does my Web API should allow for changing Address from endpoint PUT /payments (I mean changing Address's properties not the whole object) called Solution 1
Question 2:
or maybe PUT /payments should update only simple properties of Payment without Address properties? In this scenario Address properties could by changed by endpoint PUT /payments/{paymentId}/address (called Solution 2)?
Question 3:
Currently I have implemented Solution 1 but I have problem to set context properly for Payment updates with updated Address's properties. I have to manually change EF State value of Address. If solution 2 would solve my problem?
Question 4
By default EF one-to-many relation is defined automatically like in my example. But I can use ForeignKey attribute mark column as foreign key. Why this solution is better? Does is help in anything?
public class Payment()
{
public string Id { get; set; }
public string Name { get; set; }
public decimal Amount { get; set; }
public int AddressId{ get; set; }
[ForeignKey("AddressId")]
public Address PaymentAddress{ get; set; }
}

How can I control Json.NET serilaization to use a custom version of JsonIgnore?

Having just merged two branches of a class library, I find one has added several JsonIgnore attributes to model properties. These will break the web client of that library, but are required in the mobile client of that library. I would like to create a new 'Json ignore' attribute that will only ignore marked properties if the calling code is not the web client. Then I would like to hook into the serialization code to look at my new attribute vs. the normal one.
Not a good idea. My suggestion is the classes(let's call them models) in the shared project are really shared (with no attributes), and in other projects where the models are outputted you define classes with attributes. Something like this:
//in MyProject.Core which is shared
class User
{
public int Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
//in MyProject.WcfApi which has wcf services for other teams
[DataContract]
class UserOutput
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string UserName { get; set; }
//no password property here
}
//in MyProject.WebApi which has some web apis for js
class UserOutput
{
[MyJsonRelatedAttribute]
public int Id { get; set; }
}

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.

Categories