ASP.NET Cache always returns null - asp.net

I am using SQLCacheDependency in my ASP.NET application with Query Notifications.
I followed this article to set up my database with success.However whenever I am trying to store data in the cache object.It just does not hold value.It is always null .I am not getting any errors or exceptions.
Here is my code
Global.asax
void Application_Start(object sender, EventArgs e)
{
// Code that runs on application startup
System.Data.SqlClient.SqlDependency.
Start(ConfigurationManager.ConnectionStrings["McdConn"].ToString());
}
void Application_End(object sender, EventArgs e)
{
// Code that runs on application shutdown
System.Data.SqlClient.SqlDependency.
Stop(ConfigurationManager.ConnectionStrings["McdConn"].ToString());
}
public static class CacheManagement
{
public static DataTable CreateCache(string cacheName, string tableName, string query)
{
DataTable dtResult = new DataTable();
try
{
string connectionString = ConfigurationManager.ConnectionStrings["McdConn"].ToString();
dtResult = HttpContext.Current.Cache[cacheName] as DataTable;
if (dtResult == null)
{
dtResult = new DataTable();
using (var cn = new SqlConnection(connectionString))
{
cn.Open();
var cmd = new SqlCommand(query, cn);
cmd.Notification = null;
cmd.NotificationAutoEnlist = true;
SqlCacheDependencyAdmin.EnableNotifications(connectionString);
if (!SqlCacheDependencyAdmin.GetTablesEnabledForNotifications(connectionString).Contains(tableName))
{
SqlCacheDependencyAdmin.EnableTableForNotifications(connectionString,tableName);
}
var dependency = new SqlCacheDependency(cmd);
//SqlDataAdapter ad = new SqlDataAdapter(cmd);
//ad.Fill(dsResult);
SqlDataReader reader = cmd.ExecuteReader();
dtResult.Load(reader);
HttpContext.Current.Cache.Insert(cacheName, dtResult, dependency);
}
}
}
catch (Exception ex)
{
Exception_Log.ExceptionMethod("Web", "CacheManagement.cs", "CacheManagement", ex);
}
return dtResult = HttpContext.Current.Cache[cacheName] as DataTable;
}
}
Code Behind
var dtCachedCategories = HttpContext.Current.Cache["tbl_CategoryMaster_Cached"] as DataTable;
if (dtCachedCategories == null)
{
dtCachedCategories = CacheManagement.CreateCache("tbl_CategoryMaster_Cached","dbo.tbl_CategoryMaster_Languages", "Select * from dbo.tbl_CategoryMaster_Languages");
}
The above always returns null.
Can anyone help me in pointing out what could be missing?

Well there's a lot you can do to debug your code and arrive at a conclusion. It seems like your cached item is getting removed too frequently.
1.) Use CacheItemPriority.NotRemovable to Cache.Insert() to make sure ASP.NET doesn't removes
your item whenever it feels so. use the Insert() method explained here. Check this MSDN
article too.
2.) To find out the reason why your cached item is getting removed , log this removal action using
CacheItemRemovedCallback delegate option of your Cache.Insert() method. Check this Insert method
overload version and also this link.
3.) Make sure your dtresult as well as your reader is not null. Check the lines:
SqlDataReader reader = cmd.ExecuteReader(); & dtResult.Load(reader); , together with your logs.
4.) Check your application Pool recycle time. This link has everything related to App pool settings ( IIS 7 +).
5.) This link has a solution for App pool of IIS 6: http://bytes.com/topic/net/answers/717129-c-asp-net-page-cache-getting-removed-too-soon
Also, try using HttpRuntime.Cache method to see if it works.
System.Web.HttpRuntime.Cache.Insert(cacheName, dtResult, dependency);

Related

SQLDependency Onchange event always firing without data change

