SqlDependency not working mvc app. Hits once - asp.net-mvc

I am following the blog http://www.venkatbaggu.com/signalr-database-update-notifications-asp-net-mvc-usiing-sql-dependency/ to get a signalR push message out to connected clients.
My debugger never hits the onchange event.
my Global.asax.cs:
string connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
protected void Application_Start()
{
// basic stuff
SqlDependency.Start(connString);
var repo = new Repositories.MarkerRepository();
repo.GetAllMarkers(); // to register the dependency
}
My MarkerRepository.cs:
readonly string _connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;
private MarkersHub _mh = new MarkersHub(); // my signalr hub class
public IEnumerable<House> GetAllMarkers()
{
var markers = new List<House>();
using (var connection = new SqlConnection(_connString))
{
connection.Open();
using (var command = new SqlCommand(#"SELECT * FROM [dbo].Houses", connection))
{
command.Notification = null;
var dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
if (connection.State == ConnectionState.Closed)
connection.Open();
var reader = command.ExecuteReader();
while (reader.Read())
{
markers.Add(item: new House {
ID = (int)reader["ID"],
Name = (string)reader["Name"],
Code = reader["Code"] != DBNull.Value ? (string)reader["Code"] : "",
Latitude = Convert.ToDouble(reader["Latitude"]),
Longitude = Convert.ToDouble(reader["Longitude"])
});
}
}
}
return markers;
}
private void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
_mh.SendMarkers();
}
}
I have had a hit once but it was no change, only a notification for subscribe. I have read a lot about resubscribe, but when it hit this event the sql:
select * from sys.dm_qn_subscriptions
still returns no rows. Not on my db or master. So I think that there is an error in the blog post with the re-subscribe to the on change event? This sample https://msdn.microsoft.com/en-us/library/a52dhwx7(VS.80).aspx does unregister in the onchange event and calls the method which registers a new event. Can someone verify my assumption?

These were the values for the SqlNotificationEventArgs e in my event and told me that my query to depend on, was invalid.
SqlNotificationEventArgs.Type --> SqlNotificationType.Subscribe
SqlNotificationEventArgs.Info --> SqlNotificationInfo.Invalid
SqlNotificationEventArgs.Source --> SqlNotificationSource.Statement
The statement may not use the asterisk () or table_name. syntax to specify columns.
source https://msdn.microsoft.com/en-us/library/ms181122.aspx

Related

Signalr .Net Client Console application receive messages from hub only once

I'm using Signalr .Net Client in my Console application to receive messages from the Signalr Hub which is a separate web application.
My console application is connecting to the hub correctly and receive message from the hub only once. Then the client method in the Signalr .Net client not getting called.
Once I stop the console application and run it, again it receive a message from the hub only once and nothing happens.
Here is my Hub Code
public override Task OnConnected()
{
try
{
var cType = Context.QueryString["type"];
var connectionId = Context.ConnectionId;
var connectedUserList = (from d in Users
where d.ClientType == cType
select d).ToList();
if (connectedUserList.Count > 0)
{
var conUser = connectedUserList.First<ConnectedUsers>();
conUser.ConnectionIds.Add(connectionId);
}
else
{
var newUser = new ConnectedUsers
{
ConnectionIds = new HashSet<string> {connectionId}
,
ClientType = cType
};
Users.Add(newUser);
}
}
catch (Exception ex)
{
).Error(ex);
}
return base.OnConnected();
}
And My .Net Client Connection
static void Main(string[] args)
{
SignalrHandler();
Console.ReadLine();
}
public static async void SignalrHandler()
{
var url = ConfigurationSettings.AppSettings["Url"] ?? #"http://localhost:1010/";
var querystringData = new Dictionary<string, string> { { "type", "WIN" } };
_hubConnection = new HubConnection(url, querystringData);
MarcolinMainProxy = _hubConnection.CreateHubProxy("MainHub");
MarcolinMainProxy.On<string>("sendAlert", type => InvokeMethod(type));
await _hubConnection.Start();
}
Client Method
private static void InvokeMethod(string type)
{
Console.WriteLine(String.Format("Recieved Message From Server On :{0}",System.DateTime.Now.ToString()));
Console.WriteLine("Message Received");
Console.ReadLine();
}
And This happens when I use an Invoke method with following line
MarcolinMainProxy.On<string>("sendAlert", type => InvokeMethod(type));
And when I use following line it works..
MarcolinMainProxy.On<string>("sendAlert", stock => Console.WriteLine("Symbol {0} Price {1}", "sd", "sdde"));
Check the following link
https://damienbod.com/2013/11/13/signalr-messaging-a-complete-client-with-a-console-application/
You have to change your code to
MarcolinMainProxy.On<string>("sendAlert", InvokeMethod);

