DTO to specific object conversion pattern - windows-runtime

The architecture: Win8 app + local Web API Self-Host share a common "Contracts" project.
The Web API returns very general contract types (IEnumerable etc.).
Within the Win8 app I want to convert these contracts to concrete MVVM compatible model objects which use ObservableCollection for example instead of IEnumerables.
I would have loved to use AutoMapper for this task but it is not compatible with the WinRT.

I used AutoMapper some time ago, but now I generally use a specific class to do this work so I can test it and implement "strange" logic. This class is responsible for the mapping in the 2 direction (if both are needed).
Sometimes, because I'm lazy ;-), I have used an implicit conversion operator to simplify the conversion, but I think that conceptually a constructor for the dto could be better:
public class ItemDto
{
public Int32 Id { get; set; }
public String Description { get; set; }
public static implicit operator ItemDto (Item item)
{
var dto = new ItemDto()
{
Id = item.Id,
Description = item.LongDescription
};
return dto;
}
In all these cases, I think that the possibility to test your mapping has a great value.

You can to use reflection ( System.Reflection) for mapper yours DTOs by yourself, in a loop by the properties and mapping using the portable CLR types.

Thank you for your suggestions.
I solved it in a non-generic fashion, for every model I do have a specific converter that does the job. What do you think?
using Project.Contracts;
using Project.Models;
namespace Project.Converters.Contracts
{
public static class ProductConverter
{
public static ProductContract ToContract(this Product model)
{
if (model == null)
{
return new ProductContract();
}
return new ProductContract
{
Id = model.Id,
Name = mode.Name,
Tags = model.Tags.ToContracts()
};
}
public static ICollection<ProductContract> ToContracts(this IEnumerable<Product> models)
{
if (models == null)
{
return new Collection<ProductContract>();
}
return models.Select(m => m.ToContract()).ToList();
}
public static Product ToModel(this ProductContract contract)
{
if (contract == null)
{
return new Product();
}
return new Product
{
Id = contract.Id,
Name = contract.Name,
Tags = contract.Tags.ToModels()
};
}
public static ObservableCollection<Product> ToModels(this IEnumerable<ProductContract> contracts)
{
if (contracts == null)
{
return new ObservableCollection<Product>();
}
return new ObservableCollection<Product>(contracts.Select(c => c.ToModel()));
}
}
}

Related

How can I do JSON serializer ignore navigation properties?

I am exactly in the same case that this question:
How do I make JSON.NET ignore object relationships?
I see the proposed solution and I know I must use a Contract Revolver, and I also see the code of the Contract Resolver, but I do not know how to use it.
Should I use it in the WebApiConfig.vb?
Should I modify my Entity Model anyway?
It is a useful question👍 and I hope this help:
A)
If you have created your models manually (without Entity Framework), mark the relation properties as virtual first.
If your models were created by EF, It has already done it for you and each Relation Property is marked as virtual, as seen below:
Sample class:
public class PC
{
public int FileFolderId {get;set;}
public virtual ICollection<string> Libs { get; set; }
public virtual ICollection<string> Books { get; set; }
public virtual ICollection<string> Files { get; set; }
}
B)
Those relation properties can now be ignored by the JSON serializer by using the following ContractResolver for JSON.NET:
CustomResolver:
class CustomResolver : DefaultContractResolver
{
private readonly List<string> _namesOfVirtualPropsToKeep=new List<string>(new String[]{});
public CustomResolver(){}
public CustomResolver(IEnumerable<string> namesOfVirtualPropsToKeep)
{
this._namesOfVirtualPropsToKeep = namesOfVirtualPropsToKeep.Select(x=>x.ToLower()).ToList();
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
var propInfo = member as PropertyInfo;
if (propInfo != null)
{
if (propInfo.GetMethod.IsVirtual && !propInfo.GetMethod.IsFinal
&& !_namesOfVirtualPropsToKeep.Contains(propInfo.Name.ToLower()))
{
prop.ShouldSerialize = obj => false;
}
}
return prop;
}
}
C)
Finally, to serialize your model easily use the above ContractResolver. Set it up like this:
// -------------------------------------------------------------------
// Serializer settings
JsonSerializerSettings settings = new JsonSerializerSettings
{
// ContractResolver = new CustomResolver();
// OR:
ContractResolver = new CustomResolver(new []
{
nameof(PC.Libs), // keep Libs property among virtual properties
nameof(PC.Files) // keep Files property among virtual properties
}),
PreserveReferencesHandling = PreserveReferencesHandling.None,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
Formatting = Formatting.Indented
};
// -------------------------------------------------------------------
// Do the serialization and output to the console
var json = JsonConvert.SerializeObject(new PC(), settings);
Console.WriteLine(json);
// -------------------------------------------------------------------
// We can see that "Books" filed is ignored in the output:
// {
// "FileFolderId": 0,
// "Libs": null,
// "Files": null
// }
Now, all the navigation (relation) properties [virtual properties] will be ignored automatically except you keep some of them by determine them in your code.😎
Live DEMO
Thanks from #BrianRogers for his answer here.
If you are using Newtonsoft.Json
Mark field with
Newtonsoft.Json.JsonIgnore
Instead of
System.Text.Json.Serialization.JsonIgnore

