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.
Related
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;
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 ; }
Over the past two years I developed apps for the CF .NET 3.5 to be runned on warehouse's portable device(windows mobile).
From the beginning I just jumped into the process and made a lot of mistakes that I'm gradually correcting. What has came out are apps made in this way:
a main form to start the whole process which automatically creates a data-form, that will stay alive for the whole time. This data-form will keep all the datas that the user will insert or request from the server. The other forms are basically views of the data with methods to manipulate them.
It works but...am I doing this in the right way? Or maybe am I missing something really fundamental?
So, you created a data form, and you are using it like RAM. You never display the data, you simply store it there to access.
If someone ever has to take over your job (like you leave the company or die), they are going to hate you so bad.
A better technique would be to create a Class that houses all of this data.
The good part is, since you already have a data form, you probably already know how everything is organized!
Now, just use that knowledge of your data to create your class that you can read and write to.
If you have groups of similar items, create other classes that your main class will contain.
If you have several of these similar items, create publically accessible Lists of these items.
Make it as dead simple or as complex as you'd like!
Consider these classes, which are all generic enough to modify however you would need and demonstrate some extras added:
public class DataForm {
private GroupedItem m_item2;
public event EventHandler Item2Changed;
public DataForm() { // this is your constructor
Item1 = new GroupedItem();
Item2 = new GroupedItem();
ItemCollection = new GroupCollectionItems("Group1");
}
public float Value1 { get; set; }
public float Value2 { get; set; }
public GroupedItem Item1 { get; set; }
public GroupedItem Item2 {
get { return m_item2; }
set {
if (m_item2 != value) {
m_item2 = value;
if (Item2Changed != null) {
Item2Changed(this, EventArgs.Empty); // notify whoever is listening for the change
}
}
}
}
public GroupCollectionItems ItemCollection { get; set; }
}
public class GroupedItem {
public GroupedItem() { // this is your constructor
}
public string Name { get; set; }
public object Value { get; set; }
}
public class GroupCollectionItem {
private GroupCollectionItem() { // this is your constructor
}
public static GroupCollectionItem Create(string groupName, string itemName, object itemValue) {
var item = new GroupCollectionItem() {
Group = groupName,
Name = itemName,
Value = itemValue
};
return item;
}
public string Group { get; private set; }
public string Name { get; private set; }
public object Value { get; set; }
}
public class GroupCollectionItems : List<GroupCollectionItem> {
public GroupCollectionItems(string name) { // this is your constructor
Name = name;
}
public string Name { get; private set; }
}
I have this issue where I'm sending a request for a JSON Feed. The issue is that the feed has a dynamic header (i.e. when I send a request for "testinput1" the header response will be testinput1.
Therefore I need to make my RootObject dynamic, but I'm not sure how, could you please help me?
I've entered the troublesome part of the code below
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
textBlock1.Text = "Details Loaded.";
short_description.Text = feed.testinput1.short_description; // can I make testinput1 a constant? its based on code below
});
public class Event
{
public string description { get; set; }
public string datetime { get; set; }
}
public class TrackCode
{
public string short_description { get; set; }
public List<Event> events { get; set; }
}
public class RootObject
{
public string tracker;
public TrackCode testinput1// This needs to be based on user input each time
{
get; // Can I do something here to make sure that the "testinput1" changes each time?
set; // And create a constant that can be referred to?
}
}
Hopefully I can do something like this:
short_description.Text = feed.trackcode.short_description; // this is a constant
public class RootObject
{
public string tracker = "AB123456789NZ"; // This is the variable that changes
public TrackCode trackcode // this becomes a constant
{
get { return tracker; } // uses tracking number as value for JSON when it retrieves it
set { tracker = value;}
}
}
Where have I gone wrong? Thankyou!
I'm trying to figure out what the proper syntax is to achieve a certain API goal, however I am struggling with visibility.
I want to be able to access a Messenger instance's member like msgr.Title.ForSuccesses.
However, I do not want to be able to instantiate Messenger.Titles from outside my Messenger class.
I'm also open to making Messenger.Titles a struct.
I'm guessing I need some sort of factory pattern or something, but I really have no idea how I'd go about doing that.
See below:
class Program {
static void Main(string[] args) {
var m = new Messenger { Title = { ForErrors = "An unexpected error occurred ..." } }; // this should be allowed
var t = new Messenger.Titles(); // this should NOT be allowed
}
}
public class Messenger {
// I've tried making this private/protected/internal...
public class Titles {
public string ForSuccesses { get; set; }
public string ForNotifications { get; set; }
public string ForWarnings { get; set; }
public string ForErrors { get; set; }
// I've tried making this private/protected/internal as well...
public Titles() {}
}
public Titles Title { get; private set; }
public Messenger() {
Title = new Titles();
}
}
You just need to make Titles private and expose an interface instead of it.
class Program {
static void Main(string[] args) {
var m = new Messenger { Title = { ForErrors = "An unexpected error occurred ..." } }; // this is allowed
var t = new Messenger.Titles(); // this is NOT allowed
}
}
public class Messenger {
public interface ITitles {
string ForSuccesses { get; set; }
string ForNotifications { get; set; }
string ForWarnings { get; set; }
string ForErrors { get; set; }
}
private class Titles : ITitles {
public string ForSuccesses { get; set; }
public string ForNotifications { get; set; }
public string ForWarnings { get; set; }
public string ForErrors { get; set; }
}
public ITitles Title { get; private set; }
public Messenger() {
Title = new Titles();
}
}
If you make the Titles constructor internal you will be able to create instances of it within your assembly only. If it is an API, perhaps that will be protected enough? You can see this pattern within the BCL (such as HttpWebRequest that can be created only through calls to WebRequest.Create).
Why Would I Ever Need to Use C# Nested Classes Nested type is never intended to be initialized from external type.
Well, you could make Titles a struct and make the constructor either public or internal. In that way, every time a client gets a copy of the Titles instance through the Title property, they will be getting the value, not the reference. They could modify that value, but to apply that change to the internal state of your object, they would need to be able to set the value back again through the Title property. They can't, because you have the Title setter marked private.
You will have to do the same when you change a value internally. For example:
// Your constructor...
public Messenger()
{
Titles t = new Titles();
t.ForSuccesses = "blah";
Title = t;
}
You can do this internally because you have access to the private setter for the Title property.
The main downside is that it might confuse the clients of your framework a bit because it looks like you can set the values of the Titles instance, but there is no real way for them to commit that change back to the Messenger class.