I am trying to develop a web-socket server app for my UWP Windows 10 App.
This is my code:
class Server
{
public async void Start()
{
MessageWebSocket webSock = new MessageWebSocket();
//In this case we will be sending/receiving a string so we need to set the MessageType to Utf8.
webSock.Control.MessageType = SocketMessageType.Utf8;
//Add the MessageReceived event handler.
webSock.MessageReceived += WebSock_MessageReceived;
//Add the Closed event handler.
webSock.Closed += WebSock_Closed;
Uri serverUri = new Uri("ws://127.0.0.1/motion");
try
{
//Connect to the server.
await webSock.ConnectAsync(serverUri);
//Send a message to the server.
await WebSock_SendMessage(webSock, "Hello, world!");
}
catch (Exception ex)
{
//Add code here to handle any exceptions
}
}
//The MessageReceived event handler.
private void WebSock_MessageReceived(MessageWebSocket sender, MessageWebSocketMessageReceivedEventArgs args)
{
DataReader messageReader = args.GetDataReader();
messageReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
string messageString = messageReader.ReadString(messageReader.UnconsumedBufferLength);
//Add code here to do something with the string that is received.
}
//The Closed event handler
private void WebSock_Closed(IWebSocket sender, WebSocketClosedEventArgs args)
{
//Add code here to do something when the connection is closed locally or by the server
}
//Send a message to the server.
private async Task WebSock_SendMessage(MessageWebSocket webSock, string message)
{
DataWriter messageWriter = new DataWriter(webSock.OutputStream);
messageWriter.WriteString(message);
await messageWriter.StoreAsync();
}
}
It errors here:
await webSock.ConnectAsync(serverUri);
with this error:
Not found (404). (Exception from HRESULT: 0x80190194)
I don't have any personal experience with it, but you might want to give IotWeb HTTP Server a try. It seems to be a portable embedded HTTP and web socket server that also supports UWP and can be run inside Windows Store and Windows 10 IoT Core applications.
Judging from its repository, it's rather new and not exactly mature, nor does it have a lot of documentations or samples available. There's a NuGet package available, though.
Unfortunately I didn't manage to find any other alternative yet.
The code
await webSock.ConnectAsync(serverUri);
Is try to connect to existing server at ws://127.0.0.1/motion, Not to deploy a server on this address.
You can look for ways to build a c# WebSocket server at the follwing links:
https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API/Writing_WebSocket_server
http://www.codeproject.com/Articles/57060/Web-Socket-Server
Related
I created a Web API and would like to access it in my Android XAMARIN App. It's a XAMARIN Forms App, which references a .NET Standard 2.0 library with the newest RestSharp nuget package installed.
Unfortunately I get the error:
Error: ConnectFailure (No route to host)
whenever I do the following:
public async Task<List<ETFPortfolio>> GetPortfolios()
{
var client = new RestClient("http://10.0.2.2:51262/api/");
var request = new RestRequest("portfolio", Method.GET);
request.AddHeader("Accept", "application/json");
var response = client.Execute(request); // Result with the error stated above
throw new Exception();
}
My WebAPI controller is set up like this:
[Route("api/[controller]")]
public class PortfolioController : Controller
{
// GET api/portfolio
[HttpGet]
public async Task<IActionResult> Get()
{
try
{
var handler = new MyHandler();
var portfolioList = await handler.Handle();
return Ok(portfolioList);
}
catch (Exception ex)
{
return BadRequest(ex.Message);
}
}
I found a similar question, unfortunately there were no answers yet.
Error: ConnectFailure (No route to host)
Is there anything I'm missing here or could check out to make this work?
Since you are using a real device, your API url should not be a localhost but an IP address of the computer on which you have the API running.
localhost will work only on the emulator running on the same machine with your API.
P.S.: I wrote a blogpost on this topic, you might be interested in checking it as well.
I created an Edge browser extension which uses Native Messaging to a native app running via a Desktop Bridge technology. I used the SecureInput as a sample, which contains the Edge extension, UWP host and a Win32 Desktop Bridge app.
I need the Win32 Desktop Bridge app to connect to a web service using HTTP and WebSocket, so I added an internetClientServer and a privateNetworkClientServer capabilities to the package manifest, beside the already existed runFullTrust one.
The Win32 Desktop Bridge app activates just fine, and it is able to connect to the web server using HTTP. But as soon as it tries to open a WebSocket connection, the BackgroundTaskInstance on the UWP host receives a cancellation request with a BackgroundTaskCancellationReason.SystemPolicy as a reason, and the Desktop Bridge application closes. Unfortunately, the documentation for the BackgroundTaskCancellationReason.SystemPolicy does not explain much about true reasons of the cancellation request.
I tried to use two WebSocket classes: the System.Net.WebSockets.ClientWebSocket and the Windows.Networking.Sockets.MessageWebSocket, with the same result. No fancy code, just regular
var socket = new MessageWebSocket();
...
await socket.ConnectAsync(new Uri("wss://127.0.0.1:9001/myservice"));
The same WebSocket service endpoint is available from other WS clients, so I guess there is no server/firewall/antivirus issue here.
I also played with the CheckNetIsolation tool, adding loopback exemption for the Edge browser and for the package, with no effect. The HTTP works fine without the loopback exemption.
What may be a true reason of the task cancellation, and what can be a possible way to prevent it?
Ok, I resolved the issue. Thanks to this comment by Tom Shane I stumbled upon, I realized that the BackgroundTaskCancellationReason.SystemPolicy tells that the background task is closed by the system to release some system resources, and that in my case it happened because I didn't obtain a deferral in my async event handler. When the event handler yielded without a deferral, the system decided it can shut the task down. Below is a digested version of the code:
static class Program
{
static AppServiceConnection connection = null;
[STAThread]
static void Main(string[] args)
{
Thread appServiceThread = new Thread(new ThreadStart(ThreadProc));
appServiceThread.Start();
Application.Run();
}
static async void ThreadProc()
{
try {
connection = new AppServiceConnection();
connection.AppServiceName = "...";
connection.PackageFamilyName = Windows.ApplicationModel.Package.Current.Id.FamilyName;
connection.RequestReceived += OnRequestReceived;
connection.ServiceClosed += OnServiceClosed;
var status = await connection.OpenAsync();
....
}
catch (Exception e) { ... }
}
private static async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args)
{
var defer = args.GetDeferral(); // <== that was missing, rookie mistake!
try {
var msg = ParseMessage(args.Request.Message);
if (msg.type.Equals("ws")) {
// this method was truly async
// and every time it yielded the issue was revealed
await HandleWsMessage(request, msg);
}
else if (msg.type.Equals("http")) {
// but this method was actually synchronous despite being marked as "async"
// and it never yielded, masking the issue for HTTP client
await HandleHttpMessage(request, msg);
}
}
catch (Exception e) { ... }
finally {
defer.Complete();
}
}
}
We are using xamarin forms. After an Android or IOS device resumes from background, we are making a REST call in .net that is being triggered by a timer. The first attempt on IOS returns a "The Descriptor is not a socket" error and the Android returns a "Connection refused" error. The same code works fine in Windows. Future attempts (every few seconds) in all 3 platforms work fine. Has anyone seen this and have a fix?
Code
//app on resume event
protected async override void OnResume()
{
// Handle when your app resumes
if (MainPage is RootPage)
{
RootPage mainPage = MainPage as RootPage;
if (mainPage.Detail is NavigationPage)
{
NavigationPage nvPage = mainPage.Detail as NavigationPage;
if(nvPage.CurrentPage is ThingsPage)
{
ThingsPage thPage = nvPage.CurrentPage as ThingsPage;
thPage.TurnOnTimer();
}
}
}
}
//code on the page
public void TurnOnTimer()
{
if (viewModel != null)
{
viewModel.ContinueTimer = true;
viewModel.StartAnotherTimer();
}
}
//code in view model
public async void StartAnotherTimer()
{
while (ContinueTimer)
{
try
{
DevicesUpdate devicesUpdate = await DataSource.GetDevices(LocationID, ControllerID, lastDevicesUpdateReceivedAt);
}
catch (Exception ex)
{
}
// Update the UI (because of async/await magic, this is still in the UI thread!)
if (ContinueTimer)
{
await Task.Delay(TimeSpan.FromSeconds(3));
}
}
}
public static async Task<DevicesUpdate> GetDevices(Guid locationID, Guid controllerID, DateTime lastUpdateReceivedAt)
{
DevicesUpdate devicesUpdate = await GetLastUpdatedDevices(controllerID, lastUpdateReceivedAt);
}
//code in view model
public static async Task<DevicesUpdate> GetLastUpdatedDevices(Guid controllerID,
DateTime lastUpdate)
{
System.Net.Http.HttpClient client = new System.Net.Http.HttpClient();
string url = string.Format("http://appname.azurewebsites.net/api/devices?controllerid={1}&lastUpdate={2}"
, Constants.WebServerURL, controllerID, lastUpdate);
System.Net.Http.HttpResponseMessage response = await client.GetAsync(new Uri(url));
string result = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
DevicesUpdate devices = JSONHelper.Deserialize<DevicesUpdate>(result);
return devices;
}
else
{
if (response.ReasonPhrase == "UserException")
{
throw new UserException(result);
}
else
{
//throw error because the response from rest api is not a success
throw new System.Net.Http.HttpRequestException(result);
}
}
}
You might have a few things happening here that's causing problems.
GetDevices doesn't return anything. (I hope you just left out the return for brevity sake)
You are never setting ContinueTimer to false.
What iOS version are you on? In later versions, you HAVE to use HTTPS or explicitly allow non-secure connections. This shouldn't be a problem because Azure has ssl.
If you plan on running this in the background, you need to register your app as a background process.
If you don't plan on running this in the background, you might have issues with previous attempts being ran (or still trying to execute, or just have failed) and then calling more.
What is the reason for calling the 3 second timer for the network calls? What if the call takes more than 3 seconds (then you are making duplicate calls even though the first might succeed).
If you want to make your network calls more robust, check out this Blog Post by Rob Gibbons about resilient network calls.
First thing I would do is remove it from the timer because it seems like the underlying sockets are having issues cross-thread.
I have problem retrieve Azure messages from Queue on Windows Phone 7.
To add message I am using such code:
var queueClient = CloudStorageContext.
Current.
Resolver.
CreateCloudQueueClient() as CloudQueueClient;
var queue = queueClient.GetQueueReference("queuein");
queue.Create(
r => queue.AddMessage(
new CloudQueueMessage { AsBytes = Encoding.UTF8.GetBytes(msg) },
c =>
{
// Some logic here.
}));
To get message back it looks like I have to follow similar principle and use queue instance.
But GetMessage() method has VOID return type:
Could you guys help me to understand what the hell is going on in Mobile version of Azure queues, because in Windows console application those methods has return type.
Async patterns are a bit different on the phone. You need to handle the message in the callback function.
ShowAmWorkingInUILol = true;
// snip
queue.GetMessage(TimeSpan.FromMinutes(1), OnMessageReturned);
}
private void OnMessageReturned(CloudOperationResponse<CloudQueueMessage> response)
{
ShowAmWorkingInUILol = false;
// here's your response.
}
I have a Action that sends a simple email:
[HttpPost, ActionName("Index")]
public ActionResult IndexPost(ContactForm contactForm)
{
if (ModelState.IsValid)
{
new EmailService().SendAsync(contactForm.Email, contactForm.Name, contactForm.Subject, contactForm.Body, true);
return RedirectToAction(MVC.Contact.Success());
}
return View(contactForm);
}
And a email service:
public void SendAsync(string fromEmail, string fromName, string subject, string body, bool isBodyHtml)
{
MailMessage mailMessage....
....
SmtpClient client = new SmtpClient(settingRepository.SmtpAddress, settingRepository.SmtpPort);
client.EnableSsl = settingRepository.SmtpSsl;
client.Credentials = new NetworkCredential(settingRepository.SmtpUserName, settingRepository.SmtpPassword);
client.SendCompleted += client_SendCompleted;
client.SendAsync(mailMessage, Tuple.Create(client, mailMessage));
}
private void client_SendCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
Tuple<SmtpClient, MailMessage> data = (Tuple<SmtpClient, MailMessage>)e.UserState;
data.Item1.Dispose();
data.Item2.Dispose();
if (e.Error != null)
{
}
}
When I send a email, I am using Async method, then my method SendAsync return immediately, then RedirectToAction is called. But the response(in this case a redirect) isnĀ“t sent by ASP.NET until client_SendCompleted is completed.
Here's what I'm trying to understand:
When watching the execution in Visual Studio debugger, the SendAsync returns immediately (and RedirectToAction is called), but nothing happens in the browser until email is sent?
If i put a breakpoint inside client_SendCompleted, the client stay at loading.... until I hit F5 at debugger.
This is by design. ASP.NET will automatically wait for any outstanding async work to finish before finishing the request if the async work was kicked off in a way that calls into the underlying SynchronizationContext. This is to ensure that if your async operation tries to interact with the HttpContext, HttpResponse, etc. it will still be around.
If you want to do true fire & forget, you need to wrap your call in ThreadPool.QueueUserWorkItem. This will force it to run on a new thread pool thread without going through the SynchronizationContext, so the request will then happily return.
Note however, that if for any reason the app domain were to go down while your send was still in progress (e.g. if you changed the web.config file, dropped a new file into bin, the app pool recycled, etc.) your async send would be abruptly interrupted. If you care about that, take a look at Phil Haacks WebBackgrounder for ASP.NET, which let's you queue and run background work (like sending an email) in such a way that will ensure it gracefully finishes in the case the app domain shuts down.
This is an interesting one. I've reproduced the unexpected behaviour, but I can't explain it. I'll keep digging.
Anyway the solution seems to be to queue a background thread, which kind of defeats the purpose in using SendAsync. You end up with this:
MailMessage mailMessage = new MailMessage(...);
SmtpClient client = new SmtpClient(...);
client.SendCompleted += (s, e) =>
{
client.Dispose();
mailMessage.Dispose();
};
ThreadPool.QueueUserWorkItem(o =>
client.SendAsync(mailMessage, Tuple.Create(client, mailMessage)));
Which may as well become:
ThreadPool.QueueUserWorkItem(o => {
using (SmtpClient client = new SmtpClient(...))
{
using (MailMessage mailMessage = new MailMessage(...))
{
client.Send(mailMessage, Tuple.Create(client, mailMessage));
}
}
});
With .Net 4.5.2, you can do this with ActionMailer.Net:
var mailer = new MailController();
var msg = mailer.SomeMailAction(recipient);
var tcs = new TaskCompletionSource<MailMessage>();
mailer.OnMailSentCallback = tcs.SetResult;
HostingEnvironment.QueueBackgroundWorkItem(async ct =>
{
msg.DeliverAsync();
await tcs.Task;
Trace.TraceInformation("Mail sent to " + recipient);
});
Please read this first: http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx
I sent the bug to Microsoft Connect https://connect.microsoft.com/VisualStudio/feedback/details/688210/smtpclient-sendasync-blocking-my-asp-net-mvc-request