Change the json DateTime serialization in WCF 4.0 REST Service

I need to replace the DateTime serialization for JSON in WCF REST Self Hosted service. Right now, I'm using something like the following code to do it, but it's definitely not the way to go since it requires manipulating each class.
[DataContract]
public class Test
{
[IgnoreDataMember]
public DateTime StartDate;
[DataMember(Name = "StartDate")]
public string StartDateStr
{
get { return DateUtil.DateToStr(StartDate); }
set { StartDate = DateTime.Parse(value); }
}
}
where my utility function DateUtil.DateToStr does all the formatting work.
Is there any easy way to do it without having to touch the attributes on my classes which have the DataContract attribute? Ideally, there would be no attributes, but a couple of lines of code in my configuration to replace the serializer with one where I've overridden DateTime serialization.
Everything that I've found looks like I have to replace huge pieces of the pipeline.
This article doesn't appear to apply because in I'm using WebServiceHost not HttpServiceHost, which not part of the 4.5.1 Framework.
JSON.NET Serializer for WCF REST Services
By default WCF uses DataContractJsonSerializer to serialize data into JSON. Unfortunatelly date from this serializer is in very difficult format to parse by human brain.
"DateTime": "\/Date(1535481994306+0200)\/"
To override this behavior we need to write custom IDispatchMessageFormatter. This class will receive all data which should be returned to requester and change it according to our needs.
To make it happen to the operations in the endpoint add custom formatter - ClientJsonDateFormatter:
ServiceHost host=new ServiceHost(typeof(CustomService));
host.AddServiceEndpoint(typeof(ICustomContract), new WebHttpBinding(), Consts.WebHttpAddress);
foreach (var endpoint in host.Description.Endpoints)
{
if (endpoint.Address.Uri.Scheme.StartsWith("http"))
{
foreach (var operation in endpoint.Contract.Operations)
{
operation.OperationBehaviors.Add(new ClientJsonDateFormatter());
}
endpoint.Behaviors.Add(new WebHttpBehavior());
}
}
ClientJsonDateFormatter is simple class which just applies formatter ClientJsonDateFormatter
public class ClientJsonDateFormatter : IOperationBehavior
{
public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) { }
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
dispatchOperation.Formatter = new ResponseJsonFormatter(operationDescription);
}
public void Validate(OperationDescription operationDescription) { }
}
In the formatter we took imput and serialize it with the changed Serializer:
public class ResponseJsonFormatter : IDispatchMessageFormatter
{
OperationDescription Operation;
public ResponseJsonFormatter(OperationDescription operation)
{
this.Operation = operation;
}
public void DeserializeRequest(Message message, object[] parameters)
{
}
public Message SerializeReply(MessageVersion messageVersion, object[] parameters, object result)
{
string json=Newtonsoft.Json.JsonConvert.SerializeObject(result);
byte[] bytes = Encoding.UTF8.GetBytes(json);
Message replyMessage = Message.CreateMessage(messageVersion, Operation.Messages[1].Action, new RawDataWriter(bytes));
replyMessage.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Raw));
return replyMessage;
}
}
And to send information to client we need data writer - RawDataWriter. Its implementation is simple:
class RawDataWriter : BodyWriter
{
byte[] data;
public RawDataWriter(byte[] data)
: base(true)
{
this.data = data;
}
protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
{
writer.WriteStartElement("Binary");
writer.WriteBase64(data, 0, data.Length);
writer.WriteEndElement();
}
}
Applying all code will result in returning date in more friendly format:
"DateTime":"2018-08-28T20:56:48.6411976+02:00"
To show it in practice I created example in the github branch DateTimeFormatter.
Please check also this answer as very likely you also will need it.
There is a limitation in JSON to convert DateTime, specially according to your case.
Please see http://msdn.microsoft.com/en-us/library/bb412170(v=vs.110).aspx
and read the section Dates/Times and JSON
To resolve this problem, I simply changed the type of serialization from JSON to XML for all the calls including DateTime.
After long time discussion ,I have find out the solution for it.
Please Use the following Code to Solve serialized date..
[IgnoreDataMember]
public DateTime? PerformanceDate { get; set; }
[DataMember(EmitDefaultValue = false, Name = "PerformanceDate")]
public string UpdateStartDateStr
{
get
{
if (this.PerformanceDate.HasValue)
return this.PerformanceDate.Value.ToUniversalTime().ToString("s", CultureInfo.InvariantCulture);
else
return null;
}
set
{
// should implement this...
}
}

