asp.net core with signalR < - > static socket - sockets

Use Case:
I have a asp.net core web application with signalR core for messaging. :)
Problem:
I have to receive messages from a socket connection [via System.Net.Sockets] (machine with own socket communication)
Is there any way to integrate the socket client in the web app (maybe Progamm.cs or Startup.cs?)
And how can I get access to the signalR to forward the received message to the signalR Hub?
thx

I suggest you to read the stockticker sample on : https://learn.microsoft.com/en-us/aspnet/signalr/overview/getting-started/tutorial-server-broadcast-with-signalr
I show you here a small sample which you can adapt to your application. You have to subscribe the messages from your own socket communication and then you can forward this messages to the connected clients.
Here is a small sample how to send the time from server to the clients.
(The interesting part for you is the line GlobalHost.ConnectionManager.GetHubContext<ClockHub>().Clients.All.sendTime(DateTime.UtcNow.ToString());. Which this you can send something to all connected clients.
My main class is a clock which sends the actual time to all connected clients:
public class Clock
{
private static Clock _instance;
private Timer timer;
private Clock()
{
timer = new Timer(200);
timer.Elapsed += Timer_Elapsed;
timer.Start();
}
private void Timer_Elapsed(object sender, ElapsedEventArgs e)
{ // ---> This is the important part for you: Get hubContext where ever you use it and call method on hub GlobalHost.ConnectionManager.GetHubContext<ClockHub>().Clients.All.sendTime(DateTime.UtcNow.ToString());
GlobalHost.ConnectionManager.GetHubContext<ClockHub>().Clients.Clients()
}
public static Clock Instance
{
get
{
if (_instance == null)
{
_instance = new Clock();
}
return _instance;
}
}
}
}
In the startup I created a sigleton instance of this clock, which lives as long as the application is running.
public class Startup
{
public void Configuration(IAppBuilder app)
{
var inst = Clock.Instance;
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
}
}
}
My Hub:
public class ClockHub : Hub<IClockHub>
{
}
Hub interface which defines the method, which the server can call:
public interface IClockHub
{
void sendTime(string actualTime);
}
This is the clients part:
<!DOCTYPE html>
<html>
<head>
<title></title>
<meta charset="utf-8" />
</head>
<body>
<div id="timeLabel" ></div>
<script src="scripts/jquery-1.6.4.min.js"></script>
<script src="scripts/jquery.signalR-2.2.0.js"></script>
<script src="signalr/hubs"></script>
<script>
$(function () { // I use jQuery in this example
var ticker = $.connection.clockHub;
function init() {
}
ticker.client.sendTime = function (h) {
$("#timeLabel").html(h);
}
$.connection.hub.start().done(init);
});
</script>
</body>
</html>
How to inject hubcontext in asp.net core 2.x
Call SignalR Core Hub method from Controller

Related

How to create a background service in .NET Maui

