Should we user Request and Response model same? - c#

As a good API writing practice should we use request and response model separate or common?
Ex.
public abstract class BaseModel
{
public DateTime CreatedOn {get;set;}
public int CreatedOn {get;set;}
}
public class UserModel : BaseModel
{
public int UserId {get;set;}
public string UserName{get;set;}
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
string _name;
public string Name
{
get { return string.Format("{0}{1}{2}", FirstName, MiddleName, LastName) }
set { _name=value; }
}
}
Now if I'm creating API
CreateUser(UserModel uModel)
{
}
GetUsers()
{
// Here I'm returning all users from the system, so each user's object will contains CreatedOn and CreatedBy, which I don't require in the API response
}
So here should we need to create multiple UserModel ?

If your response format is json, one solution is using [ScriptIgnore] annotation such that :
public abstract class BaseModel
{
[ScriptIgnore]
public DateTime CreatedOn { get; set; }
[ScriptIgnore]
public int CreatedOn2 { get; set; }
}
So that you can use your common class with not serializing unwanted fields for your api.

Related

The name `Foo` was already registered by another type, GraphQL

I am using GraphQL as a part of my CQRS application.
I have separated Command and Query domain model into two different projects (Query and Command).
each of there projects has some models for instance Student model.
I use two different model in Domain.Query.Students.Student and Domain.Command.Students.Student, but both have the same entity name (Student and Address)
I simplified my entity as below:
public class Student:Entity
{
public string FirstName { get; set; }
public string LastName { get; set; }
public Address Address { get; set; }
public DateTimeOffset CreatedOn { get; set; }
public DateTimeOffset ModifiedOn { get; set; }
}
Student is being used in Query and Command projects.
in Startup.cs I have configured GraphQL like this:
services
.AddGraphQLServer()
.AddQueryType<StudentQuery>()
.AddMutationType<AddStudentMutation>();
In StudentQuery.cs
namespace GraphQL.Query.Students
{
public class StudentQuery
{
public List<Student> AllStudents([ScopedService] StudentRepository studentRepository)
{
var query = studentRepository.GetEmployees();
return query;
}
}
}
and AddStudentMutation.cs
namespace GraphQL.Command.Students
{
public class AddStudentMutation
{
public async Task<Student> AddStudentAsync(AddStudentInputType student,[Service] IMediator mediator)
{
var result =await mediator.Send(new AddStudentCommand(student.FirstName,student.LastName,student.StreetAddress,
student.City,student.State,student.ZipCode));
return result;
}
}
[GraphQLName("AddStudentInput")]
public class AddStudentInputType
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string StreetAddress { get; set; }
public string City { get; set; }
public string State { get; set; }
public string ZipCode { get; set; }
}
}
When I run the application I get the following error:
The name `Student` was already registered by another type. (HotChocolate.Types.ObjectType<Domain.Query.Students.Student>)
If I change the Student entity in Domain.Query.Students.Student to ReadStudent or something else, it will run without any issue, but I don't want to change it.
You can add the GraphQL annotation onto the Student class as [GraphQLName("StudentQuery")]

Two same table's mapping LINQ TO SQL