NHibernate LinqToHqlGenerator for SQL Server 2008 full text index 'Containing' keyword

I think I'm missing something fundamental when implementing a LinqToHql generator class.
I've successfully registered the SQL Server 2008 contains query using a custom dialect with this registration:
RegisterFunction("contains", new StandardSQLFunction("contains", null));
I have only one class with a full text index to be queried:
public class SearchName
{
public virtual Guid Id {get; set;}
public virtual string Name {get; set;} // this is the search field
}
The contains function works properly in HQL:
var names = Session.CreateQuery("from SearchName where contains(Name,:keywords)")
.SetString("keywords", "john")
.List();
and the generated SQL is perfect:
select searchname0_.Id as Id4_,
searchname0_.Name as Name4_
from Search_Name searchname0_
where contains(searchname0_.Name, 'john' /* #p0 */)
The next challenge was to implement the Linq to HQL generator:
public class MyLinqtoHqlGeneratorsRegistry :
DefaultLinqToHqlGeneratorsRegistry
{
public MyLinqtoHqlGeneratorsRegistry()
{
this.Merge(new ContainsGenerator());
}
}
public class ContainsGenerator : BaseHqlGeneratorForMethod
{
public ContainsGenerator()
{
SupportedMethods = new[] {
ReflectionHelper.GetMethodDefinition<SearchName>(d => d.Name.Contains(String.Empty))
};
}
public override HqlTreeNode BuildHql(MethodInfo method,
System.Linq.Expressions.Expression targetObject,
ReadOnlyCollection<System.Linq.Expressions.Expression> arguments,
HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
return treeBuilder.MethodCall("contains",
visitor.Visit(targetObject).AsExpression(),
visitor.Visit(arguments[0]).AsExpression()
);
}
}
}
Calling the method like this:
var namesLinq = Session.Query<SearchName>().Where(x=> x.Name.Contains("john")).ToList();
Unfortunately, this doesn't seem to override the built-in Contains method, and the generated SQL is wrong:
select searchname0_.Id as Id4_,
searchname0_.Name as Name4_
from Search_Name searchname0_
where searchname0_.Name like ('%' + 'john' /* #p0 */ + '%')
Is it not possible to override the default Contains method, or have I just made a silly mistake?
PS - I'm using NHibernate 3.3.1.4000
OK, I've finally figured it out!
First, I managed to delete the registration code from my configuration:
...
.ExposeConfiguration(cfg =>
{
cfg.LinqToHqlGeneratorsRegistry<MyLinqtoHqlGeneratorsRegistry>();
...
}
Second, don't try to override the existing Linq behaviors. I moved my Contains extension method to the full-text class.
Third, build the Hql tree correctly.
For others trying to implement a SQL 2008 Free-text contains search, here's the complete implementation:
public static class DialectExtensions
{
public static bool Contains(this SearchName sn, string searchString)
{
// this is just a placeholder for the method info.
// It does not otherwise matter.
return false;
}
}
public class MyLinqtoHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public MyLinqtoHqlGeneratorsRegistry()
: base()
{
RegisterGenerator(ReflectionHelper.GetMethod(() =>
DialectExtensions.Contains(null, null)),
new ContainsGenerator());
}
}
public class ContainsGenerator : BaseHqlGeneratorForMethod
{
string fullTextFieldName = "Name";
public ContainsGenerator()
: base()
{
SupportedMethods = new[] {
ReflectionHelper.GetMethodDefinition(() =>
DialectExtensions.Contains(null, null))
};
}
public override HqlTreeNode BuildHql(MethodInfo method,
System.Linq.Expressions.Expression targetObject,
ReadOnlyCollection<System.Linq.Expressions.Expression> arguments,
HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
// cannot figure out how to interrogate the model class to get an
// arbitrary field name...
// perhaps the RegisterGenerator() call above could be used to pass a
// property name to the ContainsGenerator constructor?
// in our case, we only have one full text searchable class, and its
// full-text searchable field is "Name"
HqlExpression[] args = new HqlExpression[2] {
treeBuilder.Ident(fullTextFieldName).AsExpression(),
visitor.Visit(arguments[1]).AsExpression()
};
return treeBuilder.BooleanMethodCall("contains", args);
}
}
For the above to work, you must have declared and used your custom dialect:
public class CustomMsSql2008Dialect : NHibernate.Dialect.MsSql2008Dialect
{
public CustomMsSql2008Dialect()
{
RegisterFunction(
"contains",
new StandardSQLFunction("contains", null)
);
}
}
Then you can use your new contains search this way:
var namesLinq = Session.Query<SearchName>().Where(x => x.Contains("john")).ToList();
... and the resulting SQL is perfect! (at least if you only have one table you're performing full-text searches on)
EDIT: UPDATED IMPLEMENTATION TO SUPPORT MORE THAN ONE FULLTEXT 'Contains' SEARCH PER QUERY.
Here's the revised version:
public static class DialectExtensions
{
public static bool FullTextContains(this string source, string pattern)
{
return false;
}
}
public class MyLinqtoHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public MyLinqtoHqlGeneratorsRegistry()
: base()
{
RegisterGenerator(ReflectionHelper.GetMethod(() => DialectExtensions.FullTextContains(null, null)),
new FullTextContainsGenerator());
}
}
public class FullTextContainsGenerator : BaseHqlGeneratorForMethod
{
public FullTextContainsGenerator()
{
SupportedMethods = new[] { ReflectionHelper.GetMethod(() => DialectExtensions.FullTextContains(null, null)) };
}
public override HqlTreeNode BuildHql(MethodInfo method,
System.Linq.Expressions.Expression targetObject,
ReadOnlyCollection<System.Linq.Expressions.Expression> arguments,
HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
HqlExpression[] args = new HqlExpression[2] {
visitor.Visit(arguments[0]).AsExpression(),
visitor.Visit(arguments[1]).AsExpression()
};
return treeBuilder.BooleanMethodCall("contains", args);
}
}
To use the revised version, the syntax is slightly different:
var namesLinq = Session.Query<SearchName>().Where(x => x.Name.FullTextContains("john")).ToList();

