Windows Application SqlDepedency Calling Onchange infinitely - stored-procedures

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.

Related

SqlDependency not working mvc app. Hits once

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

Database not persisted between builds with xamarin ios

I'm creating a simple sqlite driven app for ios using xamarin studio on a mac.
The sqlite file is created in the "personal" folder and is persisted between builds but when i run the app the tables i created in the previous debug session is gone?
In my code, after checking that the file exists, i connect using a sqliteconnection and create a table and insert a row with the executenonquery method from the command object. While in the same context i can query the table using a second command object but if i stop the debugger and restart the table i gone?
Should i have the file in a different folder, is it a setting in xamarin or ios to keep the tables? Am i unintentionally using temp tables in sqlite or what could be the problem?
Note: so far i'm only using starter version of xamarin and debugging on iphone simulator.
public class BaseHandler
{
private static bool DbIsUpToDate { get; set; }
const int DB_VERSION = 1; //Created DB
const string DB_NAME = "mydb.db3";
protected const string CNN_STRING = "Data Source=" + DB_NAME + ";Version=3";
public BaseHandler ()
{
//No need to validate database more than once on each restart.
if (DbIsUpToDate)
return;
CheckAndCreateDatabase(DB_NAME);
int userVersion = GetUserVersion();
UpdateDBToVersion(userVersion);
DbIsUpToDate = true;
}
int GetUserVersion()
{
int version = 0;
using (var cnn = new SqliteConnection(CNN_STRING))
{
cnn.Open();
using (var cmd = cnn.CreateCommand())
{
cmd.CommandText = "CREATE TABLE UVERSION (VERSION INTEGER);" +
"INSERT INTO UVERSION (VERSION) VALUES(1);";
cmd.ExecuteNonQuery();
}
using (var cmd = cnn.CreateCommand())
{
cmd.CommandText = "SELECT VERSION FROM UVERSION;";
var pragma = cmd.ExecuteScalar();
version = Convert.ToInt32((long)pragma);
}
}
return version;
}
void UpdateDBToVersion(int userVersion)
{
//Prepare the sql statements depending on the users current verion
var sqls = new List<string> ();
if (userVersion < 1)
{
sqls.Add("CREATE TABLE IF NOT EXISTS MYTABLE ("
+ " ID INTEGER PRIMARY KEY, "
+ " NAME TEXT, "
+ " DESC TEXT "
+ ");");
}
//Execute the update statements
using (var cnn = new SqliteConnection(CNN_STRING))
{
cnn.Open();
using (var trans = cnn.BeginTransaction(System.Data.IsolationLevel.ReadCommitted))
{
foreach(string sql in sqls)
{
using (var cmd = cnn.CreateCommand())
{
cmd.CommandText = sql;
cmd.ExecuteNonQuery();
}
}
trans.Commit();
//SetUserVersion(DB_VERSION);
}
}
}
protected string GetDBPath (string dbName)
{
// get a reference to the documents folder
var documents = Environment.GetFolderPath(Environment.SpecialFolder.Personal);
// create the db path
string db = Path.Combine (documents, dbName);
return db;
}
protected void CheckAndCreateDatabase (string dbName)
{
var dbPath = GetDBPath(dbName);
// determine whether or not the database exists
bool dbExists = File.Exists(dbPath);
if (!dbExists)
SqliteConnection.CreateFile(dbPath);
}
}
Again, my problem is that every time I run the debugger it runs GetUserVersion but the table UVERSION is not persisted between sessions. The "File.Exists(dbPath)" returns true so CreateFile is not run. Why is the db empty?
This is a code snippet I've used to save my databases in the iOS simulator and the data seems to persist between app compiles just fine:
string documentsPath = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
string libraryPath = Path.Combine (documentsPath, "../Library/");
var path = Path.Combine (libraryPath, "MyDatabase.db3");
You may also want to check out the SQLite class for Xamarin off of Github:
https://github.com/praeclarum/sqlite-net/tree/master/src
Here's a tutorial on how to use said class:
http://docs.xamarin.com/recipes/ios/data/sqlite/create_a_database_with_sqlitenet
Turns out that I was creating the connection object using the CNN_STRING which just had the db-name instead of the full path to the db. Apperantly the connection object creates the database if the file doesn't exist so the File.Exists(...) might not be needed. I'm not really sure if it should be a temporary db if the complete path is not supplied but it seems to be the case. Changing the creation of the connection object to "datasource=" solved the problem.

