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();
}
Related
I'm using socketIO on node and hook it up with the front-end, they work fine
Now I want to push things further
I want my .net clients (UWP) communicate with the socketIO
But there is something really weird happening
At first I tested and it run just fine, the second time I run the client
It started to send twice or more messages when I only send one. And I realize that if I open the .net client first and the server later this won't happen, but when I shut my clients down (while the server still running) this bug started to happen.
public sealed partial class StuffDetail : Page
{
Socket socket = IO.Socket("ws://localhost:8888");
ObservableCollection<SocketMessage> InCommingData { get; set; } = new ObservableCollection<SocketMessage>();
public StuffDetail()
{
this.InitializeComponent();
DisconnectState();
SetSocket();
ChatWindow.ItemsSource = InCommingData;
}
private void DisconnectState()
{
ReceivedText.Text = "Not Connect";
}
private void SetSocket()
{
socket.Connect();
ReceivedText.Text = "Connect Completed";
socket.On("chat", async (data) =>
{
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
{
var IncomeMess = JsonConvert.DeserializeObject<SocketMessage>(data.ToString());
InCommingData.Add(IncomeMess);
});
});
}
private void Send(object sender, RoutedEventArgs e)
{
var message = new SocketMessage()
{
message = MessTextBox.Text,
handle = "From Beta User"
};
socket.Emit("chat", JsonConvert.SerializeObject(message));
}
}
I have created my own MSMQ wrapper class like this:
public class MsgQueue
{
private MessageQueue messageQueue;
public delegate void ReadMessageDelegate(string message);
public event ReadMessageDelegate NewMessageAvailable;
public MsgQueue(string queueName)
{
var queuePath = #".\Private$\" + queueName;
if (!MessageQueue.Exists(queuePath)) MessageQueue.Create(queuePath);
messageQueue = new MessageQueue(queuePath);
messageQueue.Label = queueName;
messageQueue.Formatter = new XmlMessageFormatter(new Type[] { typeof(string)});
messageQueue.ReceiveCompleted += new ReceiveCompletedEventHandler(MsgReceivedHandler);
messageQueue.BeginReceive();
}
private void MsgReceivedHandler(object sender, ReceiveCompletedEventArgs e)
{
try
{
MessageQueue mq = (MessageQueue)sender;
var message = mq.EndReceive(e.AsyncResult);
NewMessageAvailable(message.Body.ToString());
mq.BeginReceive();
}
catch (MessageQueueException)
{
// Handle sources of MessageQueueException.
}
return;
}
public void SendMessage(string message)
{
messageQueue.Send(message);
}
}
I tested it on two separate WinForms applications.
First app sends a text message when button is clicked:
private void btn_Click(object sender, EventArgs e)
{
var queue = new MsgQueue.MsgQueue("GBMqueue");
queue.SendMessage("some message text");
}
Second app is listening for any incoming messages and then tries to process it:
// declaration
private MsgQueue queue;
// preparation of the queue
private void Form1_Load(object sender, EventArgs e)
{
queue = new MsgQueue.MsgQueue("GBMqueue");
queue.NewMessageAvailable += Queue_NewMessageAvailable;
}
// Handler for the incoming messages
private void Queue_NewMessageAvailable(string message)
{
// Hits here very rarely!!!
}
The problem is that I can send the message from App1 several times, but the Queue_NewMessageAvailable handler catches only one random message, not the first one - just one of those which were sent.
No exception is thrown, it just does not catch the incoming messages.
What am I doing wrong here?
I think the first App should not listen for new messages. It's possible that it takes away the messages for the second App. It should only send messages.
When you split the functionality it should work.
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>
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.
We are developing an ASP.NET MVC web application that is dependent on another system for some of it's data. (The merits of this choice are outside the scope of this question)
When our web application starts up we need it to check the status of the other system. We do this by logging in to it using a HTTPCLient request.
If the system does not respond or the credentials are incorrect, then our system should not start either, and redirect the user to an Error page. If the login is successful, we grab a load of data from it, and put it into our local cache.
The problem i'm having is that the user is not directed to the error page, the are directed to our application login page instead.
Here's my Global ASAX.
private bool _externalSystemAvailable;
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
GlobalConfiguration.Configure(WebApiConfig.Register);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AutomapperConfiguration.Configure();
_externalSystemAvailable = ExternalSystem.Login();
}
protected void Application_BeginRequest(object source, EventArgs e)
{
var app = (HttpApplication) source;
var ctx = app.Context;
FirstRequestInitialisation.Initialise(ctx, _externalSystemAvailable);
}
I have another class based on this that checks whether the application is initialised already and performs the necessary post initialisation routines. I have this class so that the check is not performed on every request.
public class FirstRequestInitialisation
{
private static bool _alreadyInitialized = false;
private static object _lock = new object();
public static void Initialise(HttpContext context, bool _xternalSystemAvailable)
{
if (_alreadyInitialized)
{
return;
}
lock (_lock)
{
if (_alreadyInitialized)
{
return;
}
}
if ( !externalSystemAvailable)
{
HttpContext.Current.RewritePath("/Home/Error");
}
_alreadyInitialized = true;
}
}
the HttpContext.Current.RewritePath("/Home/Error");is being hit, but the user is not being redirected.
You can redirect user in Application_BeginRequest
protected void Application_BeginRequest(object source, EventArgs e)
{
if (!externalSystemAvailable)
{
Response.Redirect("/Home/Error", false);
Response.StatusCode = 301;
}
}
But there is problem with above code and that is by calling Response.Redirect you create new page request which means that event fires again and again and again and it fall into infinite loop.
I think better place for doing that is Session_Start:
protected void Session_Start(object source, EventArgs e)
{
if (Session.IsNewSession && !externalSystemAvailable)
{
Response.Redirect("/Home/Error", false);
Response.StatusCode = 301;
}
}
Stupid mistake on my part. The Home Controller was restricted to authenticated users.