Any suggestion with my signalr codes?It is not working - c#

I'm encountering now a serious problem about my signalr application.
What do you think that is lack to my code or any suggestion about signalr. I am new to signalr so can't really tell if it is correct.
I hope any suggestion or comment about my codes. Please anyone can review it.
All I want is when the database is changed my application will automatically change without refreshing the browser.
I also followed this limitation about Broker in SQL server
https://msdn.microsoft.com/en-us/library/ms181122.aspx
I also enable my database broker.
Hub
[HubName("iTestHub")]
public class iTestHub : Hub
{
public void Hello()
{
Clients.All.hello();
}
public static void Show()
{
IHubContext context = GlobalHost.ConnectionManager.GetHubContext<iTestHub>();
context.Clients.All.displayStatus();
}
}
AngularJS Controller
var iTest = $.connection.iTestHub;
// Declare a function on the job hub so the server can invoke it
iTest.client.displayStatus = function () {
getData();
};
// Start the connection
$.connection.hub.start();
getData();
function getData() {
StudentExamService.GetStudentExam(studId + '|' + yearCode).then(function(results) {
$scope.studentExams = results.data;
});
}
Web API starup
public void Configuration(IAppBuilder app)
{
ConfigureApp(app);
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);
app.MapSignalR();
app.UseWebApi(config);
}
Globa.asax
protected void Application_Start(object sender, EventArgs e)
{
SqlDependency.Start(ConfigurationManager.ConnectionStrings["CentralizedStudentInformationConnectionString"].ConnectionString);
SqlDependency.Start(ConfigurationManager.ConnectionStrings["Aptus-TestConnection"].ConnectionString);
}
protected void Application_End(object sender, EventArgs e)
{
SqlDependency.Stop(ConfigurationManager.ConnectionStrings["CentralizedStudentInformationConnectionString"].ConnectionString);
SqlDependency.Stop(ConfigurationManager.ConnectionStrings["Aptus-TestConnection"].ConnectionString);
}

You should invoke getData() function, after start() method is done:
$.connection.hub.start().done(function(){
getData();
});
Now, you will invoke get data after connection is established.

Related

Remove RoleInstance from data sent to Azure Application Insights from WPF

I'm trying to add Application Insights to a WPF app using this documentation: https://learn.microsoft.com/en-us/azure/azure-monitor/app/windows-desktop. The basic integration is working. I am now trying to remove the RoleInstance property from the submitted data, as described in the documentation, as this contains the user's computer name (personally identifiable information). Here's my code, based on the documentation above:
Telemetry.cs
public static class Telemetry
{
public static TelemetryClient Client;
public static void Close()
{
if (Client != null)
{
Client.Flush();
System.Threading.Thread.Sleep(1000);
}
}
public static void Initialize()
{
TelemetryConfiguration.Active.InstrumentationKey = "xxxxxxxx";
TelemetryConfiguration.Active.TelemetryInitializers.Add(new MyTelemetryInitializer());
Client = new TelemetryClient(TelemetryConfiguration.Active);
Client.Context.Session.Id = Guid.NewGuid().ToString();
Client.Context.Device.OperatingSystem = Environment.OSVersion.ToString();
}
private class MyTelemetryInitializer : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
if (string.IsNullOrEmpty(telemetry.Context.Cloud.RoleName))
{
telemetry.Context.Cloud.RoleInstance = null;
}
}
}
}
App.xaml.cs
public partial class App : Application
{
protected override void OnExit(ExitEventArgs e)
{
Telemetry.Close();
base.OnExit(e);
}
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
Telemetry.Initialize();
}
}
When I call Telemetry.Client.TrackEvent(), Telemetry.Initialize() runs, and RoleInstance is null from the start. But, the data sent to AI contains my computer name as the RoleInstance. Not sure how to debug further.
Note: the documentation describes integration into WinForms, and I'm in WPF, so I've guessed at using App.OnStartup instead of Main.
I just found something interesting, if you set a dummy value for RoleInstance, it really takes effect. Maybe the null/empty value will be checked and replaced by the real RoleInstance in the backend. As a workaround, you can just specify a dummy value instead of null/empty value.
Here is my test result with a dummy value:
in azure portal:

How to report file progress to clients using SignalR?