Problem while adding a new value to a hashtable when it is enumerated

`hi
I am doing a simple synchronous socket programming,in which i employed twothreads
one for accepting the client and put the socket object into a collection,other thread will
loop through the collection and send message to each client through the socket object.
the problem is
1.i connect to clients to the server and start send messages
2.now i want to connect a new client,while doing this i cant update the collection and add
a new client to my hashtable.it raises an exception "collection modified .Enumeration operation may not execute"
how to add a NEW value without having problems in a hashtable.
private void Listen()
{
try
{
//lblStatus.Text = "Server Started Listening";
while (true)
{
Socket ReceiveSock = ServerSock.Accept();
//keys.Clear();
ConnectedClients = new ListViewItem();
ConnectedClients.Text = ReceiveSock.RemoteEndPoint.ToString();
ConnectedClients.SubItems.Add("Connected");
ConnectedList.Items.Add(ConnectedClients);
ClientTable.Add(ReceiveSock.RemoteEndPoint.ToString(), ReceiveSock);
//foreach (System.Collections.DictionaryEntry de in ClientTable)
//{
// keys.Add(de.Key.ToString());
//}
//ClientTab.Add(
//keys.Add(
}
//lblStatus.Text = "Client Connected Successfully.";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
private void btn_receive_Click(object sender, EventArgs e)
{
Thread receiveThread = new Thread(new ThreadStart(Receive));
receiveThread.IsBackground = true;
receiveThread.Start();
}
private void Receive()
{
while (true)
{
//lblMsg.Text = "";
byte[] Byt = new byte[2048];
//ReceiveSock.Receive(Byt);
lblMsg.Text = Encoding.ASCII.GetString(Byt);
}
}
private void btn_Send_Click(object sender, EventArgs e)
{
Thread SendThread = new Thread(new ThreadStart(SendMsg));
SendThread.IsBackground = true;
SendThread.Start();
}
private void btnlist_Click(object sender, EventArgs e)
{
//Thread ListThread = new Thread(new ThreadStart(Configure));
//ListThread.IsBackground = true;
//ListThread.Start();
}
private void SendMsg()
{
while (true)
{
try
{
foreach (object SockObj in ClientTable.Keys)
{
byte[] Tosend = new byte[2048];
Socket s = (Socket)ClientTable[SockObj];
Tosend = Encoding.ASCII.GetBytes("FirstValue&" + GenerateRandom.Next(6, 10).ToString());
s.Send(Tosend);
//ReceiveSock.Send(Tosend);
Thread.Sleep(300);
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
You simply can't modify a Hashtable, Dictionary, List or anything similar while you're iterating over it - whether in the same thread or a different one. There are concurrent collections in .NET 4 which allow this, but I'm assuming you're not using .NET 4. (Out of interest, why are you still using Hashtable rather than a generic Dictionary?)
You also shouldn't be modifying a Hashtable from one thread while reading from it in another thread without any synchronization.
The simplest way to fix this is:
Create a new readonly variable used for locking
Obtain the lock before you add to the Hashtable:
lock (tableLock)
{
ClientTable.Add(ReceiveSock.RemoteEndPoint.ToString(), ReceiveSock);
}
When you want to iterate, create a new copy of the data in the Hashtable within a lock
Iterate over the copy instead of the original table
Do you definitely even need a Hashtable here? It looks to me like a simple List<T> or ArrayList would be okay, where each entry was either the socket or possibly a custom type containing the socket and whatever other information you need. You don't appear to be doing arbitrary lookups on the table.
Yes. Don't do that.
The bigger problem here is unsafe multi-threading.
The most basic "answer" is just to say: use a synchronization lock on the shared object. However this hides a number of important aspects (like understanding what is happening) and isn't a real solution to this problem in my mind.

System.TypeInitializationException was unhandled by user code ERROR please help

I am busy with an e-commerce web application using visual studio 2005 and IIS 7
I got this error
System.TypeInitializationException was unhandled by user code
Message="The type initializer for 'ShopConfiguration' threw an exception."
Source="App_Code.r-ihwy-d"
TypeName="ShopConfiguration"
StackTrace:
at ShopConfiguration.get_DbProviderName()
at GenericDataAccess.CreateCommand() in c:\inetpub\wwwroot\Beadafrican\App_Code\GenericDataAccess.cs:line 63
at CatalogAccess.GetDepartments() in c:\inetpub\wwwroot\Beadafrican\App_Code\CatalogAccess.cs:line 28
at UserControls_DepartmentsList.Page_Load(Object sender, EventArgs e) in c:\inetpub\wwwroot\Beadafrican\UserControls\DepartmentsList.ascx.cs:line 22
at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e)
at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
If I look at the code it refers to I dont see what is wrong? Here is the code if anyone can please assist it would be great!
GenericDataAccess.cs:
public static class GenericDataAccess
{
//static constructor
static GenericDataAccess()
{
//
// TODO: Add constructor logic here
//
}
//execute a command and returns the result as a DataTable Object
public static DataTable ExecuteSelectCommand(DbCommand command)
{
//The DataTable to be returned
DataTable table;
//Execute the command making sure the connection gets closed in the end
try
{
//open the data connection
command.Connection.Open();
//Execute the command and save the results in a DataTable
DbDataReader reader = command.ExecuteReader();
table = new DataTable();
table.Load(reader);
//Close the reader
reader.Close();
}
catch (Exception ex)
{
Utilities.LogError(ex);
throw ex;
}
finally
{
//Close the connection
command.Connection.Close();
}
return table;
}
//creates and prepares a new DbCommand object on a new connection
public static DbCommand CreateCommand()
{
//Obtain the database provider name
string dataProviderName = ShopConfiguration.DbProviderName;
//Obtain the database connection string
string connectionString = ShopConfiguration.DbConnectionString;
//Create a new data provider factory
DbProviderFactory factory = DbProviderFactories.GetFactory(dataProviderName);
//Obtain a database specific connection object
DbConnection conn = factory.CreateConnection();
//Set the connection string
conn.ConnectionString = connectionString;
//Create a database specific command object
DbCommand comm = conn.CreateCommand();
//Set the command type to stored procedure
comm.CommandType = CommandType.StoredProcedure;
//Return the initialised command object
return comm;
}
CatalogAccess.cs
public static class CatalogAccess
{
static CatalogAccess()
{
//
// TODO: Add constructor logic here
//
}
//Retrieve the list of departments
public static DataTable GetDepartments()
{
//get configured DbCommand object
DbCommand comm = GenericDataAccess.CreateCommand();
//set the stored procedure name
comm.CommandText = "GetDepartments";
//execute the stored procedure and return the results
return GenericDataAccess.ExecuteSelectCommand(comm);
}
}
DepartementList.ascx.cs
public partial class UserControls_DepartmentsList : System.Web.UI.UserControl
{
// Load department details into the DataList
protected void Page_Load(object sender, EventArgs e)
{
// don't reload data during postbacks
{
// CatalogAccess.GetDepartments returns a DataTable object containing
// department data, which is read in the ItemTemplate of the DataList
list.DataSource = CatalogAccess.GetDepartments();
// Needed to bind the data bound controls to the data source
list.DataBind();
}
}
}
the ShopConfiguration class
{
//Caches the connection string
private readonly static string dbConnectionString;
//Caches the data provider name
private readonly
static string dbProviderName;
//stores the number of products per page
private readonly static int productsPerPage;
//Stores the product description length for product lits
private readonly static int productDescriptionLenght;
//Store the name of your shop
private readonly static string siteName;
//Initialize various proeprties in the constructor
static ShopConfiguration()
{
dbConnectionString = ConfigurationManager.ConnectionStrings["LocalSqlServer"].ConnectionString;
dbProviderName = ConfigurationManager.ConnectionStrings["LocalSqlServer"].ProviderName;
productsPerPage = Int32.Parse(ConfigurationManager.AppSettings["ProductsPerPage"]);
productDescriptionLenght = Int32.Parse(ConfigurationManager.AppSettings["ProductDescriptionLenght"]);
siteName = ConfigurationManager.AppSettings["SiteName"];
}
//Returns the connection string for BeadAfrican database
public static string DbConnectionString
{
get
{
return dbConnectionString;
}
}
//Returns the data provider name
public static string DbProviderName
{
get
{
return dbProviderName;
}
}
I am quite sure that the TypeInitializationException that is thrown has another exception assigned to its InnerException property. If you examine that exception, I think you will find the real cause of your problem.
Sounds like you have specified an invalid setting for DbProviderName so internal checking code reports this exception. You'd better review the connection string settings.

VSTO 3.0 Get/Change an excel 2007 workbook connection

I've struggling to find a way to get and change and excel 2007 workbook connection (Menu Data -> Existing Connections -> Connections on this Workbook).It's a connection (several actually) to a SQL Server and used in a pivot table.
I've tried using Application.ActiveWorkbook.Connections or Globals.ThisWorkbook.Connections but they both return always Null..I've tried in an sheet event as well as in a custom ribbon's button event as well.
The only way left I can think of is use to code a VBA method that does the work and then invoke it in my VSTO code, but it's not very elegant is it...
Existing connections in Excel (this works in 2007) are not active connections. You must connect using an existing connection before being able to acquire that connection (I did this manually before clicking a button that executed this code).
var application = Globals.ThisAddIn.Application;
//This must be an active connection otherwise handle exceptions
// such as 'Invalid index. (Exception from HRESULT: 0x8002000B (DISP_E_BADINDEX))'
var connection = application.ActiveWorkbook.Connections["EXISTING_CONNECTION_NAME"];
var oledb = connection.OLEDBConnection;
var settings = oledb.Connection;
Here I adjust connection string of Excel Connections. Take in account that I have only ONE connection in Workbook.
public class WorkbookConnectionsManager
{
public static void AdjustConnectionToSqlConnectionString(Excel.WorkbookConnection connection, String connectionString)
{
char[] propertiesSeparator = new char[] { ';' };
char[] propertyValueSeparator = new char[] { '=' };
Excel.OLEDBConnection oleDbConn = connection.OLEDBConnection;
Dictionary<string, string> dictExcelConnStrProperties = GetConnStrDictionary(oleDbConn.Connection, propertiesSeparator, propertyValueSeparator);
Dictionary<string, string> dictActualConnStrProperties = GetConnStrDictionary(connectionString, propertiesSeparator, propertyValueSeparator);
string[] reggedPropertyies = new string[] { "Integrated Security", "Persist Security Info", "User ID", "Password", "Initial Catalog", "Data Source", "Workstation ID" };
foreach (string property in reggedPropertyies)
if (dictExcelConnStrProperties.ContainsKey(property) && dictActualConnStrProperties.ContainsKey(property)
&& null != dictActualConnStrProperties[property] && !String.IsNullOrEmpty(dictActualConnStrProperties[property].ToString()))
dictExcelConnStrProperties[property] = dictActualConnStrProperties[property];
string connStr = GetConnStrFromDict(dictExcelConnStrProperties, propertiesSeparator[0], propertyValueSeparator[0]);
oleDbConn.Connection = connStr;
}
private static string GetConnStrFromDict(Dictionary<string, string> dictConnStrProperties, char propertiesSeparator, char propertyValueSeparator)
{
StringBuilder connStrBuilder = new StringBuilder();
foreach (KeyValuePair<string, string> keyValuePair in dictConnStrProperties)
{
connStrBuilder.Append(keyValuePair.Key);
if (!String.IsNullOrEmpty(keyValuePair.Value))
{
connStrBuilder.Append(propertyValueSeparator);
connStrBuilder.Append(keyValuePair.Value);
}
connStrBuilder.Append(propertiesSeparator);
}
string connStr = String.Empty;
if (connStrBuilder.Length > 1)
{
connStr = connStrBuilder.ToString(0, connStrBuilder.Length - 1);
}
return connStr;
}
private static Dictionary<string, string> GetConnStrDictionary(string connString, char[] propertiesSeparator, char[] propertyValueSeparator)
{
string[] keyAndValue;
string[] arrayConnStrProperties = connString.Split(propertiesSeparator);
Dictionary<string, string> dictConnStrProperties = new Dictionary<string, string>();
foreach (string excelConnStrProperty in arrayConnStrProperties)
{
keyAndValue = excelConnStrProperty.Split(propertyValueSeparator);
if (keyAndValue.Length > 1)
{
dictConnStrProperties.Add(keyAndValue[0], keyAndValue[1]);
}
else if (keyAndValue.Length > 0)
{
//standalone attribute
dictConnStrProperties.Add(keyAndValue[0], String.Empty);
}
}
return dictConnStrProperties;
}
}
I can't remember where but I remember reading somewhere that the Connections collection was of limited use for writing ODBC type connections. It has several enum values for a "connection" but I'm not sure if some of those are readonly from that interface.
Regardless it should be quite easy to implement new connections and edit existing ones from VSTO. The best option would be to use COM interop to call the SQLConfigDataSource() function from the ODBCCP32.DLL win32 library.
Also check out the following addin which makes it easier to work with query tables in Excel.

Resources