I'm using it on a console project.
.NET Framework: 4.5
In my test code, SQLDependency onChange always firing although there is no data changes in Database.
class Program
{
private static string _connStr;
static void Main(string[] args)
{
_connStr = "data source=xxx.xxx.xx.xx;User Id=xxx;Password=xxx; Initial Catalog=xxx";
SqlDependency.Start(_connStr);
UpdateGrid();
Console.Read();
}
private static void UpdateGrid()
{
using (SqlConnection connection = new SqlConnection(_connStr))
{
using (SqlCommand command = new SqlCommand("select msgdtl,msgid From NotifyMsg", connection))
{
command.CommandType = CommandType.Text;
connection.Open();
SqlDependency dependency = new SqlDependency(command);
dependency.OnChange += new OnChangeEventHandler(dependency_OnChange);
SqlDataReader sdr = command.ExecuteReader();
Console.WriteLine();
while (sdr.Read())
{
Console.WriteLine("msgdtl:{0}\t (msgid:{1})", sdr["msgdtl"].ToString(), sdr["msgid"].ToString());
}
sdr.Close();
}
}
}
private static void dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
UpdateGrid();
}
when I start running, onChange event fires and never stop. But there is no change in my databse.
Try to check the SqlNotificationEventArgs object in the dependency_OnChnage method. It looks like you have an error there. I had the same SqlDependency behavior one time and the problem was solved by changing select msgdtl,msgid From NotifyMsg to select msgdtl,msgid From dbo.NotifyMsg (The dbo statement has been added).
But I should warn you: be careful using SqlDependency class - it has the problems with memory leaks. Hovewer, you can use an open source realization of the SqlDependency class - SqlDependencyEx. It uses a database trigger and native Service Broker notification to receive events about the table changes. This is an usage example:
int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME))
{
sqlDependency.TableChanged += (o, e) => changesReceived++;
sqlDependency.Start();
// Make table changes.
MakeTableInsertDeleteChanges(changesCount);
// Wait a little bit to receive all changes.
Thread.Sleep(1000);
}
Assert.AreEqual(changesCount, changesReceived);
With SqlDependecyEx you are able to monitor INSERT, DELETE, UPDATE separately and receive actual changed data (xml) in the event args object. Hope this help.
there is a custom implementation of SqlDependency that report you the changed table records:
var _con= "data source=.; initial catalog=MyDB; integrated security=True";
static void Main()
{
using (var dep = new SqlTableDependency<Customer>(_con, "Customer"))
{
dep.OnChanged += Changed;
dep.Start();
Console.WriteLine("Press a key to exit");
Console.ReadKey();
dep.Stop();
}
}
static void Changed(object sender, RecordChangedEventArgs<Customer> e)
{
if (e.ChangeType != ChangeType.None)
{
for (var index = 0; index < e.ChangedEntities.Count; index++)
{
var changedEntity = e.ChangedEntities[index];
Console.WriteLine("DML operation: " + e.ChangeType);
Console.WriteLine("ID: " + changedEntity.Id);
Console.WriteLine("Name: " + changedEntity.Name);
Console.WriteLine("Surame: " + changedEntity.Surname);
}
}
}
Here is the link: [https://tabledependency.codeplex.com]

Issue regarding implementing SQL Dependency in Application_Start event

i through i will call SQL Dependency related code Application_Start event and my objective will be completed. my scenario is i have a routine in my web application which i invoke manually just clicking on a button when data updated in sql server table. i was told to make this process automated.
so i go through couple of article on SQL Dependency and through i can make my manual process automated by SQL Dependency because we can monitor table change by SQL Dependency and SQL Dependency can notify us when change done.
please see my code
protected void Application_Start(Object sender, EventArgs e)
{
System.Data.SqlClient.SqlDependency.Stop(connectionString);
System.Data.SqlClient.SqlDependency.Start(connectionString);
RegisterNotification();
}
static SqlDependency dep;
private static void RegisterNotification()
{
string tmpdata = "";
try
{
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "SELECT ActivityDate FROM [bba-reman].ContentChangeLog";
dep = new SqlDependency(cmd);
dep.OnChange += new OnChangeEventHandler(OnDataChange);
SqlDataReader dr = cmd.ExecuteReader();
{
while (dr.Read())
{
if (dr[0] != DBNull.Value)
{
tmpdata = dr[0].ToString();
}
}
}
dr.Dispose();
cmd.Dispose();
}
}
finally
{
//SqlDependency.Stop(connStr);
}
}
static void OnDataChange(object sender, SqlNotificationEventArgs e)
{
SqlDependency dep = sender as SqlDependency;
dep.OnChange -= new OnChangeEventHandler(OnDataChange);
SiteSearch.CreateIndex(false);
RegisterNotification();
}
protected void Application_End(Object sender, EventArgs e)
{
System.Data.SqlClient.SqlDependency.Stop(connectionString);
}
the above code was running fine but i faced a good problem. suppose no visitor is visiting our web site and at the same time if some one change sql data by a win apps then i saw OnDataChange() event is not firing but if at least one visitor is with our site then OnDataChange() event is firing properly.
may be this is default nature of asp.net engine. i could use SQL Dependency in win service or in winform apps but i have some constrain because the routine which i am calling after detection of data change in db that is in our web application.
So please guide me what i can do as a result OnDataChange() event should always fire if no visitor is visiting our web site.
thanks

