I want to implement this function: when receive a http request, then create a new window form, and waiting for user inputing response text and write to the http response stream. The quesition is, I can not write response text to the stream in thread even I useing the Action<> delegate. Some code like this:
public partial class MainWindow : Window
{
private void Window_Loaded(object sender, RoutedEventArgs e)
{
//startup web server
Dispatcher.BeginInvoke(new Action(Start));
}
private void Start()
{
var server = new HttpServer();
try
{
server.EndPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 80);
server.Start();
server.RequestReceived += DataProcess;
}
catch (Exception ex)
{
return;
}
}
private void DataProcess(object sender, HttpRequestEventArgs e)
{
//create a new window in which user can input the response for the http request e.
var pw = (PrivateWindow)Dispatcher.Invoke(new Func<HttpRequestEventArgs, PrivateWindow>(CreatePrivateWindow), e);
}
public PrivateWindow CreatePrivateWindow(string windowKey, HttpRequestEventArgs e)
{
var pw = new PrivateWindow();
pw.httpRequest = e;//pass the stream to thread here.
windows.Add(pw);
return pw;
}
}
public partial class PrivateWindow : Window
{
private void btnSendMessage_Click(object sender, RoutedEventArgs e)
{
string messageText = new TextRange(txtWriteMessage.Document.ContentStart, txtWriteMessage.Document.ContentEnd).Text.Trim();
//write the response in thread
Dispatcher.BeginInvoke(new Action<HttpRequestEventArgs, string>(WriteToStream), httpRequest, messageText);
}
private void WriteToStream(HttpRequestEventArgs e, string str)
{
//**here occurs "stream can not be written" error.**
using (var writer = new StreamWriter(e.Response.OutputStream))
{
writer.Write(str);
}
}
}
Related
I have 2 applications: 1 dispatcher and second receiver.
I'm using Name pipe server and client to send to message from dispatcher to receiver
public partial class DispatcherForm : Form
{
public DispatcherForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
var pipe = new NamedPipeServerStream("DispatcherPipe", PipeDirection.InOut);
pipe.WaitForConnection();
Task.Run(async () =>
{
var buffer = Encoding.UTF8.GetBytes("Hello from dispacther");
await pipe.WriteAsync(buffer, 0, buffer.Length);
pipe.Dispose();
Application.Exit();
});
base.OnLoad(e);
}
}
public partial class ReceiverForm : Form
{
private NamedPipeClientStream m_pipe;
public ReceiverForm()
{
InitializeComponent();
}
protected override void OnLoad(EventArgs e)
{
startProcess();
base.OnLoad(e);
}
private void startProcess()
{
string processName = "DispatcherEventTester.exe";
var process = new Process();
process.StartInfo.FileName = processName;
process.Start();
m_pipe = new NamedPipeClientStream("DispatcherPipe");
startConnecting(new CancellationTokenSource().Token);
}
private Task startConnecting(CancellationToken token)
{
var buffer = new byte[8096];
return m_pipe.ConnectAsync(token)
.ContinueWith(async t =>
{
while(m_pipe.IsConnected)
{
if (t.IsCanceled)
{
m_pipe.Close();
break;
}
var ret = await m_pipe.ReadAsync(buffer, 0, buffer.Length);
this.Invoke(new Action(() =>
{
richTextBox1.AppendText(Encoding.UTF8.GetString(buffer)+Environment.NewLine);
}));
m_pipe.Close();
break;
}
},token);
}
private void button1_Click(object sender, EventArgs e)
{
startProcess();
}
}
the application works but weird things happen sometimes.
The application throws System.IO.IOException: All pipe instances are busy.
if pressing on button1 few times
what is this error and how do I clear the pipe instances?
there were also few times I received in ReadAsync method 0 values
Currently I am using WebSocket-Sharp. I am able to connect to the server through my application and I am able to send a Client.Send(Move.HeadNod); to the server on button click. However even though I declared
private WebSocket client;
const string host="ws://localhost:80";
public Form1()
{
InitializeComponent();
client=new WebSocket(host);
client.connect();
Client.OnMessage+=client_OnMessage
}
where:
client_OnMessage(object sender,MessageEventArgs e)
{
textbox1.text=convert.tostring(e);
client.send(move.headleft);
}
I am still unable to get a response from the server and continue sending command afterwards.
Edit
void Client_OnMessage(object sender,MessageEventArgs e)
{
if(e.IsText)
{
edata=e.data;
return;
}
else if(e.IsBinary)
{
Textbox1.Text=Convert.Tostring(e.RawData);
return;
}
}
This is the complete code that works on my machine. Put a break-point in both event handlers to see what happens. Maybe your web socket server throws an exception and you just don't know it:
public partial class Form1 : Form
{
private readonly WebSocket _client;
public Form1()
{
InitializeComponent();
_client = new WebSocket("ws://echo.websocket.org");
_client.OnMessage += Ws_OnMessage;
_client.OnError += Ws_OnError;
_client.Connect();
}
private void Ws_OnError(object sender, ErrorEventArgs e)
{
}
private void Ws_OnMessage(object sender, MessageEventArgs e)
{
if (e.IsText)
{
Invoke(new MethodInvoker(delegate () {
textBox1.Text = e.Data;
}));
}
else if (e.IsBinary)
{
Invoke(new MethodInvoker(delegate () {
textBox1.Text = Convert.ToString(e.RawData);
}));
}
}
private void button1_Click(object sender, System.EventArgs e)
{
_client.Send("Hi");
}
}
I'm writing an android app in c#, which communicates with a server.
// Set our view from the "main" layout resource
SetContentView (Resource.Layout.Main);
Button button = FindViewById<Button>(Resource.Id.button1);
TextView txt = FindViewById<TextView>(Resource.Id.textView1);
Client client = new Client();
client.Setup("ws://192.168.0.14:8001", "basic", WebSocketVersion.Rfc6455);
client.Start();
...
On start up, it should display a message on the TextView.
class Client : Activity{
private WebSocket websocketClient;
...
public void Setup(string url, string protocol, WebSocketVersion version)
{
...
websocketClient.Opened += new EventHandler(websocketClient_Opened);
}
private void websocketClient_Opened(object sender, EventArgs e){
txt.Text = ("Client successfully connected."); // this line is wrong
websocketClient.Send("Hello World!");
}
}
The problem is, I have no idea, how to access the TextView. I found this, but I don't know how should I use it in my case.
I don't know what library WebSocket you a using. I using websocket-sharp. It is example use:
protected override void OnCreate(Bundle bundle)
{
TextView txt = FindViewById<TextView>(Resource.Id.My);
using (var ws = new WebSocket("ws://dragonsnest.far/Laputa"))
{
ws.OnError += (sender, e) =>
{
txt.Text = e.Message;
};
..........
}
It is work. I see error message in my TextView.
If you get error, try use RunOnUiThread.Example:
private void websocketClient_Opened(object sender, EventArgs e)
{
this.RunOnUiThread(() =>
{
txt.Text = "your message";
});
}
Hope this help.
Just make WebsocketClient a property it a instead of a class variable and then you can access it from you activity.
public class MainActivity : Activity
{
private TextView txt;
private Client client;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
txt = FindViewById<TextView>(Resource.Id.textView1);
client = new Client();
client.WebsocketClient.Opened += websocketClient_Opened;
client.Setup("ws://192.168.0.14:8001", "basic", WebSocketVersion.Rfc6455);
client.Start();
}
protected override void OnDestroy()
{
client.WebsocketClient.Opened -= websocketClient_Opened;
base.OnDestroy();
}
private void websocketClient_Opened(object sender, EventArgs e)
{
txt.Text = ("Client successfully connected.");
// maybe have to be wrapped in a RunOnUiThread(() =>{ ... });
}
}
class Client
{
public WebSocket WebsocketClient { get; set; }
public void Setup(string url, string protocol, WebSocketVersion version)
{
// WebsocketClient = new ...
WebsocketClient.Opened += websocketClient_Opened;
}
private void websocketClient_Opened(object sender, EventArgs e)
{
WebsocketClient.Send("Hello World!");
}
}
Everything is going fine with connection , except when i close the connection and reopen (everything fine till now , data is received fine).
The error pops up when I try to write in the stream :
Cannot access a disposed object: 'System.Net.Sockets.NetworkStream' !!
I have tried using a new instance of client each time I connect
When closing connection : i have tried all these things like _client.GetStream().Close();
_client.Close();
but everything fail
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
myform = this;
}
public static Form1 myform;
Client c1;
public void ConnectButton_Click(object sender, EventArgs e)
{
c1 = new Client();
try
{ c1.Connect(IPADRESStext.Text, PORTNUMBERtext.Text); }
catch (Exception ex)
{ MessageBox.Show(ex.ToString()); }
}
private void CloseButton_Click(object sender, EventArgs e)
{
c1.Disconnect();
}
}
public sealed partial class Client
{
public void SendData(byte[] data)
{ _sender.SendData(data); }
public event EventHandler<DataReceivedEventArgs> DataReceived;
public void Connect(string IPADRESStxt, string PORTNUMBERtxt)
{
sq = new sequence();
_client = new TcpClient(IPADRESStxt, Int32.Parse(PORTNUMBERtxt));
_stream = _client.GetStream();
_sender = new Sender(_stream);
_receiver = new Receiver(_stream);
_receiver.DataReceived += OnDataReceived;
}
public void Disconnect()
{
_stream.Close();
_client.Close();
//_client.Client.Disconnect(false);
//tcpClient.GetStream().Close();
//tcpClient.Close();
}
private void OnDataReceived(object sender, DataReceivedEventArgs e)
{
var handler = DataReceived;
if (handler != null) DataReceived(this, e); // re-raise event
}
private TcpClient _client;
private NetworkStream _stream;
private Receiver _receiver;
private Sender _sender;
}
public sealed partial class Client
{
private sealed class Sender
{
internal void SendData(byte[] data)
{
_stream.Write(data, 0, data.Length); /// 2 When trying to execute this instruction
}
internal Sender(NetworkStream stream)
{
_stream = stream;
_thread = new Thread(Run);
_thread.Start();
}
private void Run()
{
// Code Code Code
SendData(Sframe); /// 1 Error pops up here
}
private NetworkStream _stream;
private Thread _thread;
}
}
I am using c# Windows Form Application and ftpWebRequest, I am doing a directory listing. I have a listbox that will display folders, by using the event DoubleClick in my listbox, the double clicked folder or item in my listbox will show its content. And now my problem is I don't know how to go back to the previous directory by using back button.
Here is my Code File:
namespace myFTPClass
{
public class myFTP
{
public string user;
public string pass;
public delegate void cThread1(string thread1);
public event EventHandler EH;
public List<string> myDIR = new List<string>();
public void getDirectoryList(string getDirectory)
{
try
{
FtpWebRequest fwr = FtpWebRequest.Create(getDirectory) as FtpWebRequest;
fwr.Credentials = new NetworkCredential(user, pass);
fwr.UseBinary = true;
fwr.UsePassive = true;
fwr.KeepAlive = true;
fwr.Method = WebRequestMethods.Ftp.ListDirectory;
StreamReader sr = new StreamReader(fwr.GetResponse().GetResponseStream());
while (!sr.EndOfStream)
{
myDIR.Add(sr.ReadLine());
}
}
catch(Exception we)
{
myDIR.Clear();
string msg = we.Message;
}
}
void myCallBackMethod(IAsyncResult ar)
{
cThread1 myThread = (cThread1)((System.Runtime.Remoting.Messaging.AsyncResult)ar).AsyncDelegate;
myThread.EndInvoke(ar);
if (EH != null) EH(this, null);
}
public void Async_getDirectoryList(string dir)
{
AsyncCallback ac = new AsyncCallback(myCallBackMethod);
cThread1 myThread = new cThread1(getDirectoryList);
myThread.BeginInvoke(dir, ac, null);
}
}
}
And Here is my Form1:
namespace my_ftp_v0._01
{
public partial class Form1 : Form
{
myFTP ftp = new myFTP();
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
btn_connect.Click += new EventHandler(btn_connect_Click);
listBox1.DoubleClick += new EventHandler(listBox1_DoubleClick);
btn_back.Click += new EventHandler(btn_back_Click);
ftp.EH += new EventHandler(ftp_EH);
}
void btn_back_Click(object sender, EventArgs e)
{
}
void listBox1_DoubleClick(object sender, EventArgs e)
{
string forward = "ftp://127.0.0.1/" + listBox1.SelectedItem.ToString();
listBox1.Items.Clear();
ftp.myDIR.Clear();
ftp.Async_getDirectoryList(forward);
}
void Form1_Load(object sender, EventArgs e)
{
txt_dir.Text = "ftp://127.0.0.1/";
txt_pass.PasswordChar = '‡';
}
void ftp_EH(object sender, EventArgs e)
{
if (InvokeRequired)
{
EventHandler eh = new EventHandler(ftp_EH);
this.Invoke(eh, new object[] { sender, e });
return;
}
for (int i = 0; i < ftp.myDIR.Count; i++)
{
listBox1.Items.Add(ftp.myDIR[i]);
}
}
void btn_connect_Click(object sender, EventArgs e)
{
ftp.Async_getDirectoryList(txt_dir.Text);
ftp.user = txt_user.Text;
ftp.pass = txt_pass.Text;
}
}
}
Move your SetDirectoryList to its own method
Add a Stack object to your class to track your requests
When the user double clicks add the request to the stack and then set the directory.
When the user hits the back
button, check if the stack has a request, if it does, pop it off and
call the set directory method.
Something like this...
public partial class Form1 : Form
{
myFTP ftp = new myFTP();
Stack _requestStack = new Stack();//Stack to store requests
public Form1()
{
InitializeComponent();
this.Load += new EventHandler(Form1_Load);
btn_connect.Click += new EventHandler(btn_connect_Click);
listBox1.DoubleClick += new EventHandler(listBox1_DoubleClick);
btn_back.Click += new EventHandler(btn_back_Click);
ftp.EH += new EventHandler(ftp_EH);
}
void btn_back_Click(object sender, EventArgs e)
{
if(_requestStack.Count > 0)
{
string directoryPath = (string)_requestStack.Pop();
SetDirectoryList(directoryPath);
}
}
void listBox1_DoubleClick(object sender, EventArgs e)
{
string directoryPath = listBox1.SelectedItem.ToString();
_stack.Push(directoryPath);
SetDirectoryList(directoryPath);
}
void SetDirectoryList(string directoryPath)
{
string forward = "ftp://127.0.0.1/" + directoryPath;
listBox1.Items.Clear();
ftp.myDIR.Clear();
ftp.Async_getDirectoryList(forward);
}
void btn_back_Click(object sender, EventArgs e)
{
create.server = create.server.TrimEnd('/');
create.server = create.server.Remove(create.server.LastIndexOf('/')+1);
listBox1.Items.Clear();
ftp.myDIR.Clear();
ftp.Async_getDirectoryList("");
}
I've already done this code to my back button and it works properly.