I have written a component that gets and excel file and stores its data into a database. Since I wanted this class to support different environments (for example using it inside a console app) So I decided to create some events:
public interface IDataSeeder
{
Task Seed(string fileName);
event EventHandler<UserSucceedEventArgs> UserAdded;
event EventHandler<UserErrorEventArgs> Error;
event EventHandler<UserUpdateEventArgs> UserUpdated;
event EventHandler<FinishDataSeederEventArgs> ProcessCompleted;
}
Each of this events will trigger in different places inside Seed method. It works like a charm in my console application.
Now I want to use this component inside my ASP.NET MVC app, for doing so I decided to use SignalR for pushing event's data to client, So I created a hub like this:
public class ProgressHub : Hub
{
public static void UserAdded(UserSucceedEventArgs e)
{
var ctx = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
ctx.Clients.All.userAdded(e);
}
public static void Error(UserErrorEventArgs e)
{
var ctx = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
ctx.Clients.All.error(e);
}
public static void UserUpdated(UserUpdateEventArgs e)
{
var ctx = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
ctx.Clients.All.userUpdated(e);
}
public static void ProcessCompleted(FinishDataSeederEventArgs e)
{
var ctx = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
ctx.Clients.All.processCompleted(e);
}
}
Then I created this action method for getting uploaded file and pass it to my component:
[HttpPost]
public async Task<ActionResult> AddFromExcel(HttpPostedFileBase excelFile)
{
if (excelFile != null)
{
var fileName = Utilities.UploadFile.UploadFile.UploadCommonFile(excelFile, "users");
_dataSeeder.UserAdded += DataSeeder_Succeed;
_dataSeeder.Error += DataSeeder_Error;
_dataSeeder.UserUpdated += DataSeeder_Update;
_dataSeeder.ProcessCompleted += DataSeeder_Finish;
await _dataSeeder.Seed(Server.MapPath($"~/Content/Files/users/{fileName}"));
return RedirectToAction("AddFromExcel");
}
return RedirectToAction("List");
}
private static void DataSeeder_Finish(object sender, FinishDataSeederEventArgs e)
{
ProgressHub.ProcessCompleted(e);
}
private static void DataSeeder_Update(object sender, UserUpdateEventArgs e)
{
ProgressHub.UserUpdated(e);
}
private static void DataSeeder_Error(object sender, UserErrorEventArgs e)
{
ProgressHub.Error(e);
}
private static void DataSeeder_Succeed(object sender, UserSucceedEventArgs e)
{
ProgressHub.UserAdded(e);
}
As you can see inside each event handler I notify the clients using my signalr hub.
All of this process is like a messaging system, but I have no idea how to implement it inside a web application. A flaw with my code is that after attaching the event handler I immediately redirect the user to another action method, I know it must be an asynchronous process but I have no idea how to make my events async.
Any idea?
What you have to do is match the SignalR server calls with JavaScript functions that will show the results to the connected clients:
<script type="text/javascript">
// the proxy to your hub
var hub = $.connection.ProgressHub;
// the function that will be called when you call
// ctx.Clients.All.userAdded(e);
hub.client.userAdded = function (data) {
// show the data
alert(data);
};
// follow suit with the rest of the functions
hub.client.error = function (data) {
alert(data);
};
// etc
</script>

My asp.net mvc 4 application does not send/publish to rabbitmq

I have an application, an asp.net mvc 4 application. I want to use rabbitmq with easynetq. In my local computer, it works perfectly. But in the production environment which is windows server 2012, it does not send any message.
I could not understand, why it does not work. In log message, nothing unusual. IIS and rabbitmq is in the same machine.
protected void Application_Start()
{
...
using (var bus = RabbitHutch.CreateBus("host=localhost"))
{
bus.Publish(new SystemLog() { Code = "startapplication", Message = "nomessage" });
}
...
}
void Session_End(object sender, EventArgs e)
{
...
using (var bus = RabbitHutch.CreateBus("host=localhost"))
{
bus.Publish(new SystemLog() { Code = "sessionends", Message = "somenumber"});
};
...
}
Thanks in advance
Don't put it in a using statement, that will dispose the bus instance immediately when startup is complete, you want to keep the same instance during the life time of your application.
Instead save the instance somewhere (like a static variable), and dispose it in the application_end event, not session_end.
So more like this:
protected void Application_Start()
{
_bus = RabbitHutch.CreateBus("host=localhost"))
_bus.Publish(new SystemLog() { Code = "startapplication", Message = "nomessage" });
}
void Session_End(object sender, EventArgs e)
{
_bus.Publish(new SystemLog() { Code = "sessionends", Message = "somenumber"});
}
protected void Application_End()
{
if(_bus!=null)
_bus.Dispose();
}

Handling Server-side RtmpConnection.Invoke() when connecting with NetConnection as a client using FluorineFx