Using Postal and Hangfire in Subsite

I have been trying to use Postal on my MVC5 site. When I host my webpage a subsite ie, http://localhost/Subsite I am receiving the error
The virtual path '/' maps to another application, which is not allowed
I have debugged it down to when the ControllerContext is being created the HttpContext isn't getting set correctly. Since I'm running Postal from Hangfire the HttpContext.Current is always null. Postal creates the ContollerContext using the code below.
ControllerContext CreateControllerContext()
{
// A dummy HttpContextBase that is enough to allow the view to be rendered.
var httpContext = new HttpContextWrapper(
new HttpContext(
new HttpRequest("", UrlRoot(), ""),
new HttpResponse(TextWriter.Null)
)
);
var routeData = new RouteData();
routeData.Values["controller"] = EmailViewDirectoryName;
var requestContext = new RequestContext(httpContext, routeData);
var stubController = new StubController();
var controllerContext = new ControllerContext(requestContext, stubController);
stubController.ControllerContext = controllerContext;
return controllerContext;
}
string UrlRoot()
{
var httpContext = HttpContext.Current;
if (httpContext == null)
{
return "http://localhost";
}
return httpContext.Request.Url.GetLeftPart(UriPartial.Authority) +
httpContext.Request.ApplicationPath;
}
How can I specify the UrlRoot so that instead of pulling the default of localhost to pull it based on my subsite?
I followed the directions here http://docs.hangfire.io/en/latest/tutorials/send-email.html to send my email. The method in the tutorial is below
public static void NotifyNewComment(int commentId)
{
// Prepare Postal classes to work outside of ASP.NET request
var viewsPath = Path.GetFullPath(HostingEnvironment.MapPath(#"~/Views/Emails"));
var engines = new ViewEngineCollection();
engines.Add(new FileSystemRazorViewEngine(viewsPath));
var emailService = new EmailService(engines);
// Get comment and send a notification.
using (var db = new MailerDbContext())
{
var comment = db.Comments.Find(commentId);
var email = new NewCommentEmail
{
To = "yourmail#example.com",
UserName = comment.UserName,
Comment = comment.Text
};
emailService.Send(email);
}
}
I found the issue was that the FileSystemRazorViewEngine was not being used bty postal. To get the this to work I had to make sure that the FileSystemRazorViewEngine was the first engine in the available. I then removed it because I did not want it to be the default engine. Below is my updated method.
public static void NotifyNewComment(int commentId)
{
// Prepare Postal classes to work outside of ASP.NET request
var viewsPath = Path.GetFullPath(HostingEnvironment.MapPath(#"~/Views/Emails"));
var eng = new FileSystemRazorViewEngine(viewsPath));
ViewEngines.Engines.Insert(0, eng);
var emailService = new EmailService(engines);
// Get comment and send a notification.
using (var db = new MailerDbContext())
{
var comment = db.Comments.Find(commentId);
var email = new NewCommentEmail
{
To = "yourmail#example.com",
UserName = comment.UserName,
Comment = comment.Text
};
emailService.Send(email);
ViewEngines.Engines.RemoveAt(0)
}
}
Below is another possible solution that I think is more elegant than above. It also resolves an issue that appears when accessing the MVC application while the background process is being executed.
public static void SendTypedEmailBackground()
{
try
{
var engines = new ViewEngineCollection();
var viewsPath = Path.GetFullPath(HostingEnvironment.MapPath(#"~/Views/Emails"));
var eng = new FileSystemRazorViewEngine(viewsPath);
engines.Add(eng);
var email = new WebApplication1.Controllers.EmailController.TypedEmail();
email.Date = DateTime.UtcNow.ToString();
IEmailService service = new Postal.EmailService(engines);
service.Send(email);
}
catch(Exception ex)
{
throw ex;
}
}

JavaFX WebView cookie

How do I get the cookie set by a connection to a webpage from JavaFX WebView. I want to use this cookie in order to open a seperate connection to the website after the originaol login.
Is there a way to do this and how?
Thank you for your time
I have a local "login.html" that does an AJAX call to my server to log in.
JavaFX application code:
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Battleround client");
URL loginPageUrl = Main.class.getResource("/pages/login.html");
final WebView webview = new WebView();
final WebEngine webEngine = webview.getEngine();
webEngine.setJavaScriptEnabled(true);
webEngine.load(loginPageUrl.toString());
/*
* Alright, this piece of code might be hard to understand. Basically
* we're adding a JavaScript object that's actually a Java object. So we
* can call Java methods from JavaScript. And we're adding this
* javascript object as soon as the page has been fully loaded.
*/
webEngine.getLoadWorker().stateProperty().addListener(new ChangeListener<Worker.State>() {
#Override
public void changed(ObservableValue<? extends State> ov, State t, State t1) {
if (t1 == Worker.State.SUCCEEDED) {
JSObject window = (JSObject) webEngine.executeScript("window");
window.setMember("java", new AuthenticationApplication());
}
}
});
StackPane root = new StackPane();
root.getChildren().add(webview);
primaryStage.setScene(new Scene(root, 400, 500));
primaryStage.show();
}
public class AuthenticationApplication {
public void start(String JSESSIONID) {
// From here on I start my game with the JSESSIONID from the login call.
}
}
My JavaScript code in the login.html:
function login(username, password) {
var xmlHttp = new XMLHttpRequest();
if (window.ActiveXObject) {
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
var url = "http://192.168.2.7:8888/Login";
var params = "username=" + userName + "&password=" + password;
xmlHttp.open("POST", url, true);
// Send the proper header information along with the request
xmlHttp.setRequestHeader("Content-type",
"application/x-www-form-urlencoded");
xmlHttp.setRequestHeader("Content-length", params.length);
xmlHttp.setRequestHeader("Connection", "close");
xmlHttp.withCredentials = "true";
xmlHttp.onreadystatechange = function() {// Call a function when the state changes.
if (xmlHttp.readyState == 4 && xmlHttp.status == 200) {
if(xmlHttp.responseText == "login.successful") {
document.getElementById("loginForm").innerHTML = getResources("login.successful");
var setCookieHeader = xmlHttp.getResponseHeader('Set-Cookie');
java.start(setCookieHeader.split(";")[0].split("=")[1]); // Obtain the JSESSIONID, and send it to the java code. Warning: this code will mess up if there's other cookies.
} else {
document.getElementById("validationMessage").innerHTML = getResources(xmlHttp.responseText);
}
}
};
xmlHttp.send(params);
}
function getResources(key) {
var resources = {};
resources["login.already.logged.in"] = "You are already logged in! Log out first if you want to try again.";
resources["login.error"] = "The login failed because an error occurred, Sorry!";
resources["login.failed"] = "User name and password do not match.";
resources["login.successful"] = "Login succeeded.";
return resources[key];
}

Handling a domain event in an asp.net mvc controller

I'm looking into using Domain Events to bubble information from operations occuring deep inside of my domain model in order to signal certain events at the controller level. Unfortunately, I haven't been able to find an example of how to properly wire this on an asp.net mvc controller.
In short, this is what I'm looking for inside of my action:
service.doSomethingComplicated();
var model = new ViewModel();
model.somethingComplicatedCausedSomethingElse = <true-if-my-domain-event-was-raised>;
return View(model);
Can anyone offer me some guidance?
Update
Just to be clear, I understand how I would raise and handle the domain event in the controller; I'm just looking for an implementation of registering for the event that will be safe to use in the context I've described.
Based on the example you linked to, where the author does this:
Customer preferred = null;
DomainEvents.Register<CustomerBecamePreferred>(
p => preferred = p.Customer
);
c.DoSomething();
You should be able to do this:
var model = new ViewModel();
// Register a handler that sets your bool to true if / when the event is raised
DomainEvents.Register<YourDomainEvent>(e => model.somethingComplicatedCausedSomethingElse = true);
// EDIT: If using the singleUseActions modification, pass the second parameter
// DomainEvents.Register<YourDomainEvent>(e => model.somethingComplicatedCausedSomethingElse = true, true);
// Call the service. If it raises the event, the handler you just registered will set your bool
service.doSomethingComplicated();
return View(model);
Edit (DomainEvents modification)
This is untested and written in the StackOverflow edit box, but it's where I'd start. I'm using an optional parameter so that existing calls need not be modified, and a separate list "singleUseActions" to leave the existing guts as untouched as possible. Hope it helps.
public static class DomainEvents
{
[ThreadStatic] //so that each thread has its own callbacks
private static List<Delegate> actions;
[ThreadStatic] //so that each thread has its own callbacks
private static List<Delegate> singleUseActions;
public static IContainer Container { get; set; } //as before
//Registers a callback for the given domain event
public static void Register<T>(Action<T> callback, bool isSingleUse = false) where T : IDomainEvent
{
List<Delegate> targetList;
if (isSingleUse)
{
if (singleUseActions == null) singleUseActions = new List<Delegate>();
targetList = singleUseActions;
}
else
{
if (actions == null) actions = new List<Delegate>();
targetList = actions;
}
targetList.Add(callback);
}
//Clears callbacks passed to Register on the current thread
public static void ClearCallbacks ()
{
actions = null;
singleUseActions = null;
}
//Raises the given domain event
public static void Raise<T>(T args) where T : IDomainEvent
{
if (Container != null)
foreach(var handler in Container.ResolveAll<Handles<T>>())
handler.Handle(args);
if (actions != null)
foreach (var action in actions)
if (action is Action<T>)
((Action<T>)action)(args);
if (singleUseActions != null)
// Don't foreach because we are going to modify the collection
for (int index = singleUseActions.Count - 1; index > -1; index--)
{
var singleUseAction = singleUseActions[index];
if (singleUseAction is Action<T>)
{
((Action<T>)singleUseAction)(args);
singleUseActions.RemoveAt(index);
}
}
}
}

Windows Application SqlDepedency Calling Onchange infinitely

I have console application in which I am doing sqldependency. My problem is when I set commandType as Text, it is working fine. But if I use commandType as StoredProcedure, onchange method is calling infinitely.
Please see the code below:
static DataSet myDataSet;
static SqlConnection connection;
static SqlCommand command;
static void Main(string[] args)
{
// Remove any existing dependency connection, then create a new one.
string connstr = "Data Source=XYZ;Initial Catalog=Dev;Integrated Security=True";
string ssql = #"[dbo].[SchedulerPendingControlRequestIDFetch]";
CanRequestNotifications();
SqlDependency.Stop(connstr);
SqlDependency.Start(connstr);
if (connection == null)
connection = new SqlConnection(connstr);
if (command == null)
command = new SqlCommand(ssql, connection);
command.CommandType = CommandType.StoredProcedure;
if (myDataSet == null)
myDataSet = new DataSet();
GetAdvtData();
System.Console.ReadKey();
connection.Close();
}
private static bool CanRequestNotifications()
{
SqlClientPermission permission =
new SqlClientPermission(
PermissionState.Unrestricted);
try
{
permission.Demand();
return true;
}
catch (System.Exception)
{
return false;
}
}
private static void GetAdvtData()
{
myDataSet.Clear();
// Ensure the command object does not have a notification object.
command.Notification = null;
// Create and bind the SqlDependency object to the command object.
SqlDependency dependency = new SqlDependency(command,null,100);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
using (SqlDataAdapter adapter = new SqlDataAdapter(command))
{
adapter.Fill(myDataSet, "ControlRequest");
}
}
private static void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency dependency =
(SqlDependency)sender;
dependency.OnChange -= dependency_OnChange;
Console.WriteLine(e.Info.ToString() + e.Source.ToString());
GetAdvtData();
}
My stored Procedure is:
IF OBJECT_ID('SchedulerSirasColcoDetailFetch') IS NOT NULL
DROP PROCEDURE SchedulerSirasColcoDetailFetch
Go
PRINT 'Creating stored procedure SchedulerSirasColcoDetailFetch'
Go
CREATE PROCEDURE [dbo].[SchedulerSirasColcoDetailFetch]
AS
BEGIN
SELECT Colco_Code AS 'CountryCode',Connection_String AS 'Url',Resend_Interval AS 'ResendInterval',
Default_Encoding AS 'Encoding' FROM dbo.SirasColcoDetail
END
If I copy the select statement inside stored procedure as my command text and set the commandType as Text, everything is working fine.
could you please let me know what the issue is????
Thanks a lot in advance.
Mahesh
You're supposed to check the values of the SqlNotificationEventArgs argument. Only if Type is Change and Source is Data where you notified for a data change.
You'll discover that you're not notified for data changes, but for incorrect settings or incorrect query. Your query and connection settings must comply with the requirements specified in Creating a Query for Notifications.

Resources