In Unity project I have some class WsMessage for WebSocket interaction. This class located in my own library WebSocketModels.
namespace WebSocketModels
{
[Serializable]
public enum WsMessageType
{
System, Player, Challenge, DeclineChallenge, RemoveChallenge, Game, Move, Moves, Chat,
Players, Challenges, Games, Clock
}
[Serializable]
public class WsMessage
{
public WsMessageType type { get; set; }
public string data { get; set; }
public WsMessage() { }
public WsMessage(WsMessageType type, string data)
{
this.type = type;
this.data = data;
}
}
}
By some reason it cannot be deserialized. I didn't see any errors.
If i move this class from library directly to Unity project object of WsMessage creating normally.
I use this simple command for get an object of WsMessage:
WsMessage message = JsonConvert.DeserializeObject<WsMessage>(inputWsMessage);
I've met this problem after change my Unity player Scripting Backend to IL2CPP. On Mono everything was OK.
Example of JSON content
{"type":10,"data":"[{\"id\":\"0d8648e4-ce15-4084-87f9-f3de2b5a9b32\",\"fromPlayer\":{\"id\":\"af76e7c3-27b2-4d05-bcd3-f4b41c3bb7ba\",\"name\":\"Aydar\",\"rating\":1600.0,\"isOnline\":false},\"color\":0,\"timeControl\":{\"time_range\":10,\"time_increment\":5,\"control_type\":0},\"toPlayer\":null}]"}
So, seems like the problem is here;
public WsMessageType type { get; set; }
public string data { get; set; }
Why? because { get; set; } is syntactic sugar for getter and setter methods.
So, in other words, your code above is 'equivalent' to;
public void WsMessageType_SetValue(WsMessageType value)
{
WsMessageType = value;
}
public WsMessageType WsMessageType_GetValue()
{
return WsMessageType;
}
And the same for 'data'.
The problem arises when you try to serialize some data into some function, it doesn't make it sense, and the { get; set; } shortcut makes it harder to see.
If you use variables instead of getter/setter it should work!
ie;
public WsMessageType type;
public string data;
Related
I'm currently working on my final project which contains the use of WCF, WPF and C# and I'm having a hard time transfering an object through wcf.
I get an error after a while which says that the server did not provide a meaningful response.
The classes that are in use in the method that crashes are:
[DataContract]
public class Player
{
//public static int clientID = 0;
[DataMember]
public int Wins { get; set; }
[DataMember]
public int Loses { get; set; }
[DataMember]
public int realID { get; }
[DataMember]
public string nickName { get; set; }
public Player(int Wins, int Loses, string nickName)
{
this.Wins = Wins;
this.Loses = Loses;
this.nickName = nickName;
//clientID++;
realID = 1; //clientID;
}
}
[DataContract]
public class Run
{
[DataMember]
public List<Player> Players { get; set; }
[DataMember]
public bool isActive { get; set; }
public Run()
{
Players = new List<Player>();
}
public void playerJoined(Player player)
{
Players.Add(player);
}
public void playerLeft(Player player)
{
if (Players.Contains(player)) Players.Remove(player);
}
public void generateRun()
{
// TODO: get a random map from the DB and pass it to all players
return;
}
}
and the method that crashes the code is:
public Run getRunDetails(int runNumber)
{
runNumber = runNumber - 1;
return Runs[runNumber];
}
the code at the client side is:
ListBoxItem tempItem = ((ListBoxItem)allRuns.SelectedItem);
if(tempItem != null && !tempItem.Content.Equals("There are no runs available, create one now."))
{
string numString = ((string)tempItem.Content);
numString = numString.Substring(4, numString.Length - 4);
run = Service.getRunDetails(int.Parse(numString));
}
After some time of debugging I've found out the problem is in the list variable, I've tried to change it only to a Player variable -> getting the same error. Same goes for making my buffer and message sizes bigger.
The only way the code wont crash and send my Run object is when the List is not a data member..
//[DataMember]
public List<Player> Players { get; set; }
If I do the above the code works perfectly but I desperately need the List passed to the client side.
Sorry for the long post but I don't have a very long time and I need it done, any help will be very appreciated.
(Also, sorry for the poor formatting, I did my best)
I'm pretty sure the problem here is that you don't have a parameterless constructor in your Player...
try to add a
public Player() {}
to your class...
Either that or because your 'realId' [DataMember] has no setter, see this link for tips on correctly serializing readonly members.
WCF: Exposing readonly DataMember properties without set?
Also, dont forget to 'Update Service Reference' on the WCF Service in the Visual Studio client Project if you have changed members in classes that are passed across the WCF Channel.
My application reads in JSON from disk and deserialising using JSON.net; which is working fine.
My JSON is laid out like this:
{
"driver": {
"driverTag": "blah_blah",
"driverName": "Blah Blah",
"driverTransport": "serial-device"
},
"devices": [
{
"deviceName": "Dev1",
"deviceTag": "DEV1",
"deviceStartMode": "Auto"
},
{
"deviceName": "Dev2",
"deviceTag": "DEV2",
"deviceStartMode": "Auto"
}
]
}
Based on the "driverTransport" value, I deserialise to either a SerialDriverConfig, TelnetDriverConfig, SNMPDriverConfig... etc class.
As the "driver" properties will be the same for every driver, no matter the transport type, I have a "DriverConfigTemplate" class. The "devices" will differ from JSON file to JSON file and have specific properties for that transport type (i.e. a serial device will have properties like "serialPortName", "serialBaudRate" etc.)
I have a "DriverConfig" interface, where T is "DeviceConfig".
public interface DriverConfig<T> where T : DeviceConfig
{
DriverConfigTemplate driver { get; set; }
List<T> devices { get; set; }
}
My device config is as follows:
public class DeviceConfig : IDeviceConfig
{
public string deviceTag { get; set; }
public string deviceName { get; set; }
public string deviceStartMode { get; set; }
}
Now; the problem part. When I am deserialising, I check the transport type before hand and determine the class to use; i.e for a serial driver I will use the "SerialDriverConfig" class and deserialise using the "SerialDeviceConfig":
public class SerialDeviceConfig : DeviceConfig
{
public int serialComPort { get; set; }
public int serialBaudRate { get; set; }
public int serialDataBits { get; set; }
public string serialParity { get; set; }
public string serialStopBits { get; set; }
public string serialHandshake { get; set; }
public int serialReadTimeout { get; set; }
public int serialWriteTimeout { get; set; }
public bool serialRtsEnable { get; set; }
public bool serialDtrEnable { get; set; }
}
My "SerialDriverConfig" class looks like this:
public class SerialDriverConfig : DriverConfig<SerialDeviceConfig>
{
public DriverConfigTemplate driver { get; set; }
public List<SerialDeviceConfig> devices { get; set; }
}
Again, this is fine and the JSON.net deserialiser does its job perfectly.
I have a function that gets called when the JSON config file has been loaded and validated against its respective schema, then passed on to a "DeserialiseDriverConfig" function where I am trying to return the derived driver object; which is where I am stuck :(
private DriverConfig<DeviceConfig> DeserialiseDriverConfig(string _json, string _driverTransport)
{
switch (_driverTransport)
{
case "serial-device":
try
{
SerialDriverConfig _serialDriverConfig = JsonConvert.DeserializeObject<SerialDriverConfig>(_json);
if (_serialDriverConfig != null)
{
return _serialDriverConfig;
}
}
catch (Exception e)
{
//Blah blah blah
}
break;
}
return null;
}
I have been stuck on this one for a few days, have tried many things and this is where I have ended up. I am getting "Cannot implicitly convert type "SerialDriverConfig" to "DriverConfig". An explicit conversion exists (are you missing a cast?)" So I understand why this error is occurring, but cannot get around it.
Hope my code makes sense and someone can help me out here?
You can change your DriverConfig class to be non-generic
public interface DriverConfig
{
DriverConfigTemplate driver { get; set; }
List<DeviceConfig> devices { get; set; }
}
and instead of using derived classes (SerialDriverConfig etc.) you can set Json.net to deserialize to the correct DeviceConfig type based on either having a $type attribute in your JSON like this or using a custom JsonConverter similar to this
I'm not sure if this solution fits your need but if you create your method and SerialDriverConfig with using generic type T you can use your interface as a returning type. Can you try the code below;
Your Method:
private static DriverConfig<T> DeserialiseDriverConfig<T>(string _json, string _driverTransport)
{
switch (_driverTransport)
{
case "serial-device":
try
{
SerialDriverConfig<T> _serialDriverConfig = JsonConvert.DeserializeObject<SerialDriverConfig<T>>(_json);
if (_serialDriverConfig != null)
{
return _serialDriverConfig;
}
}
catch (Exception e)
{
//Blah blah blah
}
break;
}
return null;
}
SerialDriverConfig Class:
public class SerialDriverConfig<T> : DriverConfig<T>
{
public DriverConfigTemplate driver { get; set; }
public List<T> devices { get; set; }
}
Also you should consider changing DriverConfig<T> interface approach because if you leave it as-is you will have boxing issue. If you do not need you may remove where T : DeviceConfig from your interface or modify it according to your current circumstances.
Hope this helps, please let me know if this works for you
Scenario
I have some XML come down from a service that I want to deserialize.
Depending on what is returned from the service, the XML can vary slightly (with the element names); but the XML always follows a common structure.
Here is a sample of what the XML might look like:
<ATemplate>
<Name>SomeTemplate</Name>
<TemplateItems>
<ATemplateItem>
<Name>SomeTemplateItem</Name>
<TemplateFields>
<ATemplateField>
<Name>SomeTemplateField</Name>
<Colour>Blue</Colour>
</ATemplateField>
... more template fields
</TemplateFields>
</ATemplateItem>
... more template items
</TemplateItems>
</ATemplate>
Using the above XML as an example, I have created a ATemplate class that will deserialize nicely from the XML, using the ATemplateItem and ATemplateField classes accordingly:
public class ATemplate
{
public string Name { get; set; }
public List<ATemplateItem> TemplateItems { get; set; }
}
public class ATemplateItem
{
public string Name { get; set; }
public List<ATemplateField> TemplateFields { get; set; }
}
public class ATemplateField
{
public string Name { get; set; }
public string Colour { get; set; }
}
I use this code to deserialize:
ATemplate template;
using (TextReader reader = new StringReader(xmlString))
{
template = (ATemplate)new XmlSerializer(typeof(ATemplate)).Deserialize(reader);
}
All good, so far.
Curveball
The same scenario might occur where the XML contains BTemplate, BTemplateItems and BTemplateFields; still following the structure as above.
So I created other classes for this situation:
public class BTemplate { ... }
public class BTemplateItem { ... }
public class BTemplateField { ... }
And made the relevant classes inherit respectively from ITemplate, ITemplateItem and ITemplateField I created, also:
Interfaces
public class ITemplate
{
public string Name { get; set; }
public List<ITemplateItem> TemplateItems { get; set; }
}
public class ITemplateItem
{
public string Name { get; set; }
public List<ITemplateField> TemplateFields { get; set; }
}
public class ITemplateField
{
public string Name { get; set; }
public string Colour { get; set; }
}
This is so I can then create one function, which is able to loop through the ITemplateItems and their ITemplateFields and perform some cool stuff:
public void Foo(ITemplate template)
{
foreach (var item in template.TemplateItems)
{
// do cool stuff
foreach (var field in item.TemplateFields)
{
// do more cool stuff
}
}
}
Some things to note:
In the object that contains the XML, I know what "type" the XML contains - given an Enum I use to identify
I then use a switch statement to run different methods, depending on the said "type"
Generic Method?
Now, rather than deserializing the XML differently in each of those method cases, I would like to use a Generic method to deserialize.
So I created one, like this:
public ITemplate DeserializeTemplate<T>(string xmlString) where T : ITemplate
{
using (TextReader reader = new StringReader(xmlString))
{
return (T)new XmlSerializer(typeof(T)).Deserialize(reader);
}
}
And call it from within the specific methods like so:
var template = DeserializeTemplate<ATemplate>(xmlString);
Then, I can use the ITemplate that it returns, and pass it to Foo(ITemplate template) to go and perform some magic and wizardry.
But...
No compilation errors, as yet - however I get a RunTime error, because it cannot deserialize an Interface.
I gather this is because it's trying to then deserialize the ITemplate's TemplateItems as ITemplateItems.
Can I do the above?
My question is:
How can I get around this issue?
Can I use this Generic deserialize method?
Will I need to treat each one differently in the separate methods?
Will I need to make the Interface generic also, with the types to expect?
I'm banging my head against the desk, so I really hope you lovely SO people can help.
As always, your comments, answers and suggestions are much appreciated :)
Let's say I have a class from a 3rd-party, which is a data-model. It has perhaps 100 properties (some with public setters and getters, others with public getters but private setters). Let's call this class ContosoEmployeeModel
I want to facade this class with an interface (INavigationItem, which has Name and DBID properties) to allow it to be used in my application (it's a PowerShell provider, but that's not important right now). However, it also needs to be usable as a ContosoEmployeeModel.
My initial implementation looked like this:
public class ContosoEmployeeModel
{
// Note this class is not under my control. I'm supplied
// an instance of it that I have to work with.
public DateTime EmployeeDateOfBirth { get; set; }
// and 99 other properties.
}
public class FacadedEmployeeModel : ContosoEmployeeModel, INavigationItem
{
private ContosoEmployeeModel model;
public FacadedEmployeeModel(ContosoEmployeeModel model)
{
this.model = model;
}
// INavigationItem properties
string INavigationItem.Name { get; set;}
int INavigationItem.DBID { get; set;}
// ContosoEmployeeModel properties
public DateTime EmployeeDateOfBirth
{
get { return this.model.EmployeeDateOfBirth; }
set { this.model.EmployeeDateOfBirth = value; }
}
// And now write 99 more properties that look like this :-(
}
However, it's clear that this will involve writing a huge amount of boilerplate code to expose all the properties , and I'd rather avoid this if I can. I can T4 code-generate this code in a partial class, and will do if there aren't any better ideas, but I though I'd ask here to see if anyone had any better ideas using some super wizzy bit of C# magic
Please note - the API I use to obtain the ContosoEmployeeModel can only return a ContosoEmployeeModel - I can't extend it to return a FacededEmployeeModel, so wrapping the model is the only solution I can think of - I'm happy to be corrected though :)
The other approach may be suitable for you is to use AutoMapper to map base class to your facade here is sample code:
class Program
{
static void Main(string[] args)
{
var model = new Model { Count = 123, Date = DateTime.Now, Name = "Some name" };
Mapper.CreateMap<Model, FacadeForModel>();
var mappedObject = AutoMapper.Mapper.Map<FacadeForModel>(model);
Console.WriteLine(mappedObject);
Console.ReadLine();
}
class Model
{
public string Name { get; set; }
public DateTime Date { get; set; }
public int Count { get; set; }
}
interface INavigationItem
{
int Id { get; set; }
string OtherProp { get; set; }
}
class FacadeForModel : Model, INavigationItem
{
public int Id { get; set; }
public string OtherProp { get; set; }
}
}
Resharper allows the creation of "delegating members", which copies the interface of a contained object onto the containing object and tunnels the method calls/property access through to the contained object.
http://www.jetbrains.com/resharper/webhelp/Code_Generation__Delegating_Members.html
Once you've done that, you can then extract an interface on your proxy class.
I'm trying to create a map between a domain object and viewmodel to support a use case that feels quite common. The fact that I can't find a solution makes me think I'm approaching the problem incorrectly. Here's some psuedo code that represents my source and destination types:
public class DomainClass
{
public NestedDomainClass1 NestedDomainClass1{ get; set; }
}
public class NestedDomainClass1
{
public NestedDomainClass2 NestedDomainClass2 { get; set; }
}
public class NestedDomainClass2
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
public class DomainViewModel
{
public string PropertyA { get; set; }
public string PropertyB { get; set; }
public string PropertyC { get; set; }
}
As you can see, DomainViewModel maps perfectly to DomainClass.NestedDomainClass1.NestedDomainClass2. However, for reasons that aren't entirely relevant, I can't simply create a mapping at that level. Instead I have to map two levels higher:
Mapper.CreateMap<DomainObj, DomainViewModel>();
This is unfortunate, as the minute I do this, I can no longer rely on AutoMapper conventions to automagically map similarly named properties, and I end having to write a lot of highly repetitive code:
Mapper.CreateMap<DomainClass, DomainViewModel>().ForMember(dest=>dest.PropertyA, opt=>opt.MapFrom(source=>source.NestedDomainClass1.NestedDomainClass2.PropertyA));
Mapper.CreateMap<DomainClass, DomainViewModel>().ForMember(dest=>dest.PropertyB, opt=>opt.MapFrom(source=>source.NestedDomainClass1.NestedDomainClass2.PropertyB));
I've played with the RecognizeDestinationPrefixes and RecognizeDestinationPostfixes methods in the hopes of getting AutoMapper to "skip" directly to the property I'd like to map from (NestedDomainClass2), but no luck. Any help would be appreciated!
That's because you're trying map between two completely different types. You really need to do something like this:
Mapper.CreateMap<NestedDomainClass2, DomainViewModel>();
Mapper.AssertConfigurationIsValid();
var dvm = Mapper.Map<NestedDomainClass2, DomainViewModel>
(obj.NestedDomainClass1.NestedDomainClass2);
However if you want to, you can hide that detail by defining a TypeConverter. Something like this should work:
public class DomainTypeConverter : TypeConverter<DomainClass, DomainViewModel>
{
protected override DomainViewModel ConvertCore(DomainClass source)
{
return Mapper.Map<NestedDomainClass2, DomainViewModel>
(source.NestedDomainClass1.NestedDomainClass2);
}
}
You can then define your mapping to be something like this:
Mapper.CreateMap<NestedDomainClass2, DomainViewModel>();
Mapper.CreateMap<DomainClass, DomainViewModel>()
.ConvertUsing(new DomainTypeConverter());
Mapper.AssertConfigurationIsValid();
And use it like this:
var dvm = Mapper.Map<DomainClass, DomainViewModel>(dc);