Emit odata.type field with DataContractJsonSerializer?

Is there a way to make DataContractJsonSerializer emit the "odata.type" field required when posting an OData entity into a collection that supports multiple entity types (hierarchy per table)?
If I construct DataContractJsonSerializer with a settings object with EmitTypeInformation set to Always, it emits a "__type" field in the output, but that's not the field name needed for OData and the format of the value is wrong as well.
Is there any way to hook into the DataContractJsonSerializer pipeline to inject the desired "odata.type" field into the serialization output?
It would be such a hack to have to parse the serialization output in order to inject the field. How does WCF Data Services do it? Not using DataContractJsonSerializer is my guess.
Have you considered using Json.Net? Json.Net is much more extensible and the scenario that you have can be done using a custom resolver. sample code
class Program
{
static void Main(string[] args)
{
Console.WriteLine(
JsonConvert.SerializeObject(new Customer { Name = "Raghu" }, new JsonSerializerSettings
{
ContractResolver = new CustomContractResolver()
}));
}
}
public class CustomContractResolver : DefaultContractResolver
{
protected override JsonObjectContract CreateObjectContract(Type objectType)
{
JsonObjectContract objectContract = base.CreateObjectContract(objectType);
objectContract.Properties.Add(new JsonProperty
{
PropertyName = "odata.type",
PropertyType = typeof(string),
ValueProvider = new StaticValueProvider(objectType.FullName),
Readable = true
});
return objectContract;
}
private class StaticValueProvider : IValueProvider
{
private readonly object _value;
public StaticValueProvider(object value)
{
_value = value;
}
public object GetValue(object target)
{
return _value;
}
public void SetValue(object target, object value)
{
throw new NotSupportedException();
}
}
}
public class Customer
{
public string Name { get; set; }
}
I can't answer your first two questions, but for the third question, I found on the OData Team blog a link to the OData WCF Data Services V4 library open source code. Downloading that code, you will see that they perform all serialization and deserialization manually. They have 68 files in their two Json folders! And looking through the code they have comments such as:
// This is a work around, needTypeOnWire always = true for client side:
// ClientEdmModel's reflection can't know a property is open type even if it is, so here
// make client side always write 'odata.type' for enum.
So that to me kind of implies there is no easy, clean, simple, elegant way to do it.
I tried using a JavaScriptConverter, a dynamic type, and other stuff, but most of them ended up resorting to using Reflection which just made for a much more complicated solution versus just using a string manipulation approach.

