i'm sorry i'm newbie to enterprise application as well as the design pattern. might be this question occcur lack of knowledge about design pattern. i found that its better to use DTO to transfer data.
my business entity class as below:
public class Patient
{
public string ID { get; set; }
public string FullName { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
}
so in my application user only give ID and HospitalID. so it calls for another web service and get person information
public class PersonDTO
{
public string NIC { get; set; }
public string FullName { get; set; }
public string FirstName { get; set; }
public string BirthPlace { get; set; }
public string BirthCertificateID { get; set; }
}
so based on these information im going to Patient object. (Using DTO pattern)
so i thought of write new class to convert this as follows.
public class PatientDO
{
public static Patient ConvertToEntity(
PatientRegistrationDTO pregDTO,
PersonDTO person
)
{
Patient p = new Patient();
p.NIC = pregDTO.NIC;
p.FullName = person.FullName;
p.FirstName = person.FirstName;
return p;
}
}
but lately i read few articles and they used Serializer Helper class as well as the XmlSerializer i can't understand why they used somthing like that.
for the DTO pattern is that need to use XmlSerializer and why it is used?
You should really take a look at AutoMapper.
http://automapper.org
This is a piece of software that you can include in your solution that will automatically map values from one class to another.
It'll map properties with the same name automatically, and is also pretty smart when it comes to child objects. However, it also offers complete mapping control when you need it.
EDIT
Couple of examples to show how AutoMapper works. Please note I'd never code like this in real life. Brevity!
Example classes.
// Common scenario. Entity classes that have a connection to the DB.
namespace Entities
{
public class Manager
{
public virtual int Id { get; set; }
public virtual User User { get; set; }
public virtual IList<User> Serfs { get; set; }
}
public class User
{
public virtual int Id { get; set; }
public virtual string Firstname { get; set; }
public virtual string Lastname { get; set; }
}
}
// Model class - bit more flattened
namespace Models
{
public class Manager
{
public int Id { get; set; }
public string UserFirstname { get; set; }
public string UserLastname { get; set; }
public string UserMiddlename { get; set; }
}
}
Typically, you'd have a part of your project to configure all your AutoMapping. With the examples I've just given, you can configure a map between Entities.Manager and Models.Manager like so:-
// Tell AutoMapper that this conversion is possible
Mapper.CreateMap<Entities.Manager, Models.Manager>();
Then, in your code, you'd use something like this to get a new Models.Manager object from the Entity version.
// Map the class
var mgr = Map<Entities.Manager, Models.Manager>
( repoManager, new Models.Manager() );
Incidentally, AM is smart enough to resolve a lot of properties automatically if you name things consistently.
Example above, UserFirstname and UserLastname should be automatically populated because:-
Manager has a property called User
User has properties called Firstname and Lastname
However, the UserMiddlename property in Models.Manager will always be blank after a mapping op between Entities.Manager and Models.Manager, because User does not have a public property called Middlename.
There is a nice, yet simple demo in CodeProject. It is worthy going through it.
Newbies can get a basic idea of designing DTOs.
http://www.codeproject.com/Articles/8824/C-Data-Transfer-Object
Here's a summary of the content:
The Data Transfer Object "DTO", is a simple serializable object used to transfer data across multiple layers of an application. The fields contained in the DTO are usually primitive types such as strings, boolean, etc. Other DTOs may be contained or aggregated in the DTO. For example, you may have a collection of BookDTOs contained in a LibraryDTO. I have created a framework used by multiple applications that utilizes DTOs to transfer data across tiers. The framework also relies on other OO patterns such as the Factory, Facade, etc. One of the great things about the DTO compared to a DataSet is that the DTO does not have to directly match a data table or view. The DTO can aggregate fields from another DTO
This is the base class for all Data Transfer Objects.
using System;
namespace DEMO.Common
{
/// This is the base class for all DataTransferObjects.
public abstract class DTO
{
public DTO()
{
}
}
}
This is a derived class from DTO:
using System;
using System.Xml.Serialization;
using DEMO.Common;
namespace DEMO.DemoDataTransferObjects
{
public class DemoDTO : DTO
{
// Variables encapsulated by class (private).
private string demoId = "";
private string demoName = "";
private string demoProgrammer = "";
public DemoDTO()
{
}
///Public access to the DemoId field.
///String
[XmlElement(IsNullable=true)]
public string DemoId
{
get
{
return this.demoId;
}
set
{
this.demoId = value;
}
}
///Public access to the DemoId field.
///String
[XmlElement(IsNullable=true)]
public string DemoName
{
get
{
return this.demoName;
}
set
{
this.demoName = value;
}
}
///Public access to the DemoId field.
///String
[XmlElement(IsNullable=true)]
public string DemoProgrammer
{
get
{
return this.demoProgrammer;
}
set
{
this.demoProgrammer = value;
}
}
}
This is the helper class for a DTO. It has public methods to serialize and de-serialize a DTO.
using System;
using System.Xml.Serialization;
using System.IO;
namespace DEMO.Common
{
public class DTOSerializerHelper
{
public DTOSerializerHelper()
{
}
///
/// Creates xml string from given dto.
///
/// DTO
/// XML
public static string SerializeDTO(DTO dto)
{
try
{
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
StringWriter sWriter = new StringWriter();
// Serialize the dto to xml.
xmlSer.Serialize(sWriter, dto);
// Return the string of xml.
return sWriter.ToString();
}
catch(Exception ex)
{
// Propogate the exception.
throw ex;
}
}
///
/// Deserializes the xml into a specified data transfer object.
///
/// string of xml
/// type of dto
/// DTO
public static DTO DeserializeXml(string xml, DTO dto)
{
try
{
XmlSerializer xmlSer = new XmlSerializer(dto.GetType());
// Read the XML.
StringReader sReader = new StringReader(xml);
// Cast the deserialized xml to the type of dto.
DTO retDTO = (DTO)xmlSer.Deserialize(sReader);
// Return the data transfer object.
return retDTO;
}
catch(Exception ex)
{
// Propogate the exception.
throw ex;
}
}
}
Now begin Serialization / Deserialization:
using System;
using DEMO.Common;
using DEMO.DemoDataTransferObjects;
namespace DemoConsoleApplication
{
public class DemoClass
{
public DemoClass()
{
}
public void StartDemo()
{
this.ProcessDemo();
}
private void ProcessDemo()
{
DemoDTO dto = this.CreateDemoDto();
// Serialize the dto to xml.
string strXml = DTOSerializerHelper.SerializeDTO(dto);
// Write the serialized dto as xml.
Console.WriteLine("Serialized DTO");
Console.WriteLine("=======================");
Console.WriteLine("\r");
Console.WriteLine(strXml);
Console.WriteLine("\r");
// Deserialize the xml to the data transfer object.
DemoDTO desDto =
(DemoDTO) DTOSerializerHelper.DeserializeXml(strXml,
new DemoDTO());
// Write the deserialized dto values.
Console.WriteLine("Deseralized DTO");
Console.WriteLine("=======================");
Console.WriteLine("\r");
Console.WriteLine("DemoId : " + desDto.DemoId);
Console.WriteLine("Demo Name : " + desDto.DemoName);
Console.WriteLine("Demo Programmer: " + desDto.DemoProgrammer);
Console.WriteLine("\r");
}
private DemoDTO CreateDemoDto()
{
DemoDTO dto = new DemoDTO();
dto.DemoId = "1";
dto.DemoName = "Data Transfer Object Demonstration Program";
dto.DemoProgrammer = "Kenny Young";
return dto;
}
}
Finally this code is executed in the main application
static void Main(string[] args)
{
DemoClass dc = new DemoClass();
dc.StartDemo();
}
An XmlSerializer or JsonSerializer can be used for serializing (loading) XML or Json data from a source (webservice). Or explaining the name DTO: you serialize (transfer) data from a source (webservice) to a (general DTO) object. So DTOs are general purpose objects. Sometimes its clever to make a wide as possible DTO object and fill that completely so you can use from that object whatever you like and copy that to your "own" program objects.
Example: I developped a program for showing transport navigation data. I serialize the whole xml or json messsage in a DTO object. In this DTO object is more information then I will need in my program and it can be in a different form, so I will use only whats needed. DTO objects makes it more easy to extract data from sources (webservices).
I dont want to use AutoMapper because of the name "Auto". I want to know what I am doing and think where my data is going to.
Related
Is there a way to deserialize an integer into a string ? I need it for compatibility reason.
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Abc.Test
{
[JsonSerializable(typeof(OrderInfo), GenerationMode = JsonSourceGenerationMode.Metadata)]
public partial class OrderInfoContext : JsonSerializerContext
{ }
public partial class OrderInfo
{
public string UserReference { get; set; }
}
public class Program
{
static void Main(string[] args)
{
var json = #"{""UserReference"": 123}"; // <---- how having 123 deserialize as a string?
var s = JsonSerializer.Deserialize(json, OrderInfoContext.Default.OrderInfo);
}
}
}
In some cases it can make sense to separate your serialization objects (aka DTOs) from your domain objects. This give you several benefits:
Allow your domain objects to have behavior defined, without affecting serialization.
A place to handle any complicated changes to the model without losing backwards compatibility.
Allow the serialization objects to fulfill requirements like public setters, without affecting the usage in the rest of the code.
Ex:
public class OrderInfoDTO
{
public int UserReference { get; set; }
public OrderInfo ToModel() => new OrderInfo(UserReference.ToString();
}
public class OrderInfo{
public string UserReference {get;}
public OrderInfo(string userReference) => UserReference = userReference;
}
You can use a custom converter on a property. I'll look something like:
public partial class OrderInfo
{
[JsonConverter(typeof(YourCustomConverter))]
public string UserReference { get; set; }
}
I have a repository for a DocumentDb database. My documents all have a set of common properties so all documents implement the IDocumentEntity interface.
public interface IDocumentEntity {
[JsonProperty("id")]
Guid Id { get; set; }
[JsonProperty("documentClassification")]
DocumentClassification DocumentClassification { get; set; }
}
public class KnownDocument : IDocumentEntity {
[JsonProperty("id")]
Guid Id { get; set; }
[JsonProperty("documentClassification")]
DocumentClassification DocumentClassification { get; set; }
[JsonProperty("knownProperty")]
string KnownProperty { get; set; }
}
public class BaseDocumentRepository<T> where T : IDocumentEntity {
public Set(T entity) {
// ... stuff
}
}
This works fine with a KnownDocument where I know all of the properties. But, of course, what's great about a Document Db is that I don't need to know all of the properties (and in many cases I won't).
So my client submits something like this-
{unknownProperty1: 1, unknownProperty2: 2}
And I want to upsert this using my document repository.
public OtherDocumentService() {
_otherDocumentService = new OtherDocumentRepository();
}
public UpsertDocument(dynamic entity) {
entity.id = new Guid();
entity.documentClassification = DocumentClassification.Other;
_otherDocumentRepository.Set(entity);
}
But I get an InvalidCastException from dynamic to IDocumentEntity. I assume it's because of the extra properties that exist on the dynamic object but not on the IDocumentEntity interface?
What I'm trying to do is leave my document entities open to be dynamic, but rely on a few properties being there to maintain them.
Entity parameter passed to the UpsertDocument should explicitly implement IDocumentEntity in order do make the code works, it is not enough just have a Id property.
Some options:
1) Proxy may be applied:
public class ProxyDocumentEntity : IDocumentEntity
{
public dynamic Content { get; private set; }
public ProxyDocumentEntity(dynamic #content)
{
Content = #content;
}
public Guid Id
{
get { return Content.Id; }
set { Content.Id = value; }
}
}
... using
public void UpsertDocument(dynamic entity)
{
entity.Id = new Guid();
repo.Set(new ProxyDocumentEntity(entity));
}
The stored document will have nested Object property, which may be not acceptable
2)There is a lib https://github.com/ekonbenefits/impromptu-interface which creates a proxy dynamically
and does not make extra property like solution above.
Drawback will be in performance.
Technically it could be 2 methods:
public void UpsertDocument(IDocumentEntity entity){...}
public void UpsertDocument(dynamic entity){...}
so the first (fast) will work for the objects which implement IDocumentEntity and second(slow) for the rest of the objects.
But this is a speculation a bit , as I dunno the details of the whole code base of the project you have.
If you have some flexibility as to how to name those dynamic properties, you could stuff them into a Dictionary property on your object:
public Dictionary<string, dynamic> extra { get; set; }
Goal: to save ViewModel object by Entity Framework. I have UserViewModel object which has list of UnitViewModel. Then, I have a UserAdapter class which converts UserViewModel into Entity Framework User object (see Convert()below how).
Now, my question is how do I convert this list of UnitViewModel to its corresponding Entity Framework Unit list? - Do I have to get each object from DB Context by calling something like context.Units.Where(u=>myListofUnitIDs.Contains(u.UnitID))?
public class UserViewModel
{
public Guid? UserID { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Password { get; set; }
public DateTime? CreateTime { get; set; }
public List<UnitViewModel> UserUnits { get; set; }
}
public class UnitViewModel
{
public Guid UnitID { get; set; }
public string Name { get; set; }
public int? SortIndex { get; set; }
public DateTime CreateTime { get; set; }
public bool Assigned { get; set; }
}
public class UserAdapter
{
public static User Convert(UserViewModel userView)
{
User user;
if (userView.UserID.HasValue)
{
using (var provider = new CoinsDB.UsersProvider())
{
user = provider.GetUser(userView.UserID.Value);
}
}
else
{
user = new User();
}
user.FirstName = userView.FirstName;
user.LastName = user.LastName;
user.Password = StringHelper.GetSHA1(userView.Password);
user.UserName = user.UserName;
user.CreateTime = DateTime.Now;
// Problem here :)
// user.Units = userView.UserUnits;
return user;
}
}
UPDATE: The main concern here is that I have to retrieve each Unit from database to match (or map) it with ViewModel.Unit objects, right? Can I avoid it?
For your information, this operation is called as Mapping mainly. So, you want to map your view model object to the entity object.
For this, you can either use already existed 3rd party library as AutoMapper. It will map properties by reflection which have same name. Also you can add your custom logic with After method. But, this approach has some advantages and disadvantages. Being aware of these disadvantages could help you to decide whether you must use this API or not. So, I suggest you to read some articles about advantages and disadvantages of AutoMapper especially for converting entities to other models. One of such disadvantages is that it can be problem to change the name of one property in the view model in the future, and AutoMapper will not handle this anymore and you won't get any warning about this.
foreach(var item in userView.UserUnits)
{
// get the mapped instance of UnitViewModel as Unit
var userUnit = Mapper.Map<UnitViewModel, UserUnit>(item);
user.Units.Add(userUnit);
}
So, I recommend to write your custom mappers.
For example, I have created a custom library for this and it maps objects lik this:
user.Units = userView.UserUnits
.Select(userUnitViewModel => userUnitViewModel.MapTo<UserUnit>())
.ToList();
And I am implementing these mapping functions as:
public class UserUnitMapper:
IMapToNew<UnitViewModel, UserUnit>
{
public UnitViewModel Map(UserUnit source)
{
return new UnitViewModel
{
Name = source.Name,
...
};
}
}
And then in runtime, I am detecting the types of the objects which will be used during mapping, and then call the Map method. In this way, your mappers will be seperated from your action methods. But, if you want it urgently, of course you can use this:
foreach(var item in userView.UserUnits)
{
// get the mapped instance of UnitViewModel as Unit
var userUnit= new UserUnit()
{
Name = item.Name,
...
};
user.Units.Add(userUnit);
}
I have a similar structure to the one below
Base class
public class BaseClass
{
public string Name { get; set; }
public string Address { get; set; }
public int Age { get; set; }
public Guid Guid { get; set; }
public string Hometown { get; set; }
}
Derived Class
public class DerivedClass : BaseClass
{
public List<DerivedClassDataItem> Data { get; set; }
}
Data class
public class DerivedClassDataItem
{
public string Datum1 { get; set; }
public string Datum2 { get; set; }
public string Datum3 { get; set; }
public string Datum4 { get; set; }
public int Datum5 { get; set; }
public DateTime Datum6 { get; set; }
}
What is the best practice to return specific set of info from the DerivedClass?
a potential set could be:
Name, Address, Guid and then a Data list that only contains Datum1 and Datum4
I could see anonymousTypes, Tuples or another set of class(es), all to be valid approaches.
My concern about creating new set of classs for the set returned is that the class(s) structure will be similar to the structure of the three mentioned above except it will have fewer selected members, which to me, does not sound ideal. (duplicate code and structure)
Using anonymousTypes was my initial solution to tackle this, something like
List<DerivedClass> list = new List<DerivedClass>();
var mySet = list.Select(d => new
{
Name = d.Name,
Address = d.Address,
.
.
.
.
.
Data = d.Data.Select(item => new
{
Datum1 = item.Datum1,
Datum4 = item.Datum4
})
});
but again, that was a headache for us to track through httpResponse and through out API calls.
Should I go with Tuple?
Any insights as to what is the best practice for doing this?
Edit
I am using this set of data to be a response returned by a API/GET call. I will send the set back using HttpRespose and then the framework will transform that into json
this is an actual method we have now
private void populateReturnFile()
{
var returnFileAnonymous = new
{
Vendor = this.Vendor,
OrganizationName = this.OrganizationName,
User = this.User,
Platform = this.Platform,
DictionaryType = this.DictionaryType,
UseCaseId = this.UseCaseId,
Data = this.Data.Select(d => new
{
MigrationTermId = d.MigrationTermId,
ImoLexicalCode = d.ImoLexicalCode
})
};
this.returnFile = returnFileAnonymous;
}
Then my GET will return the retunFile (this is a very simple method, i have remove irrelevant code)
[HttpGet]
public HttpResponseMessage Get(Guid migrationFileId)
{
ProblemList problemList = ProblemList.GetProblemList(migrationFileId);
return Request.CreateResponse(HttpStatusCode.OK, problemList.ReturnFile, new JsonMediaTypeFormatter());
}
If API calls is where you are using these classes, then I personally like to keep it simple and avoid complex inheritance hierarchy. Remember, simple code is good code.
I would make a separate class for each api request/response call. For very simple api calls (ajax requests for example) I like to use anonymous types, but for controllers that only handle API calls I like to create separate classes, organized in a nice folder structure.
Everyone has their "style" but as long as you strive for simplicity your code will be maintainable.
I've looked and tried every single solution posted here, with no avail.
My problem is:
On a web solution (ASP.NET MVC 3 C# / Razor), I'm using Json.Net to serialize the data displayed on some reports, to be able to send it over to a WPF application.
These reports results are a collection of Model objects.
I have the same Model objects on the WPF application, so when I deserialize the Json string, I would like to bind the results accordingly (keeping the original Model object).
The Assembly name and Object type are different on each end (Web / App) - different namespaces.
Here's what I've tried so far:
On the web solution:
// MyModel
public class MyModel
{
public long Id { get; set; }
public string Name { get; set; }
}
...
// data = IEnumerable<MyModel>
var jsonData = JsonConvert.SerializeObject(data.ToArray(), data.ToArray().GetType(),
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
});
On the app:
// MyModel
public class MyModel
{
[JsonProperty("Id")]
public long Id { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
}
...
var jsonArray = JsonConvert.DeserializeObject(e.jsonObject,
null,
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
Binder = new MySerializationBinder()
});
...
public class MySerializationBinder : DefaultSerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
return typeof(MyModel);
}
}
Can anyone give me a hand on this, please?
Thanks!
UPDATE
As per #Marc Gravell comment:
I forgot to mention the main issue here. I need to send the Object type across to the WPF app, because the listener will be expecting data from many reports - which are collections of different Models. So, when binding it back, I know which Object should be binded.
I stand by my original answer - type information in serialization data is just really messy - it would be far better to change the code not to need this, but to "fix" it (not sure that is the right word) - look carefully at the typeName - it isn't always what you are expecting:
public class MySerializationBinder : DefaultSerializationBinder
{
public override Type BindToType(string assemblyName, string typeName)
{
switch(typeName)
{
case "WebSolution.MyModel[]": return typeof(Application.MyModel[]);
case "WebSolution.MyModel": return typeof(Application.MyModel);
default: return base.BindToType(assemblyName, typeName);
}
}
}
Incidentally, once the array type is known, the element type is implicit - so you can save some effort by only including the array type:
new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.Arrays
}
But I still advise: don't do it this way.
The "mistake" here is including the full type names in the first place; the presence of type names in json should usually be the warning sign of a code-smell. Remove those, and there is nothing to do - it just works:
using Newtonsoft.Json;
using System.Collections.Generic;
using System.Linq;
static class Program
{
static void Main()
{
// here imagine we're in the web tier, serializing
var data = GetData();
var jsonData = JsonConvert.SerializeObject(
data.ToArray(), Formatting.None);
// now imagine we're at the application, deserializing
var appData = JsonConvert.DeserializeObject<Application.MyModel[]>(
jsonData);
// and it all works fine
}
static IEnumerable<WebSolution.MyModel> GetData()
{
yield return new WebSolution.MyModel { Id = 123, Name = "abc" };
yield return new WebSolution.MyModel { Id = 456, Name = "def" };
}
}
namespace WebSolution
{
// MyModel
public class MyModel
{
public long Id { get; set; }
public string Name { get; set; }
}
}
namespace Application
{
// MyModel
public class MyModel
{
[JsonProperty("Id")]
public long Id { get; set; }
[JsonProperty("Name")]
public string Name { get; set; }
}
}