I'm new to mobile app development and am learning .NET Maui. The app I'm creating needs to listen for Accelerometer events, and send a notification to a web service if the events meet certain criteria. The bit I'm struggling with is how to have the app run in the background, i.e. with no UI visible, without going to sleep, as I'd want the user to close the UI completely. So I'm thinking the app needs to run as some kind of service, with the option to show a UI when needed - how can this be done?
i know it's beign a while but will post an answer for future users!
First we need to understand that background services depends on which platform we use.(thanks Jason) And i will focus on ANDROID, based on Xamarin Documentation (thanks Eli), adapted to Maui.
Since we are working with ANDROID, on MauiProgram we will add the following:
/// Add dependecy injection to main page
builder.Services.AddSingleton<MainPage>();
#if ANDROID
builder.Services.AddTransient<IServiceTest, DemoServices>();
#endif
And we create our Interface for DI which provides us the methods to start and stop the foreground service
public interface IServiceTest
{
void Start();
void Stop();
}
Then, before platform code we need to add Android Permissions on AndroidManifest.xml:
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
Android Main Activity
public class MainActivity : MauiAppCompatActivity
{
//set an activity on main application to get the reference on the service
public static MainActivity ActivityCurrent { get; set; }
public MainActivity()
{
ActivityCurrent = this;
}
}
And Finally we create our Android foreground service. Check Comments Below. Also on xamarin docs, they show the different properties for notification Builder.
[Service]
public class DemoServices : Service, IServiceTest //we implement our service (IServiceTest) and use Android Native Service Class
{
public override IBinder OnBind(Intent intent)
{
throw new NotImplementedException();
}
[return: GeneratedEnum]//we catch the actions intents to know the state of the foreground service
public override StartCommandResult OnStartCommand(Intent intent, [GeneratedEnum] StartCommandFlags flags, int startId)
{
if (intent.Action == "START_SERVICE")
{
RegisterNotification();//Proceed to notify
}
else if (intent.Action == "STOP_SERVICE")
{
StopForeground(true);//Stop the service
StopSelfResult(startId);
}
return StartCommandResult.NotSticky;
}
//Start and Stop Intents, set the actions for the MainActivity to get the state of the foreground service
//Setting one action to start and one action to stop the foreground service
public void Start()
{
Intent startService = new Intent(MainActivity.ActivityCurrent, typeof(DemoServices));
startService.SetAction("START_SERVICE");
MainActivity.ActivityCurrent.StartService(startService);
}
public void Stop()
{
Intent stopIntent = new Intent(MainActivity.ActivityCurrent, this.Class);
stopIntent.SetAction("STOP_SERVICE");
MainActivity.ActivityCurrent.StartService(stopIntent);
}
private void RegisterNotification()
{
NotificationChannel channel = new NotificationChannel("ServiceChannel", "ServiceDemo", NotificationImportance.Max);
NotificationManager manager = (NotificationManager)MainActivity.ActivityCurrent.GetSystemService(Context.NotificationService);
manager.CreateNotificationChannel(channel);
Notification notification = new Notification.Builder(this, "ServiceChannel")
.SetContentTitle("Service Working")
.SetSmallIcon(Resource.Drawable.abc_ab_share_pack_mtrl_alpha)
.SetOngoing(true)
.Build();
StartForeground(100, notification);
}
}
Now we have our foreground Service working on Android, that show a notification ("Service Working"). Every time it starts. I make a show message foreground service to see it better while testing, in your case it suppose to close the app if that's what you want, but the functioning it's the same.
So having our background service working only left a way to call it so on our main page (as example) i will do the following:
MainPage.xaml
<VerticalStackLayout>
<Label
Text="Welcome to .NET Multi-platform App UI"
FontSize="18"
HorizontalOptions="Center" />
<Button
x:Name="CounterBtn"
Text="start Services"
Clicked="OnServiceStartClicked"
HorizontalOptions="Center" />
<Button Text="Stop Service" Clicked="Button_Clicked"></Button>
</VerticalStackLayout>
MainPage.xaml.cs
public partial class MainPage : ContentPage
{
IServiceTest Services;
public MainPage(IServiceTest Services_)
{
InitializeComponent();
ToggleAccelerometer();
Services = Services_;
}
//method to start manually foreground service
private void OnServiceStartClicked(object sender, EventArgs e)
{
Services.Start();
}
//method to stop manually foreground service
private void Button_Clicked(object sender, EventArgs e)
{
Services.Stop();
}
//method to work with accelerometer
public void ToggleAccelerometer()
{
if (Accelerometer.Default.IsSupported)
{
if (!Accelerometer.Default.IsMonitoring)
{
Accelerometer.Default.ReadingChanged += Accelerometer_ReadingChanged;
Accelerometer.Default.Start(SensorSpeed.UI);
}
else
{
Accelerometer.Default.Stop();
Accelerometer.Default.ReadingChanged -= Accelerometer_ReadingChanged;
}
}
}
//on accelerometer property change we call our service and it would send a message
private void Accelerometer_ReadingChanged(object sender, AccelerometerChangedEventArgs e)
{
Services.Start(); //this will never stop until we made some logic here
}
}
It's a long Answer and it would be great to have more official documentation about this! Hope it helps! If anyone can provide more info about IOS, Windows, MacCatalyst would be awesome!

Add multiple SPIFFS files to captive portal on Async web server on ESP32