Bind to action method

Is it possible to use a simple action method - just like with Caliburn.Micro - instead of a command with MvvmCross bindings?
Example:
public void Action()
{
Tip = 11;
}
<Button
android:text="Button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/button1"
local:MvxBind="Click Action" />
It doesn't work out of the box, I tested that.
While I found a lot of samples about adding new target bindings, I didn't find a single one about adding a new source binding.
UPDATE:
This works now out of the box with the Rio binding. To use it, add the MvvmCross MethodBinding NuGet package to the Android project.
Up until now, much of the emphasis for MvvmCross has been on allowing multi-platform target binding with the source remaining mainly 'vanilla' INotifyPropertyChanged.
There have been some deviation in terms of ViewModel structure - e.g.:
the MvxCommandCollection - http://slodge.blogspot.co.uk/2013/03/fixing-mvvm-commands-making-hot-tuna.html
some users using Fody - http://twincoders.com/blog/codigo-limpio-con-fody/
Recently, several new feature requests have also been logged in this area:
AutoCommands - I think this is what you are asking about here - https://github.com/slodge/MvvmCross/issues/301
Rio binding sources - https://github.com/slodge/MvvmCross/issues/299
Tibet binding - https://github.com/slodge/MvvmCross/issues/298
Because of these, I do expect more functionality to be exposed in this area in the future...
With that said, if you wanted to get this working today, then MvvmCross Binding is overrideable so you could fairly easily do it:
1. Implement an ICommand that invokes a MethodInfo using reflection (for completeness this should probably also use a parameter if available) - some kind of InvokeMethodCommand (code for this left to the reader!)
.
2. Implement an MyMethodSourceBinding class which wraps the InvokeMethodCommand - something like:
public class MyMethodSourceBinding : MvxSourceBinding
{
private readonly MethodInfo _methodInfo;
protected MyMethodSourceBinding(object source, MethodInfo methodInfo)
: base(source)
{
_methodInfo = _methodInfo;
}
public override void SetValue(object value)
{
// do nothing - not allowed
}
public override Type SourceType
{
get { return typeof(ICommand); }
}
public override bool TryGetValue(out object value)
{
value = new InvokeMethodCommand(source, _methodInfo);
return true;
}
}
3. Override MvvmCross's registered IMvxSourceBindingFactory with your own implementation that can detect when a method is present - sadly most of this is cut and paste coding today - it would be something like
public class MySourceBindingFactory
: IMvxSourceBindingFactory
{
private IMvxSourcePropertyPathParser _propertyPathParser;
private IMvxSourcePropertyPathParser SourcePropertyPathParser
{
get
{
if (_propertyPathParser == null)
{
_propertyPathParser = Mvx.Resolve<IMvxSourcePropertyPathParser>();
}
return _propertyPathParser;
}
}
public IMvxSourceBinding CreateBinding(object source, string combinedPropertyName)
{
var tokens = SourcePropertyPathParser.Parse(combinedPropertyName);
return CreateBinding(source, tokens);
}
public IMvxSourceBinding CreateBinding(object source, IList<MvxPropertyToken> tokens)
{
if (tokens == null || tokens.Count == 0)
{
throw new MvxException("empty token list passed to CreateBinding");
}
var currentToken = tokens[0];
if (tokens.Count == 1)
{
return CreateLeafBinding(source, currentToken);
}
else
{
var remainingTokens = tokens.Skip(1).ToList();
return CreateChainedBinding(source, currentToken, remainingTokens);
}
}
private static MvxChainedSourceBinding CreateChainedBinding(object source, MvxPropertyToken propertyToken,
List<MvxPropertyToken> remainingTokens)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerChainedSourceBinding(source, (MvxIndexerPropertyToken) propertyToken,
remainingTokens);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
return new MvxSimpleChainedSourceBinding(source, (MvxPropertyNamePropertyToken) propertyToken,
remainingTokens);
}
throw new MvxException("Unexpected property chaining - seen token type {0}",
propertyToken.GetType().FullName);
}
private static IMvxSourceBinding CreateLeafBinding(object source, MvxPropertyToken propertyToken)
{
if (propertyToken is MvxIndexerPropertyToken)
{
return new MvxIndexerLeafPropertyInfoSourceBinding(source, (MvxIndexerPropertyToken) propertyToken);
}
else if (propertyToken is MvxPropertyNamePropertyToken)
{
//**************************
// Special code is here
var propertyToken = (MvxPropertyNamePropertyToken) propertyToken;
if (source != null)
{
var method = source.GetType().GetMethod(propertyToken.PropertyName, BindingFlags.FlattenHierarchy | BindingFlags.Public | BindingFlags.Instance);
if (method != null)
{
return new MyMethodSourceBinding(source, method);
}
}
return new MvxSimpleLeafPropertyInfoSourceBinding(source,
(MvxPropertyNamePropertyToken) propertyToken);
// Special code ends here
//**************************
}
else if (propertyToken is MvxEmptyPropertyToken)
{
return new MvxDirectToSourceBinding(source);
}
throw new MvxException("Unexpected property source - seen token type {0}", propertyToken.GetType().FullName);
}
}
4. Supply this source binding factory in your own custom binding builder - e.g.:
public class MyAndroidBindingBuilder
: MvxAndroidBindingBuilder
{
protected override IMvxSourceBindingFactory CreateSourceBindingFactory()
{
return new MvxSourceBindingFactory();
}
}
5. Supply this binding builder during your setup
public class Setup : MvxAndroidSetup
{
// ....
protected override MvxAndroidBindingBuilder CreateBindingBuilder()
{
return new MyAndroidBindingBuilder();
}
}
Note: This approach is only for advanced users right now... As suggested in the first part of this question, I do expect the code in this area to change quite a lot so you might also encounter some issues maintaining a fork in this area. (Indeed the code in this area has already changed quite significantly on the Tibet Binding branch within the GitHub repo!)