I'm setting up a new client-server-network with SuperSocket and can't connenct an AppSession to the server.
I found this question and tried it for my program.
The server is running fine, but at the moment I can only connect with the 'AsynTcpSession'. When I check the connected sessions it is shown as an 'AppSession' at the server. I want to use 'AppSession', because you can give them custom parameter.
My created AppSession:
public class MyAppSession : AppSession<MyAppSession, MyRequestInfo>
{
// those parameter
public int ClientKey { get; set; }
public string HashKey { get; set; }
}
Server:
MyAppServer _server = new MyAppServer();
ServerConfig _socketServerConfig = new ServerConfig { ReceiveBufferSize = 5000, MaxRequestLength = 5000, Name = "Test- Server", SendingQueueSize = 5000, ServerType = "MyAppServer", Port = 6000};
if (_server.Setup(_socketServerConfig))
{
DoStuff();
}
Client:
ClientSession _gateway = new AsyncTcpSession();
_gateway.Connect(6000);
On receiving telegram from Client:
private void ReceivedDataFromClient(MyAppSession session, MyRequestInfo requestinfo)
{
// session.SocketSession contains the Client AsynTcpSession
}
EDIT:
The AppSession has an void Initialize(IAppServer<TAppSession, TRequestInfo> appServer, ISocketSession socketSession)-Function. How do I use it? The session only knows the server ip and port.
AsynTcpSession and AppSession are different things, althought they are all called 'session'.
Any client connection packages / classes have no matter with AppSession. (eg. AsynTcpSession)
The AppSession just a temporary storage of client connection for AppServer.
Let the AppServer controlls the client connections, identify each clients, controll the connections pool...etc.
You can define many variables in the AppSession, But to assign values will still by your own codes (and client should send these informations).
Related
I am trying to create an application that pings the devices configured by the user and reflects the status online or offline. A user can specify IP and Ping Interval for a device and based on that configuration the application needs to ping the device. For example, if the user specifies IP 198.67.227.143 and Ping Interval as 5 seconds, then the application will ping 198.67.227.143 every 5 seconds and reflect the status of whether the device is online or offline.
There can be multiple devices with different ping intervals configured. For example, Device A has a ping interval of 10 seconds and Device B has a ping interval of 20 seconds.
I want to know what is the best way to check whether a device should be pinged or not. Currently, the solution I can come up with is setting up a process that runs every second and loops through all the configured devices and checks if the device should be pinged or not based on the LastPingTime of the device.
Is there a better way of approaching this problem? I am trying to accomplish this in C# and .NET 4.6.2.
One option you can try to have different timers for reach devices, you don't need to ping every second for each device.
I have done simple basic implantation for this, you can use this concept in your code.
//each device representation
public class Device
{
public string IpAddress { get; set; }
public int PingInterval { get; set; }
public Timer PingTimer { get; set; }
public bool IsOnline { get; set; }
}
public class DeviceManager
{
private List<Device> _devices;
public DeviceManager()
{
_devices = new List<Device>();
}
public void AddDevice(string ipAddress, int pingInterval)
{
var device = new Device
{
IpAddress = ipAddress,
PingInterval = pingInterval
};
device.PingTimer = new Timer(OnPingTimerElapsed, device, TimeSpan.Zero, TimeSpan.FromSeconds(pingInterval));
_devices.Add(device);
}
private void OnPingTimerElapsed(object state)
{
//you can log the device state at this place
var device = (Device)state;
// ping and update the status of the device
device.IsOnline = SendPing(device.IpAddress);
}
private bool SendPing(string ipAddress)
{
//ping logic implementation;
}
}
you can call like this.
DeviceManager deviceManager = new DeviceManager();
deviceManager.AddDevice("10.220.63.36", 5);
deviceManager.AddDevice("10.220.63.37", 10);
Using C#, the Windows Form Template from Visual Studio and the Microsoft Azure Client SDK
I'm trying to send a message to an IOT Hub. I tested connection String with a Virtual Pi and it works there, I can see the connection and incoming messages in the Azure Shell.
Imports:
using System.Windows.Forms;
using Microsoft.Azure.Devices;
using Message = Microsoft.Azure.Devices.Message;
static string connectionString = "HostName=****.azure- devices.net;DeviceId=****;SharedAccessKey=*******=";
static string deviceId = "SensorTest";
static ServiceClient serviceClient;
serviceClient = ServiceClient.CreateFromConnectionString(connectionString);
SendMessageToCloud("takemystringyoupieceof***").Wait();
private static async Task SendMessageToCloud(string s)
{
MyData data = new MyData
{
Thing1 = "string",
Thing2 = "string",
Thing3 = 1234,
Thing4 = "string",
Thing5 = s
};
var serializeData = JsonConvert.SerializeObject(data);
var commandMessage = new Message(Encoding.ASCII.GetBytes(serializeData));
await serviceClient.SendAsync(deviceId, commandMessage);
}
This throws an Inner Exception:
{"Put token failed. status-code: 401, status-description:
Unauthorized: When KeyName is empty the resource URI must include a device id (Value '****.azure- devices.net').."}
System.Exception {Microsoft.Azure.Devices.Common.Exceptions.UnauthorizedException}
I would like some help understanding the error message:
Isn't KeyName "SharedKey" in this instance?`
The deviceID is included as you can see above?
The Value in the error message is the value for hostname?
For working code example, myData class:
internal class MyData
{
public string Thing1 { get; set; }
public string Thing2 { get; internal set; }
public int Thing3 { get; set; }
public string Thing4 { get; set; }
public string Thing5 { get; set; }
}
You are using a DeviceClient connection string with the ServiceClient. The SendAsync you are calling in your SendMessageToCloud is actually a Cloud to Device API. So depending on your intention, the answer is you either need to use the DeviceClient (a helpful sample can be found here) or you want to use an appropriate Service connection string which can be found in the Shared access policies blade for the IoTHub in the portal. Practicing least privilege, the Service key allows cloud-to-device messages (details on shared access policies can be found here)
I'm developing a multiple players game with photon server and unity, have some questions on how server send messages to clients.
I know that I need a List of clientpeer to save the connecting clients, but I dont know how to save a peer to the List,and which send-message code should I use?
//here is the List that saving the clientpeers
public class ClientCollection
{
public List<PeerBase> clients;
public ClientCollection() { }
public void AddNewClient(PeerBase peer)
//is it right that I send in a PeerBase type argument?
{
clients.Add(peer);
}
public List<PeerBase> GetClients(PeerBase peer)
{
return clients;
}
}
I have never used soap api.
I have requirements that i have to call soap api & send response as a json(REST) api.
I have Web Service API Location(...?wsdl), Endpoint, Namespace & Soap action.
I also have username, password & other input parameters.
I am not sure how to create soap Envelope using above info & call api from c#.
Can anyone suggest me how to do it.
This is service GetRxHistory i am trying to call https://pharmacy.esihealthcaresolutions.com:9100/v4.0/RxHistoryService.svc?wsdl/GetRxHistory
First add service reference to your project using References > Add > Service Reference. In the address field enter the url for your wsdl file:
https://pharmacy.esihealthcaresolutions.com:9100/v4.0/RxHistoryService.svc?singleWsdl
You can create the client for calling this API using:
RxHistoryServiceContractClient client = new RxHistoryServiceContractClient();
You can then call various operations on the service using the client object.
client.xxxx = xxx;
client.xxx = xxx;
In your case, it would be something like this for your username and password:
client.ClientCredentials.UserName.UserName = "your username";
client.ClientCredentials.UserName.Password = "your password";
Finally, to get a response you'd write something like this:
try
{
_Client.Open();
You'd pass your request or client object here:
GetRxHistoryResponse _Response = _Client.{MethodToGetResponse}(client);
_Client.Close();
}
catch (Exception ex)
{
}
Isn't there any way to create soap envelop from data that i have?
We could use the Message class(System.ServiceModel.Channels) static method, CreateMessage method.
I have made a demo, wish it is useful to you.
class Program
{
static void Main(string[] args)
{
Product p = new Product()
{
ID = 1,
Name = "Mango"
};
Message m=Message.CreateMessage(MessageVersion.Soap12, "mymessage", p);
MessageHeader hd = MessageHeader.CreateHeader("customheader", "mynamespace", 100);
m.Headers.Add(hd);
Console.WriteLine(m);
}
}
public class Product
{
public int ID { get; set; }
public string Name { get; set; }
}
Result.
Here is an official document.
https://learn.microsoft.com/en-us/dotnet/api/system.servicemodel.channels.message.createmessage?view=netframework-4.7.2
I have got a server/client relationship where the client pulls an ArrayList from the server. If I set the server to always send an empty ArrayList then I don't get this error. So clearly the problem is that my data is too big for the connection and that it's closing before all the data can get through.
I have looked into this issue and I have added the features suggested by this question/answer:
https://stackoverflow.com/a/285542/3036134 Many solutions suggest the same thing.
I believe that I have implemented something incorrectly (I think it's most likely the Service Behaviour MaxItemsInObjectGraph as I am still getting the same error. I unfortunately can't figure out what's wrong with it though. Here's my code:
The error I'm receiving:
CommunicationException was unhandled. The underlying connection was closed: The connection was closed unexpectedly.
My WCF Service Code:
[ServiceContract]
public interface IModelData
{
[OperationContract]
ArrayList GetData();
}
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, MaxItemsInObjectGraph = 2147483647)]
public class ModelDataClient
{
ChannelFactory<IModelData> HttpFactory;
IModelData HttpProxy;
public ModelDataClient()
{
HttpFactory = new ChannelFactory<IModelData>(
new BasicHttpBinding(),
new EndpointAddress("http://localhost:8000/ModelData"));
HttpProxy = HttpFactory.CreateChannel();
}
public ArrayList GetData()
{
return HttpProxy.GetData();
}
}
[ServiceBehavior(UseSynchronizationContext = false, InstanceContextMode = InstanceContextMode.Single, MaxItemsInObjectGraph = 2147483647)]
public class ModelDataServer : IModelData
{
public delegate ArrayList GetData();
public GetData _GetData { get; set; }
public ModelDataServer()
{
}
public ArrayList GetData()
{
return _GetData();
}
}
My Client Side Code:
public partial class MainForm : Form
{
private ModelDataClient Client;
public MainForm()
{
InitializeComponent();
Client = new ModelDataClient();
}
private void Refresh()
{
ArrayList dataList = Client.GetData();
// ********** ERROR POINTS TO LINE ABOVE!!!!!!!!!!!!!!!!!!!!
// do something with datalist
}
}
My Server Side Code:
public partial class ScraperForm : Form
{
ServiceHost Host;
ModelDataServer DataServer;
ArrayList Data;
public ScraperForm()
{
InitializeComponent();
#region Start Data Server
DataServer = new ModelDataServer();
DataServer._GetData = new ModelDataServer.GetData(this.GetData);
BasicHttpBinding bhttpb = new BasicHttpBinding();
bhttpb.MaxBufferSize = 2147483647;
bhttpb.MaxReceivedMessageSize = 2147483647;
bhttpb.ReaderQuotas.MaxDepth = 32;
bhttpb.ReaderQuotas.MaxStringContentLength = 8388608;
bhttpb.ReaderQuotas.MaxArrayLength = 16384;
bhttpb.ReaderQuotas.MaxBytesPerRead = 4096;
bhttpb.ReaderQuotas.MaxNameTableCharCount = 16384;
Host = new ServiceHost(DataServer, new Uri[]
{
new Uri("http://localhost:8000")
});
Host.AddServiceEndpoint(typeof(IModelData),
bhttpb,
"ModelData");
Host.Open();
Data = new ArrayList();
}
private void CloseSever()
{
Host.Close();
}
public void UpdateData() // Run on a timer
{
ArrayList Data = new ArrayList()
// Update Data
}
public ArrayList GetData() // This is called by server which is called by client
{
return Data; // no error if I return new ArrayList();
}
}
EDIT: Would the problem be being caused by not having DataContract/DataMembers?
UPDATE
I have rebuilt my new implementation from the ground up using this tutorial (and the related ones): http://blogs.msdn.com/b/brunoterkaly/archive/2013/10/28/wcf-programming-how-to-write-a-client-app-that-connects-to-a-wcf-service.aspx (For anyone interested).
Instead of using an ArrayList (lots of unboxing) and a Typed List (comes out as an array if used with WCF), I have instead opted to pass my data using a string with the following format:
"~" to denote the start of a new member of the list
"," to denote the end of one of the datatypes in my custom one.
So it might look like "~NAME,1.29,1,4,123.1~NAME,1.23,3,1,13.2" etc. I would suggest people who want to use lists use this instead.
I have run into a new problem with my new implementation, likely the same/similar problem. Please see my new question: Object reference not set to an instance of an object - WCF Service and Delegates (WCF Hosted before Delegate is instantiated)
Thanks for your help everyone.
What is your client-side configured as? You've displayed your server-side configuration, but don't forget that the client-side has it's own configuration settings.
Looking at your server-side configuration, it appears that the violation is occurring on the reception of the data on the client.
See here for an example. You can also do this programmatically as well.
Edit
Now I see in the comments that this ArrayList you are getting from the server contains your own user-defined type RFData. I believe now that this is likely the source of your problem.
Data Contracts describe the data that is being exchanged. Data Contracts are used between the Client and Server to serialize and de-serialize data that is being sent over the wire. You need to use Data Contracts/ Data Members when you are defining your own type to be used within the WCF model. Primitives as well as many of the built-in .NET types already have Data Contracts.
For your RFData type it would be something like this:
// Apply the DataContract to the type
[DataContract]
public class RFData
{
// Apply the DataMemberAttribute to the various properties
[DataMember]
public double RFDouble { get; set; }
[DataMember]
public int RFInt { get; set; }
[DataMember]
public string RFString { get; set; }
}
I know you have several integers and doubles, but you get the gist. Here is a really helpful guide on Data Contracts from MSDN.