I'm using simple code of modified Captive portal with asynchronous web portal (from ESPAsyncWebServer library - https://github.com/me-no-dev/ESPAsyncWebServer). It send html page from SPIFFS flash memory.
The way it is working now, is that it send index.html on any connection. I've just modified single line that in mentioned example was sending hmtl code. What I'd like to archive, is to be able to send more files, like html file and image.
So here is my code:
#include <DNSServer.h>
#include <WiFi.h>
#include <AsyncTCP.h>
#include "ESPAsyncWebServer.h"
#include <SPIFFS.h>
DNSServer dnsServer;
AsyncWebServer server(80);
class CaptiveRequestHandler : public AsyncWebHandler {
public:
CaptiveRequestHandler() {}
virtual ~CaptiveRequestHandler() {}
bool canHandle(AsyncWebServerRequest *request) {
//request->addInterestingHeader("ANY");
return true;
}
void handleRequest(AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", String(), false);
}
};
void setup() {
Serial.begin(115200);
if (!SPIFFS.begin()) {
Serial.println("An Error has occurred while mounting SPIFFS");
return;
}
WiFi.softAP("esp-captive");
dnsServer.start(53, "*", WiFi.softAPIP());
server.addHandler(new CaptiveRequestHandler()).setFilter(ON_AP_FILTER);//only when requested from AP
server.on("/image1", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(SPIFFS, "/image1.jpg", "image/jpg"); // this part has been modified
});
server.begin();
}
void loop() {
dnsServer.processNextRequest();
}
I've tried to add
server.on("/image1", HTTP_GET, [](AsyncWebServerRequest * request) {
request->send(SPIFFS, "/image1.jpg", "image/jpg"); // this part has been modified
});
in setup section as explained here - https://randomnerdtutorials.com/display-images-esp32-esp8266-web-server/
But it's not working. I've tried messing with path changing "/" in places whare it appears, but with no luck. Further, if I change
void handleRequest(AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", String(), false);
}
to
void handleRequest(AsyncWebServerRequest *request) {
request->send(SPIFFS, "/image1.jpg", "image/jpg");
}
when logging to AP I get image not website, so I think paths are good.
To add more information this is my webpage code:
<!DOCTYPE html>
<html style="height: 100%">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body style="background-image: url('image1'); background-size: contain; background-color: black; background-repeat: no-repeat; background-position: 50% 0%; height=100%">
<h1 style="color:white">ESP32</h1>
</body>
</html>
and it is working fine on non-captive_portal solution (as explaind in previously mentioned tutorial).
So my question is how can I get to load not only single file on captive portal in asynchronous webserver, but more complicated (still very simple) webpage?
I struggeled with it for a while. But here is the answer. On the CaptiveRequestHandler() {} you can place your http calls.
Here is an example for you:
class CaptiveRequestHandler : public AsyncWebHandler {
public:
CaptiveRequestHandler() {
/* THIS IS WHERE YOU CAN PLACE THE CALLS */
server.onNotFound([](AsyncWebServerRequest *request){
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/NotFound.html", "text/html");
request->send(response);
});
server.on("/Bootstrap.min.css", HTTP_GET, [](AsyncWebServerRequest *request) {
AsyncWebServerResponse* response = request->beginResponse(SPIFFS, "/Bootstrap.min.css", "text/css");
request->send(response);
});
}
virtual ~CaptiveRequestHandler() {}
bool canHandle(AsyncWebServerRequest *request) {
//request->addInterestingHeader("ANY");
return true;
}
void handleRequest(AsyncWebServerRequest *request) {
request->send(SPIFFS, "/index.html", String(), false);
}
};

Vertx3.0 Simple Form upload

