C# WCF - Using entity from Service in client app - c#

I am new in WCF and have simple issue. In my service library i have class :
[DataContract]
public class Player
{
[DataMember]
public string UserName { get; set; }
[DataMember]
public int WinNum { get; set; }
[DataMember]
public int LoseNum { get; set; }
[DataMember]
public int PlayedTime { get; set; }
.
.
.
[OperationContract]
public override string ToString()
{
return UserName;
}
Service class look like this:
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class PiskvorkyService :IPiskvorkyService
{
[DataMember]
public List<Player> Players { set; get; }
public PiskvorkyService()
{
Players = new List<Player>();
}
.
.
.
public List<Player> GetPlayers()
{
return Players;
}
From client app (WPF) i can add some new Players into list on server, it work well. But now i need to get Player list from service in client app and list them wherever I need. I tried something like this in client app:
var Players = ps.GetPlayers(); //ps is instance of PiskvorkyServiceClient();
foreach (var player in Players)
{
MessageBox.Show(player.ToString());
}
But for each Player in list i just get:
Could someone help me please?
Thanks

You have overridden the ToString-method on the service side
[DataContract]
public class Player
{
.
.
.
[OperationContract]
public override string ToString()
{
return UserName;
}
But methods are not serialized and therefor not transfered to the client side. This means you receive a player object with only its data (all fields and/or properties decorated with [DataMember]).
This is the default behaviour.
So your best choice would be, as #Chris already mentioned, to call player.UserName on the client side.
Some other approach you can follow is to extend your model via extension methods on the client side. So you can do something like the following:
public static class PlayerExtensions
{
public static string Print(this Player player)
{
return player.Username;
}
}
Then you can use your player-objects like this on the client side:
var player = new Player { UserName = "Nick" };
string plyerName = player.Print();

This has nothing to do with WCF, it simply that you are using ToString on an object which haven't overridden it, which means you'll get the default implementation, which gives you the class name.
Do either:
public class Player
{
...
public override string ToString()
{
return this.UserName; // or whatever you wish to print
}
...
}
Or:
MessageBox.Show( player.UserName );

Call player.UserNameĀ on the client side. var Players = ps.GetPlayers(); //ps is instance of PiskvorkyServiceClient(); foreach (var player in Players) { MessageBox.Show( player.UserName ; }

Related

C# Cannot deserialize object of class from imported library

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;

C# Resolving Base Class to Correct Repository Method Call Based on Implemented Type

In our current project, we have an abstract base user class that is implemented by multiple other user types. We have a comparison class that can compare any of these types and then needs to call a correct update api based on the implemented type. I am trying to avoid bringing an if(typeof(User)) logic tree into the code and was hoping to figure out some way to solve the issue with method overloading. Are there any design patterns that can help solve this issue with some type of interface that can be dependency injected? Here is a basic code example
using System;
using System.Collections.Generic;
namespace ConsoleApplication5
{
class Program
{
static void Main(string[] args)
{
List<BaseUser> TestUsers = new List<BaseUser>();
TestUsers.Add(new UserA() { Email = "test1#test.com", Location = "New York, NY" });
TestUsers.Add(new UserB() { Email = "test2#test.com", State = "TN" });
foreach (var user in TestUsers)
{
//need to invoke the correct Print repo method based on the actual user type, possible interface?
}
Console.Read();
}
}
public abstract class BaseUser
{
public string Email { get; set; }
}
public class UserA : BaseUser
{
public string Location { get; set; }
}
public class UserB : BaseUser
{
public string State { get; set; }
}
public class UserARepo
{
void Print(UserA user)
{
Console.Write($"User A Saved {user.Email}, {user.Location}");
}
}
public class UserBRepo
{
void Print(UserB user)
{
Console.Write($"User B Saved {user.Email}, {user.State}");
}
}
}
If the Print methods only need the Email and Location/State properties of the objects, then change their signature to accept only these two strings.
I would add a common property to the abstract class, which returns the needed property in the User* classes:
namespace ConsoleApplication5
{
public abstract class BaseUser
{
public string Email { get; set; }
public string OtherLocation { get; set;}
}
public class UserA : BaseUser
{
public string Location { get; set; }
public string OtherLocation {
get
{
return this.Location;
}
set
{
this.Location = value;
}
}
}
public class UserB : BaseUser
{
public string State { get; set; }
public string OtherLocation {
get
{
return this.State;
}
set
{
this.State = value;
}
}
}
public class UserARepo
{
void Print(BaseUser user)
{
Console.Write($"User A Saved {user.Email}, {user.OtherLocation}");
}
}
public class UserBRepo
{
void Print(BaseUser user)
{
Console.Write($"User B Saved {user.Email}, {user.OtherLocation}");
}
}
}
Hopefully I'm understanding the problem correctly - but if each of those UserTypes needs an update API or Print Repo method, put them as abstract methods in the class:
public abstract class BaseUser
{
public string Email { get; set; }
public abstract void PrintRepo();
}
Basically, it's just a question of: what functionality is required of the subclasses if they want to implement your base class? They have to handle Update requests? Then put an abstract declaration in the abstract class that says, "Hey, if you inherit from me, you have to include an Update function."
Then your main function becomes something like:
foreach (var user in TestUsers)
{
user.PrintRepo();
}

Cannot pass an object in wcf

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.

Main class USER and subclass PLAYER, how to PLAYER=USER ? c#

I'm making the first server-client application and i need your help.
The client must autenticate itself and after it can play some games.
So I've got USER and PLAYER classes: USER comprends all user registered and PLAYER comprends user that play game (there are PLAYER_GAME1,PLAYER_GAME2, etc..).
Inside USER i've proprieties like name, surname, id and etc.
Inside PLAYER i need have the proprieties of the user plus point, time in game, etc.
Actually:
public class USER
{
public string name, surname, ID, password, IP;
WALLET wallet;
bool login;
datetime lastAccess;
TcpClient socket;
Thread receiveMessages;//this receive message for log-in
...*other 30 proprieties*
public USER(string n,string s,string _id,string pw)
{
*inizialize all variables*
}
}
public class PLAYER
{
public USER user;
Thread receiveMessages;
int points;
bool online;
...*other proprieties*
public PLAYER(USER u)
{
user=u;
*inizialize all variables*
}
}
so for getting name i have to do:
PLAYER p= new PLAYER(new USER(...));
string name=p.user.name;
I think is more smart make PLAYER subclass of USER and when user want play games i "expand" the class user with the proprieties of player so i need do :
public class USER
{
protected string name, surname, ID, password, IP;
WALLET wallet;
bool login;
datetime lastAccess;
TcpClient socket;
Thread receiveMessages;//this receive message for meneage the game
...*other 30 proprieties*
public USER(string n,string s,string _id,string pw)
{
*inizialize all variables*
}
}
public class PLAYER : USER
{
Thread receiveMessages;
...*other proprieties*
public PLAYER():base()// here, what could i do?
{
*inizialize all PLAYER variables*
}
}
so for getting name i would do:
PLAYER p= new PLAYER();
p=exixtingUser;
string name=p.name;
I know that SUBCLASS=MAINCLASS is impossible so how could i do it?
As I can understand, you want to create a Player role based on the User information.
If our classes are:
public class User
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public User(Guid id, string name)
{
Id = id;
Name = name;
}
}
public class Player : User
{
public TimeSpan TimeInGame { get; set; }
public Player(User userInfo)
: base(userInfo.Id, userInfo.Name)
{
}
}
usage of such constructor will be:
var player = new Player(user);
You can use a constructor accepting the User information. You also can write the extension method .ToPlayer() or something like it.
I think you should read the article about inheritance on the MSDN and continue the reading with Constructors articles.
Update:
I've understood your problem, but, unfortunately, there is no easy solution for it. You can either remain on your current solution, this will be alright if your application creates many players based on one user. If it is a -one-to-one relation, you can do something like this:
public class User
{
public Guid Id { get; private set; }
public string Name { get; private set; }
public User(User copyFrom)
{
Id = copyFrom.Id;
Name = copyFrom.Name;
// copy all the fields you need
}
}
public class Player : User
{
public TimeSpan TimeInGame { get; set; }
public Player(User userInfo)
: base(userInfo)
{
}
}
The main problem of this solution is that you have to copy it by yourself, without any automation mechanism. You can find a similar question here:
Copying the contents of a base class from a derived class
Per your request of clarification, and to only offer expansion of the nice solution by VMAtm.
public class USER
{
// changed to public getters so externally can be accessed
// for read-only, but write access for USER instance or derived class (PLAYER)
// QUESTIONABLE on public accessor on password
public string name { get; protected set; }
public string surname { get; protected set; }
public string ID { get; protected set; }
public string password { get; protected set; }
public string IP { get; protected set; }
WALLET wallet;
bool login;
datetime lastAccess;
TcpClient socket;
// make this too protected AND available to player AND any others that make sense above
protected Thread receiveMessages; //this receive message for meneage the game
...*other 30 proprieties*
public USER(string nm, string sur, string _id, string pw)
{
name = nm;
surname = sur;
ID = _id;
password = pw;
InitUserVars();
}
private InitUserVars()
{
*inizialize all variables*
}
}
public class PLAYER : USER
{
// removed the Thread receiveMessages;
// as it is avail on parent class USER
...*other proprieties*
// slightly different option, instead, call the "THIS" version of constructor
public PLAYER(USER ui) : this(ui.name, ui.surname, ui.ID, ui.password )
{ }
// Now, pass same initializing parms to the USER base class so that all still runs the same.
public PLAYER(string nm, string sur, string _id, string pw) : base(nm, sur, _id, pw)
{
// by calling the "base" above, all default behaviors are handled first
// Now, we can do whatever else specific to the PLAYER
InitPlayerVars()
}
private InitPlayerVars()
{
*inizialize variables associated with PLAYER that is NOT part of USER baseclass*
}
}
So now, with the same parameter constructor arguments in the player expanded from the user, you can actually jump to creating a player directly with parms or indirectly by-passing a user via.
PLAYER p1 = new PLAYER( "name", "mr", 123, "mypassword" );
or as result using an INSTANCE of a USER
USER u1 = new USER( "name", "mr", 123, "mypassword" );
PLAYER p1 = new PLAYER(u1);
Does this help clarify some initialization of multiple class implementations for you?

C# : Converting Base Class to Child Class

I have a class, NetworkClient as a base class :
using System.IO;
using System.Net.Sockets;
using System.Threading.Tasks;
namespace Network
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class NetworkClient
{
public NetworkClient()
{
tcpClient = new TcpClient();
}
public NetworkClient(TcpClient client)
{
tcpClient = client;
}
public virtual bool IsConnected
{
get;
private set;
}
private StreamWriter writer { get; set; }
private StreamReader reader { get; set; }
private TcpClient tcpClient
{
get;
set;
}
public virtual NetworkServerInfo NetworkServerInfo
{
get;
set;
}
public async virtual void Connect(NetworkServerInfo info)
{
if (tcpClient == null)
{
tcpClient=new TcpClient();
}
await tcpClient.ConnectAsync(info.Address,info.Port);
reader = new StreamReader(tcpClient.GetStream());
writer = new StreamWriter(tcpClient.GetStream());
}
public virtual void Disconnect()
{
tcpClient.Close();
reader.Dispose();
writer.Dispose();
}
public async virtual void Send(string data)
{
await writer.WriteLineAsync(data);
}
public async virtual Task<string> Receive()
{
return await reader.ReadLineAsync();
}
}
}
And also have a child class derived from NetworkClient :
using System.Net;
namespace Network
{
using Data;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class SkyfilterClient : NetworkClient
{
public virtual IPAddress Address
{
get;
set;
}
public virtual int Port
{
get;
set;
}
public virtual string SessionID
{
get;
set;
}
public virtual User UserData
{
get;
set;
}
protected virtual bool Authenticate(string username, string password)
{
throw new System.NotImplementedException();
}
}
}
The problem is, that when im trying to cast NetworkClient into SkyfilterClient. An exception is thrown, Unable to cast object of type 'Network.NetworkClient' to type 'Network.SkyfilterClient'.
Whats wrong with my code ? I see that Stream can be converted to NetworkStream, MemoryStream. Why NetworkClient can't be converted to Skyfilter Client?
As long as the object is actually a SkyfilterClient, then a cast should work. Here is a contrived example to prove this:
using System;
class Program
{
static void Main()
{
NetworkClient net = new SkyfilterClient();
var sky = (SkyfilterClient)net;
}
}
public class NetworkClient{}
public class SkyfilterClient : NetworkClient{}
However, if it is actually a NetworkClient, then you cannot magically make it become the subclass. Here is an example of that:
using System;
class Program
{
static void Main()
{
NetworkClient net = new NetworkClient();
var sky = (SkyfilterClient)net;
}
}
public class NetworkClient{}
public class SkyfilterClient : NetworkClient{}
HOWEVER, you could create a converter class. Here is an example of that, also:
using System;
class Program
{
static void Main()
{
NetworkClient net = new NetworkClient();
var sky = SkyFilterClient.CopyToSkyfilterClient(net);
}
}
public class NetworkClient
{
public int SomeVal {get;set;}
}
public class SkyfilterClient : NetworkClient
{
public int NewSomeVal {get;set;}
public static SkyfilterClient CopyToSkyfilterClient(NetworkClient networkClient)
{
return new SkyfilterClient{NewSomeVal = networkClient.SomeVal};
}
}
But, keep in mind that there is a reason you cannot convert this way. You may be missing key information that the subclass needs.
Finally, if you just want to see if the attempted cast will work, then you can use is:
if(client is SkyfilterClient)
cast
I'm surprised AutoMapper hasn't come up as an answer.
As is clear from all the previous answers, you cannot do the typecast. However, using AutoMapper, in a few lines of code you can have a new SkyfilterClient instantiated based on an existing NetworkClient.
In essence, you would put the following where you are currently doing your typecasting:
using AutoMapper;
...
// somewhere, your network client was declared
var existingNetworkClient = new NetworkClient();
...
// now we want to type-cast, but we can't, so we instantiate using AutoMapper
AutoMapper.Mapper.CreateMap<NetworkClient, SkyfilterClient>();
var skyfilterObject = AutoMapper.Mapper.Map<SkyfilterClient>(existingNetworkClient);
Here's a full-blown example:
public class Vehicle
{
public int NumWheels { get; set; }
public bool HasMotor { get; set; }
}
public class Car: Vehicle
{
public string Color { get; set; }
public string SteeringColumnStyle { get; set; }
}
public class CarMaker
{
// I am given vehicles that I want to turn into cars...
public List<Car> Convert(List<Vehicle> vehicles)
{
var cars = new List<Car>();
AutoMapper.Mapper.CreateMap<Vehicle, Car>(); // Declare that we want some automagic to happen
foreach (var vehicle in vehicles)
{
var car = AutoMapper.Mapper.Map<Car>(vehicle);
// At this point, the car-specific properties (Color and SteeringColumnStyle) are null, because there are no properties in the Vehicle object to map from.
// However, car's NumWheels and HasMotor properties which exist due to inheritance, are populated by AutoMapper.
cars.Add(car);
}
return cars;
}
}
If you HAVE to, and you don't mind a hack, you could let serialization do the work for you.
Given these classes:
public class ParentObj
{
public string Name { get; set; }
}
public class ChildObj : ParentObj
{
public string Value { get; set; }
}
You can create a child instance from a parent instance like so:
var parent = new ParentObj() { Name = "something" };
var serialized = JsonConvert.SerializeObject(parent);
var child = JsonConvert.DeserializeObject<ChildObj>(serialized);
This assumes your objects play nice with serialization, obv.
Be aware that this is probably going to be slower than an explicit converter.
In OOP, you can't cast an instance of a parent class into a child class. You can only cast a child instance into a parent that it inherits from.
I don't think you can downcast an object, however there is a simple way to "downcast" the object outside the box. It isn't type safe, but it works. First serialize the object into json, then deserialize it into the child class object. It works the same as if you were passing the object between apis. So, while there are some people who may say "this doesn't work or isn't good", I would argue that it is exactly the way our internet currently works, so... why not use that method? No mapping required as long as parameter names are the same, and they will be if it is a child class. Note: This will likely not copy any private fields; if you have a constructor with parameters, this probably needs to be tested as well to ensure there aren't side effects.
Here's my toolbox:
public static string ConvertToJson<T>(this T obj)
{
return JsonConvert.SerializeObject(obj);
}
public static T ConvertToObject<T>(this string json)
{
if (string.IsNullOrEmpty(json))
{
return Activator.CreateInstance<T>();
}
return JsonConvert.DeserializeObject<T>(json);
}
Here's how to use it:
var sfcl = networkClient.ConvertToJson().ConvertToObject<SkyfilterClient>();
There's a few ways of doing this. However, here is one of the easiest ways to do this and it's reusable.
What is happening is that we're getting all the properties of the parent class and updating those same properties on the child class. Where baseObj would be the parent object and T would be the child class.
public static T ConvertToDerived<T>(object baseObj) where T : new()
{
var derivedObj = new T();
var members = baseObj.GetType().GetMembers();
foreach (var member in members)
{
object val = null;
if (member.MemberType == MemberTypes.Field)
{
val = ((FieldInfo)member).GetValue(baseObj);
((FieldInfo)member).SetValue(derivedObj, val);
}
else if (member.MemberType == MemberTypes.Property)
{
val = ((PropertyInfo)member).GetValue(baseObj);
if (val is IList && val.GetType().IsGenericType)
{
var listType = val.GetType().GetGenericArguments().Single();
var list = (IList)Activator.CreateInstance(typeof(List<>).MakeGenericType(listType));
foreach (var item in (IList)val)
{
list.Add(item);
}
((PropertyInfo)member).SetValue(baseObj, list, null);
}
if (((PropertyInfo)member).CanWrite)
((PropertyInfo)member).SetValue(derivedObj, val);
}
}
return derivedObj;
}
You can't downcast. If the parent object is created, it cannot be cast to the child.
One suggested workaround would be to Create an interface which the parent implements. Have the child override functionality if needed or just expose the parents functionality. Change the cast to be an interface and do the operations.
Edit: May be could also check if the object is a SkyfilterClient using is keyword
if(networkClient is SkyfilterClient)
{
}
You can copy value of Parent Class to a Child class. For instance, you could use reflection if that is the case.
You can use the as operator to perform certain types of conversions between compatible reference types or nullable types.
SkyfilterClient c = client as SkyfilterClient;
if (c != null)
{
//do something with it
}
NetworkClient c = new SkyfilterClient() as NetworkClient; // c is not null
SkyfilterClient c2 = new NetworkClient() as SkyfilterClient; // c2 is null
I would recommend identifying the functionality you need from any subclasses, and make a generic method to cast into the right subclass.
I had this same problem, but really didn't feel like creating some mapping class or importing a library.
Let's say you need the 'Authenticate' method to take behavior from the right subclass. In your NetworkClient:
protected bool Authenticate(string username, string password) {
//...
}
protected bool DoAuthenticate<T>(NetworkClient nc, string username, string password) where T : NetworkClient {
//Do a cast into the sub class.
T subInst = (T) nc;
return nc.Authenticate(username, password);
}
You can't upcast you can only downcast Derived Class to Base Class
, but what you want to probably do is "create" not "cast" a new derived object from an existing base class object - just do it in the derived class's constructor
public class BaseClass
{
public int Property1 { get; set; }
public int Property2 { get; set; }
public int Property3 { get; set; }
}
public class DerivedClass : BaseClass
{
public DerivedClass(BaseClass myBaseClassObject)
{
this.Property1 = myBaseClassObject.Property1;
this.Property2 = myBaseClassObject.Property2;
this.Property3 = myBaseClassObject.Property3;
}
public int DerivedClassProperty3 { get; set; }
public int DerivedClassProperty4 { get; set; }
public int DerivedClassProperty5 { get; set; }
}
DerivedClass myNewDerivedObject = new DerivedClass(baseClassObject);
Use the cast operator, as such:
var skyfilterClient = (SkyfilterClient)networkClient;

Categories

Resources