For some reason, i have two tables(they are called differently) in my database and both are fully the same.
Also, each of them has too many attributes.
So image i have two ORM Models,like this one:
[Table(Name = "DataHelper")]
class MySameTable1
{
[Column(IsPrimaryKey = true)]
public int Id { get; set; }
[Column]
public string Name { get; set; }
[Column]
public string Surname { get;set; }
[Column]
public string Country { get;set; }
//etc. too much properties
}
and the second one
[Table(Name = "DataSource")]
class MySameTable2
{
[Column(IsPrimaryKey = true)]
public int Id { get; set; }
[Column]
public string Name { get; set; }
[Column]
public string Surname { get;set; }
[Column]
public string Country { get;set; }
//etc. too much properties
}
So when i'm doing the job with table's:
DataContext _DataContext = new DataContext("connectionstring");
var MySameORM_Model1 = _DataContext.GetTable<MySameTable1>();
var MySameORM_Model2 = _DataContext.GetTable<MySameTable2>();
the main problem occurs,when i need to populate second table(MySameORM_Model2) via data that contains in table MySameTable1(not sometimes it will be directly insert,but sometimes not)
So to not foreach all entries from MySameTable1 , I have tried this steps:
1.Abstract class that contains all properties:
public abstract class BaseSameTable
{
[Column(IsPrimaryKey = true)]
public int Id { get; set; }
[Column]
public string Name { get; set; }
[Column]
public string Surname { get;set; }
[Column]
public string Country { get;set; }
//etc. too much properties
}
//inheritance
[Table(Name = "DataHelper")]
class MySameTable1 : BaseSameTable
{ }
//same
[Table(Name = "DataSource")]
class MySameTable2 : BaseSameTable
{ }
And it didn't work, I got strange exceptions with hierarchy submission
After this, i have changed abstract class to interface abstraction, but unfortenuly it didn't make the trick.
public interface IBaseEntity
{
int Id { get; set; }
string Name { get; set; }
string Surname { get;set; }
string Country { get;set; }
//etc. too much properties
}
[Table(Name = "DataHelper")]
class MySameTable1 : IBaseEntity
{
[Column(IsPrimaryKey = true)]
public int Id { get; set; }
[Column]
public string Name { get; set; }
[Column]
public string Surname { get;set; }
[Column]
public string Country { get;set; }
//etc. too much properties
}
[Table(Name = "DataSource")]
class MySameTable2 : IBaseEntity
{
[Column(IsPrimaryKey = true)]
public int Id { get; set; }
[Column]
public string Name { get; set; }
[Column]
public string Surname { get;set; }
[Column]
public string Country { get;set; }
//etc. too much properties
}
So what is the right approach for my case and what can I do to achieve my goal?
Maybe it needs additional mappings, but google didn't help me.
If your data is going from one table to another table, why get your host machine involve at all? Wite a stored procedure to handle it, so the data never has to leave the dataserver.

How to stop abstract class attributes to be pass in end result - WebAPI?

I have following scenario where I am getting OrderBase obstract class from ThirdParty library. And I have to inherit this abstract class into my model Order to get base attributes. Only below base attributes are required to be return as part of response.
Id
Name
OrderHistory
But actually it return all the base attributes as part of response due to inheritance. So is there any way by which we can restrict no of base attributes to be pass in the result without introduction of intermediate model(s) and mappings.
Code Sample- Third Party:
[DataContract]
[Serializable]
public abstract class OrderBase
{
public OrderBase(DatabaseObject obj)
{
this.Id = obj.Id;
this.Name = obj.Name;
this.Description = obj.Description;
this.ClosingDate = obj.ClosingDate;
this.Price = obj.Price;
}
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Description { get; set; }
[DataMember]
public decimal Price { get; set; }
[DataMember]
public string ClosingDate { get; set; }
}
public class DatabaseObject
{
public string Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public decimal Price { get; set; }
public string ClosingDate { get; set; }
public string OrderHistory { get; set; }
}
Model:
[DataContract]
[Serializable]
public class Order : OrderBase
{
public Order(DatabaseObject dbObject)
: base(dbObject)
{
this.OrderHistory = dbObject.OrderHistory;
}
[DataMember]
public string OrderHistory { get; set; }
}
API Code:
public class OrderController : ApiController
{
public Order GetOrder()
{
var dbObj = new DatabaseObject
{
Id = "O001",
Name = "Masala Packets",
ClosingDate = "01/02/2016",
Description = "Payment Successful",
OrderHistory = "",
Price = 10000
};
var orderObj = new Order(dbObj);
return orderObj;
}
}
Current JSON Result:
{
"OrderHistory": "",
"Id": "O001",
"Name": "Masala Packets",
"Description": "Payment Successful",
"Price": 10000.0,
"ClosingDate": "01/02/2016"
}
Expected JSON Result:
{
"OrderHistory": "",
"Id": "O001",
"Name": "Masala Packets"
}
You're serializing your domain models directly. That may not be a good idea. It's better to create a view model to send your serialized data and you will have complete control of what to serialize as well as better separation of concerns. Something like an OrderDTO
public class OrderDTO {
public string Id { get; set; }
public string Name { get; set; }
public string OrderHistory { get; set; }
}
In your web api method:
public class OrderController : ApiController
{
public OrderDTO GetOrder()
{
// return an OrderDTO instead;
}
}
Or you can use JsonIgnore property to exclude properties from serialization in case you want to expose your domain classes:
[DataContract]
[Serializable]
public abstract class OrderBase
{
public OrderBase(DatabaseObject obj)
{
this.Id = obj.Id;
this.Name = obj.Name;
this.Description = obj.Description;
this.ClosingDate = obj.ClosingDate;
this.Price = obj.Price;
}
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
[JsonIgnore]
public string Description { get; set; }
[DataMember]
[JsonIgnore]
public decimal Price { get; set; }
[DataMember]
[JsonIgnore]
public string ClosingDate { get; set; }
}
Use the [ScriptIgnore] attribute on the property you don't want to serialize as JSON.
If you don't want to do this in the parent class, you should shadow or overload the property in your child class and add the attribute there.
How to exclude property from Json Serialization