Vertx3.0 http simpleform file uploader is throwing error for multiple file.
Am using vertx3.0 simple form upload. It is working fine when i upload single file. If the form has the input "multiple" and choose multiple files, The HTTPServerUpload is throwing error "Response has already been written". Since the response is end in the endhandler for 1st file, it is throwing this error for subsequent files. is there any other way for multiple files ?
Simpleform file upload using vertx3.0
public class SimpleFormUploadServer extends AbstractVerticle {
public static void main(String[] args) {
Runner.runExample(SimpleFormUploadServer.class);
}
#Override
public void start() throws Exception {
vertx.createHttpServer()
.requestHandler(req -> {
if (req.uri().equals("/")) {
// Serve the index page
req.response().sendFile("index.html");
} else if (req.uri().startsWith("/form")) {
req.setExpectMultipart(true);
req.uploadHandler(upload -> {
upload.exceptionHandler(cause -> {
req.response().setChunked(true)
.end("Upload failed");
});
upload.endHandler(v -> {
req.response()
.setChunked(true)
.end("Successfully uploaded to "
+ upload.filename());
});
// FIXME - Potential security exploit! In a real
// system you must check this filename
// to make sure you're not saving to a place where
// you don't want!
// Or better still, just use Vert.x-Web which
// controls the upload area.
upload.streamToFileSystem(upload.filename());
});
} else {
req.response().setStatusCode(404);
req.response().end();
}
}).listen(8080);
}
}
Exception :
SEVERE: Unhandled exception
java.lang.IllegalStateException: Response has already been written
at io.vertx.core.http.impl.HttpServerResponseImpl.checkWritten(HttpServerResponseImpl.java:561)
at io.vertx.core.http.impl.HttpServerResponseImpl.end0(HttpServerResponseImpl.java:389)
at io.vertx.core.http.impl.HttpServerResponseImpl.end(HttpServerResponseImpl.java:307)
at io.vertx.core.http.impl.HttpServerResponseImpl.end(HttpServerResponseImpl.java:292)
at com.nokia.doas.vertx.http.upload.SimpleFormUploadServer$1$1$2.handle(SimpleFormUploadServer.java:85)
at com.nokia.doas.vertx.http.upload.SimpleFormUploadServer$1$1$2.handle(SimpleFormUploadServer.java:1)
at io.vertx.core.http.impl.HttpServerFileUploadImpl.notifyEndHandler(HttpServerFileUploadImpl.java:213)
at io.vertx.core.http.impl.HttpServerFileUploadImpl.lambda$handleComplete$165(HttpServerFileUploadImpl.java:206)
at io.vertx.core.file.impl.AsyncFileImpl.lambda$doClose$226(AsyncFileImpl.java:470)
at io.vertx.core.impl.ContextImpl.lambda$wrapTask$16(ContextImpl.java:335)
at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:358)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:357)
at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:112)
at java.lang.Thread.run(Unknown Source)
index.html
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title></title>
</head>
<body>
<form action="/form" ENCTYPE="multipart/form-data" method="POST" name="wibble">
choose a file to upload:<input type="file" name="files" multiple="multiple"/><br>
<input type="submit"/>
</form>
</body>
</html>
You can use vertx-web to easily handle file uploads:
router.route().handler(BodyHandler.create());
router.post("/some/path/uploads").handler(routingContext -> {
Set<FileUpload> uploads = routingContext.fileUploads();
// Do something with uploads....
});
Moreover, you will take benefits of the routing facility, and you can even serve static files such as index.html.
Hope this will help.
Multiple file upload is achievable in vert.x. Use multiple upload button in HTML and use uploadHandler of HttpRequest. UploadHandler would be invoked as many times any many files have been uploaded.
HttpServerRequest request = routingContext.request();
request.setExpectMultipart(true);
request.endHandler(new Handler<Void>() {
#Override
public void handle(Void aVoid) {
MultiMap entries = request.formAttributes();
Set<String> names = entries.names();
logger.info("UPLOAD_CONTENT: fileName = "+entries.get("fileName"));
logger.info("UPLOAD_CONTENT: type = "+entries.get("type"));
logger.info("UPLOAD_CONTENT: names = "+names);
request.response().setChunked(true).end(createResponse("SUCCESS"));
}
});
// This would be called multiple times
request.uploadHandler(upload -> {
upload.exceptionHandler(new Handler<Throwable>() {
#Override
public void handle(Throwable error) {
logger.error("UPLOAD_CONTENT: Error while uploading content "+upload.filename());
logger.error("UPLOAD_CONTENT: error = "+error.toString());
error.printStackTrace();
request.response().setChunked(true).end(createResponse("FAILURE"));
}
});
upload.endHandler(new Handler<Void>() {
#Override
public void handle(Void aVoid) {
logger.info("UPLOAD_CONTENT: fileName = "+upload.filename());
logger.info("UPLOAD_CONTENT: name = "+upload.name());
logger.info("UPLOAD_CONTENT: contentType = "+upload.contentType());
logger.info("UPLOAD_CONTENT: size = "+upload.size());
UtilityFunctions.uploadToS3(upload.filename(), "testfolder");
}
});
upload.streamToFileSystem(upload.filename());
});

tomcat websocket : cannot connect to tomcat server