I am trying to create a basic console app in order to stress test our FluorineFx based flash remoting server.
I can connect fine but the server method I am calling invokes this client-side function:
connection.Invoke("onServerDataPush", new string[] { "someParam", "anotherParam" });
I am struggling to find out how I can expose this method to the connection. The NetConnection.Call() method allow you to pass in a callback but the result of this is always null and the NetConnection call fails with the following error:
Could not find a suitable method with name onServerDataPush
Here is my client-side code:
class Program
{
private NetConnection _netConnection;
static void Main(string[] args)
{
var program = new Program();
program.Connect();
Console.ReadLine();
}
public void Connect()
{
_netConnection = new NetConnection();
_netConnection.ObjectEncoding = ObjectEncoding.AMF3;
_netConnection.OnConnect += netConnection_OnConnect;
_netConnection.NetStatus += netConnection_NetStatus;
_netConnection.Connect("rtmp://localhost:1935/MyApplication");
}
void netConnection_OnConnect(object sender, EventArgs e)
{
var responder = new Responder<object>(x =>
{
var test = x;
});
//The NetConnection object is connected now
_netConnection.Call("MyServerMethod", responder, "someParameter");
}
void netConnection_NetStatus(object sender, NetStatusEventArgs e)
{
string level = e.Info["level"] as string;
}
}
Debugging through RtmpClient line 308 finally allowed me to solve this.
You must set the NetConnection.Client property to the class that contains a method of the same signature as the one being invoked by the server (in my case this as the method is in the Program class).
public void onServerDataPush(string type, string json)
{
}
FluorineFx then calls the method using reflection.

WCF, executing Events?

While continuing to learn WCF, I'm trying to make it work with events.
In this example, upon a button click in a form, I want my wcf service to execute and event that would be trigger something in other form that are connected to this service.
That's the code for the Form1.
public Form1()
{
InitializeComponent();
client.TimeShowEvent += new EventHandler(TimeShowEvent);
///// SAYS THAT IT DOES NOT CONTAIN A DEFINITION FOR TimeShowEvent
}
MyWcfService1.IfaceServiceClient client = new MyWcfService1.IfaceServiceClient();
private void button2_Click(object sender, EventArgs e)
{
try
{
MyWcfService1.IfaceServiceClient client = new MyWcfService1.IfaceServiceClient();
client.passTime();
}
catch
{
MessageBox.Show("Service not availabe!");
}
}
void TimeShowEvent(object sender, EventArgs e)
{
textBox2.Text = client.timestring;
//// SAYS THAT IT DOES NOT CONTAIN A DEFINITION FOR timestring
}
and for the service:
namespace wcfLib
{
[ServiceContract]
public interface IfaceService
{
[OperationContract]
int wordLen(string word);
[OperationContract]
string passTime();
///// DO I NEED TO SOMEHOW DECLARE THE VARIABLES ( timestring ) AND EVENTS ( TimeShowEvent ) HERE?
}
}
Service implementation:
public class StockService : IfaceService
{
public event EventHandler TimeShowEvent;
public string timestring = "none";
public string passTime()
{
TimeShowEvent(this, new EventArgs());
timestring = DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss");
return "";
}
public int wordLen(string word)
{
return word.Length;
}
}
Service host app:
public class Service
{
static void Main()
{
ServiceHost serviceHost = new ServiceHost(typeof(StockService), new Uri("http://localhost:8000/wcfLib"));
serviceHost.AddServiceEndpoint(typeof(IfaceService), new BasicHttpBinding(), "");
serviceHost.Open();
Console.WriteLine("Press return to terminate the service");
Console.ReadLine();
serviceHost.Close();
}
}
Do I need to somehow declare events and variables in [ServiceContract]? Is so, how?...
Thanks! :)
When you create a service reference to your service, your client gets access to the service methods - and only to the service methods.
The event handler TimeShowEvent in your service implementation class will be present and usable on the server-side only - it will not be available on the client side.
If you want to have something to call, you need to define another service method - those are "mirrored" in the client-side proxy class - and only those.
The only connection your client-side proxy and your server share are the service methods defined in your service contract, and the data that gets passed for those methods - as serialized (XML) messages. There's no "magic link" between client and server - the client can't "reach into" the server class and read stuff from there or call events on that class. There is no "remote object" connection between the two.
Try something like this:
string timeString;
private void button2_Click(object sender, EventArgs e)
{
try
{
//You already declared client, so you don't need to do it again.
//Assign the value from your wcf call to a local variable
timeString = client.passTime();
}
catch
{
MessageBox.Show("Service not availabe!");
}
}
and modify the service to return a string:
public string passTime()
{
TimeShowEvent(this, new EventArgs());
return DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss");
}
and your event:
void TimeShowEvent(object sender, EventArgs e)
{
textBox2.Text = timeString; //this is your local variable
}
And your event handler needs to be in the client. The wcf service will not know anything about the event that called it or used its result.

Categories