So I've read all of the other SO questions with regard to this but it looks like everything should be set up properly. I'm running a self-hosted SignalR console application that has a single empty Hub declaration (this is for one-way communication from the server to connected clients).
EDIT: Link to project which reproduces the issue - https://dl.dropboxusercontent.com/u/66477739/SignalRTest.zip
The demo solution has 3 projects:
SignalRTest.BusinessLogic - Simple console app that just publishes a message every 10 seconds. These messages are never received by the client. This simulates my business logic layer pushing notifications to connected clients.
SignalRTest.SelfHost - The self-hosted SignalR application + hub. I added a "Send" method to the hub, only to show that everything works when a client calls server.send('message'); but it doesn't work when the server initiates the message. Typing in this console window and hitting enter will send that text to the web app. THIS WORKS!
SignalRTest.UI - Just a blank MVC app with a single page that loads the necessary scripts. A successfully received message would just log console output, there will never be any UI changes on this sample.
PublishStatusHub.cs
public class PublishStatusHub : Hub
{
}
JS
$(document).ready(function () {
$.connection.hub.url = "http://localhost:8080/signalr";
var publish = $.connection.publishStatusHub;
publish.client.addMessage = function (message) {
console.log(message);
};
$.connection.hub.start().done(function() { });
});
Calling code from a separate assembly
var context = GlobalHost.ConnectionManager.GetHubContext<PublishStatusHub>();
context.Clients.All.addMessage("Starting publish...");
Although I can see that the above code is executed (via breakpoints), the client method is never called.
I did turn on SignalR logging and no exceptions are being thrown. Also, it's never logging the incoming messages.
Interestingly enough, I can get messages sent to the client through my Main() method in Program.cs within the self-hosted console app:
Program.cs
static void Main(string[] args)
{
string url = "http://localhost:8080";
using (WebApp.Start(url))
{
Console.WriteLine("Server running on {0}", url);
while (true)
{
string message = Console.ReadLine();
IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<PublishStatusHub>();
hubContext.Clients.All.addMessage(message);
}
}
}
Now, if I type in the console window and hit enter, the message is sent successfully to the client and it's logged in the console output window.
HOWEVER, if I move this code to another file within the same console application and then call it from another assembly (which is the end goal), it fails silently again:
MessagePublisher.cs
public class MessagePublisher
{
public void Publish(string message)
{
IHubContext hubContext = GlobalHost.ConnectionManager.GetHubContext<PublishStatusHub>();
hubContext.Clients.All.addMessage(message);
}
}
Calling code from a separate assembly
var messagePublisher = new MessagePublisher();
messagePublisher.Publish("Test message");
I'm stuck on why I can't publish messages to connected clients from external assemblies.
In the project you posted, you are trying to publish a message from completely different console application (SignalRTest.BusinessLogic). This application does not host SignalR service, and so has no idea about connected clients. All clients are connected to the service hosted by another application (SinglaRTest.SelfHost) in another process. So there is no way how this could work. If you will start your service in BusinessLogic application, then this will work as usual.
I guess you've created a Constructor, you could remove it...
Related
I am currently working on a windows service application that already consuming SignalR service. My new requirement is to start a desktop application when windows service receives a notification from SignalR.
While I am google on how to start a desktop application using windows service, I found this code base and I am currently using it.
As it explains, when I called the bellow method
ProcessExtensions.StartProcessAsCurrentUser(string path);
in the windows service's OnStart method I was able to start the desktop application.
I also have SignalR client in this windows service (Bellow code).
public class NotificationHub
{
public static void ConsumeNotification()
{
try
{
var hubConnection = new HubConnection(url);
IHubProxy notificationHubHubProxy = hubConnection.CreateHubProxy("WSMassageHub");
hubConnection.Start().Wait();
notificationHubHubProxy.On<WSMessage>("SendMessage", (message) => {
// try to start from here
// but it gives error
ProcessExtensions.StartProcessAsCurrentUser(#"D:\Application\Application.exe");
});
}
catch (Exception ex)
{
logger.Error("Message: " + ex.Message + " | Stack Trace: " + ex.StackTrace);
}
}
}
Then I try to start the desktop application from windows service when windows service gets the message to SignalR client.
protected override async void OnStart(string[] args)
{
NotificationHub.ConsumeNotification();
}
Once SignalR client gets a message, the application failed and error log gets this error message.
StartProcessAsCurrentUser: CreateProcessAsUser failed. Error Code -2
According to System Error Codes, it says that The system cannot find the file specified.
Also, I suspect that this will explain the issue in here. But I don't understand that which component needs to implement to start the desktop application, once SignalR client receives the notification. So, can someone please give me help hand to overcome this issue.
Thanks in advance.
Here is my scenario, I have a windows service that runs a task every 20 minutes, the task is: requesting updates from an API hosted by a remote website.
The response is a list of JSON objects, When the Service receives the list, it carries out a set of operations then appends more JSON objects, finally the service must push the list to a running console application.
My very specific question is: how to transfer this data from the windows service to the console App both directly and professionally
By directly I mean without intermediate solution like writing in a temp file or saving in SQL table ... etc.
By professionally I mean the best optimal solution especially without p/Invoke from the service to the console App.
You would definitely need a medium to communicate between these two processes. The communication can be done in a lot of ways on the same system.
With your explanation in Question it looks like one way communication. May be you can go for Inter-process communication via sockets(raw level) or Use a messaging framework for communication(WCF/SignalR) or you can even use a Message Queue system(MSMQ/RabbitMQ) etc.
You can get a specific answer if you can narrow down your question.
A nice, clean, 'modern' way of doing this, would be to host a Web API directly in the console application, and accept JSON input.
This is relatively easy to set up, and very easy to test and use.
Other methods include .NET remoting (which is not very modern any more), some other kind of service, like WCF, or any of the multitude of windows IPC methods.
I wrote an answer here that has some applicable code. Basically, the OP there wanted to send strings from a Windows Forms application to a console application and have the console application print the strings.
My recommendation is to use a Message Queue.
A few quick notes: first, you may have to enable the feature in Windows if you've never done so. Also, I guess under certain configurations of Windows you can't create the Message Queue directly from C#; if that's the case for you, you can create it manually (or there's probably a way to do it as part of an install script or something).
Here's the Windows Forms code:
private void button1_Click(object sender, EventArgs e)
{
// Or whatever name you end up calling it if you created the queue manually
const string myQueue = ".\\myQueue";
// It's possible that this won't work on certain computers
// If not, you'll have to create the queue manually
// You'll also need to turn the Message Queueing feature on in Windows
// See the following for instructions (for Windows 7 and 8): https://technet.microsoft.com/en-us/library/cc730960(v=ws.11).aspx
if (!MessageQueue.Exists(myQueue))
{
MessageQueue.Create(myQueue);
}
using (MessageQueue queue = new MessageQueue(myQueue))
{
queue.Formatter = new XmlMessageFormatter(new[] { typeof(string) });
queue.Send("Test");
}
}
Console application:
static void Main(string[] args)
{
// Or whatever name you use
const string myQueue = ".\\myQueue";
// See my comment on the corresponding line in the Windows Forms application
if (!MessageQueue.Exists(myQueue))
{
MessageQueue.Create(myQueue);
}
MessageQueue queue = new MessageQueue(myQueue);
queue.Formatter = new XmlMessageFormatter(new[] { typeof(string) });
while (true)
{
Message message = queue.Receive();
string messageText = message.Body.ToString();
// Close if we received a message to do so
if (messageText.Trim().ToLower() == "exit")
{
break;
}
else
{
Console.WriteLine(messageText);
}
}
}
I have a MVC4 app in which I need to init a long running process. Currently, the code for this process is in a console app being installed as a service with topshelf. I have the process checking a database every few seconds to see if it needs to be run, but that's not a solution. I need a way for the MVC4 app to kick off the process and forget about it, but the process NOT be unloaded with the web app when the response is returned to the client.
Can someone point me in the right direction?
If I'm understanding your question, what you can do is, in the service (the class that's derived from ServiceBase), override OnCustomCommand:
private const int MY_CUSTOM_COMMAND = 140;
protected override void OnCustomCommand(int command)
{
if (command == MY_CUSTOM_COMMAND)
{
... Do stuff here ...
}
}
You can then trigger the command in your service, from some external application along these lines:
private const int MY_CUSTOM_COMMAND = 140;
using (ServiceController sc = new ServiceController("MyTaskService", "ServiceMachine"))
{
sc.ExecuteCommand(MY_CUSTOM_COMMAND);
}
That's the basic idea. Custom commands can be any value from 128-256 inclusive.
We use a similar system in our web app, which allows users to submit "jobs" that are then run by a windows service. The web app sends a command to the windows service to let it know a new job has been submitted. The service then goes to the DB to get the information about the job to execute.
We have currently written a MSMQ WCF service hosted in a Windows Service that acts as an email queuing service. The idea is that all of our client applications, which can be accessed by multiple concurrent clients, can submit emails to one centralized reliable queuing system. Once an email is submitted, the service processes the job in the queue (which is a custom email object) and sends it off.
The issue we are encountering is that the portion of the code that actually opens the ServiceHost seems to be sandboxed and prevents our servicing code from writing to the event logs or writing to a custom log file (managed by NLog). The oddity here is that the code also has functionality to move a file on the file system to another location - which works correctly - but as mentioned, cannot write to the event log nor the log file. There is also no exception that appears to be thrown as we have the AppDomain.UnhandledException handler setup.
We have tried changing the Windows Service "run as" account several times from Local Service, to a Domain Admin, to a random user, but nothing seems to work. We are able to prove that before the actual "ServiceHost.Open()" call, we can successfully write to the event logs and the custom log file. It's only inside the actual class that is hosted by the ServiceHost that is having trouble.
I would like to think it's permissions, but as mentioned we can move files around - so it seems contradicting to say the least. The hosted environment is Windows Server 2003 R2 x64, and we are using .NET 4.0.
** As a note, if we remove the registry/custom logging code, and simply have the send email functionality (via a .NET SMTP client object), the emails send out correctly.
Snippet 1 - the WCF service code itself, simply trying to write to the registry, which does not work and apparently doesn't throw an exception:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, IncludeExceptionDetailInFaults = true)]
public class EmailQueueListener : IEmailQueuingService
{
[OperationBehavior(TransactionScopeRequired = false, TransactionAutoComplete = true)]
public void SendEmailToQueue(SerializableMailMessage emailMessage)
{
var eventLogSrc = "Email Service";
var eventLogLogType = "[APP NAME HERE]";
if (!EventLog.SourceExists(eventLogSrc))
EventLog.CreateEventSource(eventLogSrc, eventLogLogType);
EventLog.WriteEntry(eventLogSrc, "TESTING", EventLogEntryType.Information);
Snippet 2 - the code initiating the service host, which is called from the OnStart method of the Windows service:
public static void Start(bool isConsole = false)
{
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
ConsoleLog.Info("TEST");
var eventLogSrc = "Email Service";
var eventLogLogType = "[APP NAME HERE]";
if (!EventLog.SourceExists(eventLogSrc))
EventLog.CreateEventSource(eventLogSrc, eventLogLogType);
EventLog.WriteEntry(eventLogSrc, "Email Service Started", EventLogEntryType.Information);
m_EmailServiceHost = new ServiceHost(typeof(EmailQueueListener));
m_EmailServiceHost.Open();
}
I have a .Net Remoting which work in Console Application but not work in Window Service. Its returns me null type. I don't know whats wrong here
static void TicketServer()
{
System.Diagnostics.Debugger.Break();
//Console.WriteLine("Ticket Server started...");
TcpChannel tcpChannel = new TcpChannel(9988);
ChannelServices.RegisterChannel(tcpChannel, true);
Type commonInterfaceType = Type.GetType("WindowsService.MovieTicket");
RemotingConfiguration.RegisterWellKnownServiceType(commonInterfaceType,
"MovieTicketBooking", WellKnownObjectMode.SingleCall);
}
i get the 'commonInterfaceType' null in Windows service while in Console Application works fine. I have also change the namespace when i shif the application from console to Windows Service
i find the problem but need to know that why this happens in Windows Service, For example in image highlighted line works fine in Console Application, but returns null in Windows service.
http://desmond.imageshack.us/Himg339/scaled.php?server=339&filename=testimg.png&res=landing
If i am not wrong i think this is a bug of Microsoft...
Thank you
Set tcpChannel variable outside the body ofTicketServer() method.
What is happening is that the channel is getting dispossed after the method returns.
In console application, we pause the method with a ReadLine() method of the Console class which allows the channel to continue listening and not to be disposed until a key is pressed but that's different with Windows service.