JSON Class with spaces in name

I have been given a JSON definition something along the lines of..
{
"the.data" : {
"first.name": "Joe",
"last.name": "Smith"
}
}
and i've made a class in c# to add my data too, such as
public class TheData
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class RootObject
{
public TheData TheData { get; set; }
}
Now the web service that i have to send this payload to, is expecting The.Data, and First.Name, as well as Last.Name
How can i 'change' the name definitions? Before transmitting?
Can i somehow override the name?
You can try this. you can use JsonPropertyAttribute to tell Json.Net what the property's corresponding json field is.
public class TheData
{
[JsonProperty("first.name")]
public string FirstName { get; set; }
[JsonProperty("last.name")]
public string LastName { get; set; }
}
public class RootObject
{
[JsonProperty("the.data")]
public TheData TheData { get; set; }
}
You can decorate the values, it will depend on which framework you're using but it'll be something like this:
[JsonProperty(PropertyName = "Person.Name")]
public string PersonName { get; set; }

Write a CSV file

I have a class that I've written in C# and decorated with FileHelpers attributes
[DelimitedRecord(","), IgnoreFirst(1)]
class UserAndValues
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<UserFavourites> Favourites {get;set;}
public UserAndValues()
{ }
}
class UserFavourites
{
public int Id {get;set;}
public string Title {get;set;}
}
I then call the CSV writer
var engine = new FileHelperEngine<UserAndValues>();
engine.WriteFile(myPath, myListOfUsers);
I get the following error:
The field: 'k__BackingField' has the type: ICollection`1
that is not a system type, so this field need a CustomConverter (
Please Check the docs for more Info).
I would like to write out a file that basically looks like
UserId, FirstName, LastName, Favourite1Id, Favourite1Title, Favourite2Id, Favourite2Title...
1, Joe, Smith, 1, Random Title, 2, More Title, ...
The favourites collection could be 10-50 records deep and changes based on the file.
I will not need to read this file, just write it.
How can I generate a CSV using the above class? (I can modify the class structure)
Well, very untested:
class UserAndValues
{
public int UserID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
[FieldConverter(typeof(MyListConverter))]
public ICollection<UserFavourites> Favourites {get;set;}
}
public class MyListConverter: ConverterBase
{
public override object StringToField(string from)
{
throw new NotImplemented("bad luck");
}
public override string FieldToString(object fieldValue)
{
var list = fieldValue as ICollection<UserFavourites>;
return string.Join(",",
list.Select(f => f.ToString())); // customize
}
}

Categories

Resources