Cache looks like never been made in ASP.NET SQL

I'm developing website with query notification using SqlCacheDependency. When the website loads for the first time, if there is any cache, it retrieves the data from the cache while the opposite, if there is no cache, it retrieves data from database and then insert the cache.
When the user inserts data, and clicks a button, the website stores the data to the database, removes the cache, so when the page redirects to itself, there is no cache, which makes the website should retrieve the new data.
Here is the following code:
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
return;
this.BindGrid();
System.Diagnostics.Debug.WriteLine(Cache.Count);
//cache counts : -4; I don't even know why
}
protected void btnSave_Click(object sender, EventArgs e)
{
this.Insert(this.txtTitle.Text, Convert.ToInt32(this.txtDescription.Text));
//insert just function to update the database
Cache.Remove("Messages");
this.BindGrid();
}
private void BindGrid()
{
DataTable dtMessages = (DataTable)Cache.Get("Messages");
if (dtMessages == null)
{
dtMessages = this.LoadMessages();
lblDate.Text = string.Format("Last retrieved DateTime : {0}", System.DateTime.Now);
}
else
{
lblDate.Text = "Data Retrieved from Cache";
}
grdMessages.DataSource = dtMessages;
grdMessages.DataBind();
}
private DataTable LoadMessages()
{
DataTable dtMessages = new DataTable();
dtMessages = new DataTable();
using (SqlConnection connection = new SqlConnection(this.ConnectionString))
{
SqlCommand command = new SqlCommand("select * from blablabla", connection);
SqlCacheDependency dependency = new SqlCacheDependency(command);
if (connection.State == ConnectionState.Closed)
connection.Open();
dtMessages.Load(command.ExecuteReader(CommandBehavior.CloseConnection));
if (Cache.Get("Messages") == null)
{
Cache.Insert("Messages", dtMessages, dependency);
}
}
return dtMessages;
}
The problem is, looks like the cache hasn't been made/inserted. Because the value of Cache.Count is negative number. And whenever I just refresh the page (where the page supposed to retrieve data from cache), the page retrieves the data from database.
What's wrong and what is the solution? There are two important things to know:
Page only retrieves from database when there is no cache (cache'll be removed when user inserts data)
Page retrieves from cache when there is no any updated/new data from user (e.g. user just refreshes the page, page retrieves from cache)
Please help. Thank you for your time and attention.

Returning JSON with ASP.NET and $.getJSON

I have a page that connects to the Northwind database to get a list of categories...
protected void Page_Load(object sender, EventArgs e)
{
var cnn = new SqlConnection(ConfigurationManager.ConnectionStrings["cnnString"].ConnectionString);
var cmd = new SqlCommand("SELECT CategoryID, CategoryName FROM Categories ORDER BY CategoryName", cnn);
using (cnn)
{
cnn.Open();
var dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
if (dr.HasRows)
{
var sb = new StringBuilder();
var sw = new StringWriter(sb);
using (JsonWriter jw = new JsonTextWriter(sw))
{
jw.Formatting = Formatting.Indented;
jw.WriteStartArray();
while (dr.Read())
{
jw.WriteStartObject();
jw.WritePropertyName("CategoryID");
jw.WriteValue(dr.GetInt32(0));
jw.WritePropertyName("CategoryName");
jw.WriteValue(dr.GetString(1));
jw.WriteEndObject();
}
jw.WriteEndArray();
jw.Flush();
Response.Write(sb);
}
}
}
}
This works just as expected. In my calling page I have a dropdownlist and I'm trying to use jQuery to populate it. Maybe I'm doing this wrong. I'm assuming that it takes the entire text from the .aspx file which includes the and strings and causes it to be invalid? If so, what is the correct way to do this, or what is it that I am doing wrong?
$.getJSON('GetCategories.aspx', function (data) {
alert('success!');
$.each(data, function (key, val) {
$('#ddlCategories').append('<option></option>').val(key).html(val);
});
});
The alert never happens so it craps out getting the file. The file name is correct as Chrome Inspector gives me no console errors.
You should look into HttpHandlers, as they have much lower overhead and can be restricted to just the output you want.
I use a HttpHandler as an example in another answer here Accessing Image from App_data folder

Question about inserting Users/Members into a database table!

My registration form has got a CreateUserWizard. I used its event that is fired after the user is created.
Then I obtain the users identity and key. In the last line, I send the unique key to a function inside a class that should insert the key into the Users table (the field is a primary key and is unique).
public partial class Registration : System.Web.UI.Page
{
protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)
{
MembershipUser CurrentUser = Membership.GetUser(User.Identity.Name);
int i =(int) CurrentUser.ProviderUserKey;
RegisterAdo.InsertUsers(i);
}
}
Below, I execute the query with the value that I passed and insert the user into a database
class RegisterAdo
{
public static void InsertUsers(int UsersIDentity)
{
string myConnectionString = WebConfigurationManager.ConnectionStrings["YourGuruDB"].ConnectionString;
SqlConnection sqlConnect = new SqlConnection(myConnectionString);
SqlCommand sqlCommand = new SqlCommand(RegisterAdo.insertCommand(UsersIDentity), sqlConnect);
try
{
sqlConnect.Open();
sqlCommand.ExecuteNonQuery();
}
catch (Exception x)
{
}
finally
{
sqlConnect.Close();
}
}
public static String insertCommand(int UsersIdentityToinsert)
{
string insertCommand="INSERT INTO Users(";
insertCommand += "UserID)";
insertCommand += "VALUES('";
insertCommand += UsersIdentityToinsert+"')";
return insertCommand;
}
My question is whether it is the best way to insert UserID into a table, and whether I do it right at all. I need the UserID to be unique, and the whole command executed with no fail...(just after the user was created and the whole UserCreateUser finished validating the user!!!
I would change two things mainly:
don't concatenate together your SQL statement - this opens doors to SQL injection attacks. Use parametrized queries instead - they are both safer, and they perform better (since only a single copy of the query's execution plan needs to be created and cached and will be reused over and over again)
put your SqlConnection and SqlCommand objects into using blocks so that they'll be automatically freed / disposed when the using blocks ends (and you can save yourself the finally block of the try...catch construct, too!).
So my code would look like this
public static void InsertUsers(int UsersIDentity)
{
string myConnectionString = WebConfigurationManager.ConnectionStrings["YourGuruDB"].ConnectionString;
string insertStmt =
"INSERT INTO dbo.Users(UserID) VALUES(#UserID)";
using(SqlConnection _con = new SqlConnection(myConnectionString))
using(SqlCommand _cmd = new SqlCommand(insertStmt, sqlConnect))
{
_cmd.Parameters.Add("#UserID", SqlDbType.Int).Value = UsersIDentity;
try
{
_con.Open();
_cmd.ExecuteNonQuery();
_con.Close();
}
catch (Exception x)
{
// do something if error occurs
}
}

Resources