I'm trying to use websocket on tomcat 7.0.29, to implement pub/sub system, but somehow I don't know why, it just always alert "close" every time I open the browser..
env is tomcat-7.0.29, Eclipse Juno, written in scala..
much appreciated if anyone can help...
My servlet is below:
[PubServlet]:
class PubServlet extends WebSocketServlet {
override def createWebSocketInbound (subProtocol: String, request: HttpServletRequest): StreamInbound = {
println("create#############################################")
new WebSocketHandler()
}
}
[InitServlet]:
public class InitServlet extends HttpServlet {
private static final long serialVersionUID = -3163557381361759907L;
private static List<MessageInbound> socketList;
public void init(ServletConfig config) throws ServletException {
InitServlet.socketList = new ArrayList<MessageInbound>();
super.init(config);
System.out.println("Server start============");
}
public static synchronized List<MessageInbound> getSocketList() {
return InitServlet.socketList;
}
}
[WebsocketHandler]:
class WebSocketHandler extends MessageInbound{
protected override def onBinaryMessage(arg0: ByteBuffer) {
// TODO Auto-generated method stub
}
protected override def onTextMessage(msg: CharBuffer) {
}
protected override def onClose(status: Int) {
println(status)
super.onClose(status)
}
protected override def onOpen(outbound: WsOutbound) {
super.onOpen(outbound)
InitServlet.getSocketList().add(this)
}
}
and My client code is here:
<%# page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Index</title>
<script type="text/javascript">
var ws = null;
function startWebSocket() {
if ('WebSocket' in window){
ws = new WebSocket("ws://localhost:8080/PubSub_Web/index.do");
alert(ws);
}
else if ('MozWebSocket' in window)
ws = new MozWebSocket("ws://localhost:8080/PubSub_Web/index.do");
else
alert("not support");
ws.onmessage = function(evt) {
alert(evt.data);
};
ws.onclose = function(evt) {
alert("close");
};
ws.onopen = function(evt) {
alert("open");
};
}
function sendMsg() {
ws.send(document.getElementById('writeMsg').value);
}
</script>
</head>
<body onload="startWebSocket();">
<input type="text" id="writeMsg"></input>
<input type="button" value="send" onclick="sendMsg()"></input>
</body>
</html>
See this answer. You are best off using the standard jaxax websocket-api which is available in Tomcat 7.0.47
You need to override getReadTimeout method, which is used to set socket timeout in milliseconds. for example, if you want to set socket timeout 2 minutes (2*60*1000) than you may use below code.
#Override
public int getReadTimeout() {
return 2*60*1000;
}
Note: you can set infinite (always open) by returning -1.

Finding out when a GWT module has loaded

I am exporting a GWT method to native javascript in the following manner:
public class FaceBookGalleryEntryPoint implements EntryPoint {
#Override
public void onModuleLoad() {
FacebookGallery facebookGallery = new FacebookGallery();
RootPanel.get().add(facebookGallery);
initLoadGallery(facebookGallery);
}
private native void initLoadGallery(FacebookGallery pl) /*-{
$wnd.loadGallery = function (galleryId) {
pl.#com.example.fbg.client.FacebookGallery::loadGallery(Ljava/lang/String;)(galleryId);
};
}-*/;
}
In the host page, I am trying to invoke it:
<html>
<head>
<title>Facebook image gallery</title>
<script type="text/javascript"
src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
</head>
<body>
<script type="text/javascript" src="/fbg/fbg.nocache.js"></script>
<h1>Facebook gallery test</h1>
<script type="text/javascript">
$(document).ready(function() {
loadGallery('blargh');
});
</script>
</body>
</html>
Unfortunately, when the document.ready callback is invoked, the function is not yet defined. When manually executed from the Firebug console the function works just fine.
I could perform some polling every 50 milliseconds until I find a defined function by that name, but it seems like a horrible approach.
How can I get notified when the module is loaded and therefore when the function is available?
I would try to define a callback function in the hostpage and call it from GWT at the end of the onModuleLoad() method.
Hostpage function:
<script type="text/javascript">
function onGwtReady() {
loadGallery('blargh');
};
</script>
GWT:
public void onModuleLoad() {
FacebookGallery facebookGallery = new FacebookGallery();
RootPanel.get().add(facebookGallery);
initLoadGallery(facebookGallery);
// Using a deferred command ensures that notifyHostpage() is called after
// GWT initialisation is finished.
Scheduler.get().scheduleDeferred(new Command() {
public void execute() {
notifyHostpage();
}
}
}
private native void notifyHostpage() /*-{
$wnd.onGwtReady();
}-*/;