How to cache global information for all users? - asp.net

I have my first bigger asp.net website and there are userlists of all user online - of course this list is the same for every user, but as a normal online list I update this with PageMethod / WebMethod every 10 seconds.
So if 100 users online that means 10x6x100 = 6000 database querys each minute.
How can I avoid that?
Can I save this information for all user in something like a session / querystring / cookie but global for all users to avoid querys?

The Simplest way is to create an Application Variable or DataTable, which will hold your Required Information.
After each 10 minutes, when you update the records, Just update the Application Datatable you created above. This DataTable is common for all the users and that will decrease your load drastically.
Let me know if you need code.

You may us static variable for this. If you are having more than 1 app-pool to serverpages
then use asp.net caching since static variable are not thread safe.
Here is my code that i use for something similar it has 2 class.
class1
using System;
public class onlineuser
{
public string sessionid = "";
public string username = "";
public string currentpage = "";
public DateTime time = DateTime.Now;
public onlineuser()
{
//
// TODO: Add constructor logic here
//
}
}
class2
using System;
using System.Collections;
using System.Data;
public class user
{
public static ArrayList online;
public static void adduser(string sessionid,string username,string currentpage)
{
removeunused();
remove(sessionid);
onlineuser ou = new onlineuser();
ou.sessionid = sessionid;
ou.username = username;
ou.currentpage = currentpage;
ou.time = DateTime.Now;
if (online==null)
{
online = new ArrayList();
}
online.Add(ou);
online.TrimToSize();
}
public static void remove(string sessionid)
{
if (online==null)
{
return;
}
onlineuser ou = new onlineuser();
for (int i = 0; i < online.Count; i++)
{
ou = (onlineuser)online[i];
if (ou.sessionid == sessionid)
{
online.RemoveAt(i);
online.TrimToSize();
return;
}
}
}
public static void removeunused()
{
if (online == null)
{
return;
}
onlineuser ou = new onlineuser();
for (int i = 0; i < online.Count; i++)
{
ou = (onlineuser)online[i];
if (ou.time < DateTime.Now.AddMinutes(-2))
{
online.RemoveAt(i);
online.TrimToSize();
return;
}
}
}
public static DataTable totable()
{
DataTable dt = new DataTable();
DataColumn dc = new DataColumn("SessionId", typeof(string));
DataColumn dc1 = new DataColumn("UserName", typeof(string));
DataColumn dc2 = new DataColumn("currentpage", typeof(string));
DataColumn dc3 = new DataColumn("Time", typeof(DateTime));
dt.Columns.Add(dc);
dt.Columns.Add(dc1);
dt.Columns.Add(dc2);
dt.Columns.Add(dc3);
if (online!=null)
{
onlineuser ou = new onlineuser();
for (int i = 0; i < online.Count; i++)
{
ou = (onlineuser)online[i];
dt.Rows.Add(new object[] {ou.sessionid,ou.username,ou.currentpage,ou.time});
}
}
return dt;
}
}
following code is placed in mymaster page which update userlist
try
{
string uname= "N/A";
if (Session["uname"]!=null)
{
uname = Session["uname"].ToString();
}
string page = Path.GetFileName(Request.PhysicalPath).Trim().ToLower();
if (Request.QueryString!=null)
{
page += "?"+Request.QueryString.ToString();
}
user.adduser(Session.SessionID, uname, page);
}
catch (Exception)
{
}

Related

How to use Tempdata to display the list

I have did the excel upload in dotnet core .I had to use tempdata to retrieve the details of the excel in list.Instead in my below code i had used Static object to retrieve the list.My code works as like this ,when i click on upload button it will display the details in the excel sheet.and when click on save it will save it to database and i need to edit in grid view using ajax call also .Help me out
My Action in controller is
public async Task<IActionResult> ImportEmployeeDetails(IFormFile excelfile)
{
try
{
EmployeesViewModelList employeesListObject = new EmployeesViewModelList();
List<EmployeeModel> employeesViewModelList = new List<EmployeeModel>();
if (excelfile == null || excelfile.Length == 0)
{
return View(employeesListObject);
}
var supportedTypes = new[] { ".xls", ".xlsx" };
var ext = Path.GetExtension(excelfile.FileName);
if (!supportedTypes.Contains(ext))
{
return View(employeesListObject);
}
var path = Path.Combine(
Directory.GetCurrentDirectory(), "wwwroot",
"EmployeeDetails.xlsx");
if (System.IO.File.Exists(path))
{
System.IO.File.Delete(path);
}
using (var stream = new FileStream(path, FileMode.Create))
{
await excelfile.CopyToAsync(stream);
}
FileInfo file = new FileInfo(path);
using (ExcelPackage package = new ExcelPackage(file))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
int rowCount = worksheet.Dimension.Rows;
int ColCount = worksheet.Dimension.Columns;
for (int i = 2; i <= rowCount; i++)
{
EmployeeModel emp = new EmployeeModel();
emp.EmployeeId = Convert.ToInt32(worksheet.Cells[i, 1].Value.ToString());
emp.EmpFirstName = worksheet.Cells[i, 2].Value.ToString();
employeesViewModelList.Add(emp);
}
employeesListObject.EmpModelList = employeesViewModelList;
return View(employeesListObject);
}
}
catch(Exception ex)
{
TempData["Message"] = "Opps! Something Went wrong!";
return RedirectToAction("ExcelPackage");
}
}
Try this, using your own list.
List<string> SomeList = new List<string>();
TempData["MyList"] = SomeList;
//then to get data just do
SomeList = TempData["MyList"] as List<string>; //This converts back to List<T>
Once you add the list to the TempData, you can retrive it from any Action or View in the same controller

Core 2.1 SignalR and SQLDependency

Is there any Core 2.1 sample available for using SignalR with SQLDependency.
Did enable broker, etc. but never get any dependency onChange event firing. Just the event subscribe is triggered.
When the MS-SQL database table Cities changes on the back-end, I want to see the change reflected right-away on the client web page without having to refresh/reload the page.
//start the dependency when app start in ConfigureServices
SqlDependency.Start(Configuration.GetConnectionString("DefaultConnection"));
using Microsoft.AspNetCore.SignalR;
using SignalR_Test4.Data;
using SignalR_Test4.Hubs;
using System.Collections.Generic;
using System.Data.SqlClient;
namespace SignalR_Test4.Models
{
public class CityRepository
{
private readonly ApplicationDbContext _context;
private readonly IHubContext<CityHub> _hubcontext;
public CityRepository(ApplicationDbContext context, IHubContext<CityHub> hubcontext)
{
_context = context;
_hubcontext = hubcontext;
}
public IEnumerable<City> GetCities()
{
List<City> listOf = new List<City>();
//listOf = _context.Cities;
using (var conn = new SqlConnection(GlobalVar.connectionString))
{
conn.Open();
using (var cmd = new SqlCommand(#"SELECT * FROM Cities", conn))
{
cmd.Notification = null;
SqlDependency dependency = new SqlDependency(cmd);
dependency.OnChange += Dependency_OnChange;
if (conn.State == System.Data.ConnectionState.Closed)
conn.Open();
var reader = cmd.ExecuteReader();
while (reader.Read())
{
listOf.Add(new City { Id = (string)reader["Id"], Name_en = (string)reader["name_en"], CountryId = (string)reader["CountryId"], Code = (string)reader["Code"] });
}
}
}
return listOf;
}
private void Dependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
_hubcontext.Clients.All.SendAsync("GetCities");
}
}
}
}
The issue was within the line:
var cmd = new SqlCommand(#"SELECT Id, Name_en, CountryId, Code from [dbo].Cities", conn)
It is required to use the field name (Not the *) and also the 2 part table name convention => [dbo].Cities

Retrieving Multiple rows from SQLite in Xamarin iOS

I'm doing an app with Xamarin iOS.
I put a UITableView on XCode, so that when I click on a button, it retrieves from the database and slot it in. I'm able to put it onto a row, but couldn't figure it out how to have multiple rows of data in it. This is my partial code from which I'm able to display a row of data.
cmd.CommandType = CommandType.Text;
dr = cmd.ExecuteReader();
while (dr.Read())
{
var table = new UITableView(this.retrieveData.Frame);
string[] tableItems = new String[] {dr["admin_num"] + ", " + dr["name"]};
table.Source = new TableSource(tableItems);
Add (table);
}
You are creating a completely new TableView for each row in your data. Instead, you should loop through your data and create a data structure (List, array, etc) containing ALL of the data you want to display, and then pass that data to your TableView/Source.
cmd.CommandType = CommandType.Text;
dr = cmd.ExecuteReader();
// you will need a class mydata with Num and Name properties
List<mydata> data = new List<mydata>();
while (dr.Read())
{
data.Add(new mydata { Num = dr["admin_num"], Name = dr["name"] });
}
dr.Close();
var table = new UITableView(this.retrieveData.Frame);
table.Source = new TableSource(data);
Add (table);
What you need to do is this:
public List<DemoClass> getDemoClassList()
{
List<DemoClass> lstDemoClass;
DemoClass objDemoClass;
try
{
String strCommandText;
strCommandText = "SELECT * FROM DemoClass ";
command = new SqliteCommand(strCommandText, connection);
lstDemoClass = new List<DemoClass>();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
objDemoClass = new Homes(false);
objDemoClass.ID = Convert.ToInt32(reader[0]);
objDemoClass.Name = Convert.ToString(reader[1]);
lstDemoClass.Add(objDemoClass);
}
}
return lstDemoClass;
}
catch (Exception ex)
{
throw ex;
}
finally
{
command.Dispose();
command = null;
lstDemoClass = null;
objDemoClass = null;
}
}
public void BindList()
{
List<DemoClass> lstDemoClass = new List<DemoClass>();
DemoClass hm = new DemoClass();
lstDemoClass = (List<DemoClass>)hm.getDemoClassList();
TableViewDataSource tdatasource = new TableViewDataSource(this, lstDemoClass);
table.Hidden = false;
table.DataSource = tdatasource;
table.Delegate = new TableViewDelegate(this, table, lstDemoClass);
table.ReloadData();
}
The getDemoClassList() will give the retrieved list from SQLite table, and later you can bind the list to the table datasource.
UPDATE:
As per your request I have updated my comment with the code for datasource and its delegate classes.
Now in this same class you need to add the following subclasses:
#region TableDelegate
public class TableViewDelegate : UITableViewDelegate
{
private DemoPageViewController _Controller;
private List<DemoClass> lst;
public TableViewDelegate(DemoPageViewController controller ,UITableView tableView, List<DemoClass> tblList)
{
try
{
this._Controller = controller;
this.lst = tblList;
}
catch(Exception ex)
{
}
}
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
try
{
//This loads the activity spinner till the selection code is completed
_Controller._loadPop = new LoadingOverlay (new System.Drawing.RectangleF(0,0,_Controller.View.Frame.Width,_Controller.View.Frame.Height),"Loading...");
_Controller.View.Add ( _Controller._loadPop );
// spin up a new thread to do some long running work using StartNew
Task.Factory.StartNew (
// tasks allow you to use the lambda syntax to pass work
() => {
InvokeOnMainThread(delegate{
DemoClass f = lst[indexPath.Row];
//Add your code here, usually some navigation or showing a popup
});
}).ContinueWith(t => InvokeOnMainThread(() => {
//Hide the activity spinner
_Controller._loadPop.Hide();
}));
}
catch(Exception ex)
{
}
finally
{
}
}
}
#endregion
#region TableDataSource
private class TableViewDataSource : UITableViewDataSource
{
static NSString kCellIdentifier = new NSString("MyIdentifier");
private List<DemoClass> lst;
private DemoPageViewController controller;
public TableViewDataSource (DemoPageViewController controller ,List<DemoClass> tblLst)
{
this.controller = controller;
this.lst = tblLst;
}
public override int NumberOfSections (UITableView tableView)
{
return 1;
}
public override int RowsInSection (UITableView tableView, int section)
{
return lst.Count;
}
// Override to support conditional editing of the table view.
public override bool CanEditRow (UITableView tableView, MonoTouch.Foundation.NSIndexPath indexPath)
{
// Return false if you do not want the specified item to be editable.
return false;
}
public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
{
try
{
UITableViewCell cell = tableView.DequeueReusableCell (kCellIdentifier);
if (cell == null)
{
cell = new UITableViewCell (UITableViewCellStyle.Subtitle, kCellIdentifier);
cell.Tag = Environment.TickCount;
}
DemoClass objDemo = lst[indexPath.Row];
cell.Accessory = UITableViewCellAccessory.DisclosureIndicator;
cell.ImageView.Image = UIImage.FromFile("Images/CameraImg.png");
cell.DetailTextLabel.Text = "Show some detail: " + objDemo.DemoDescription.ToString();
cell.TextLabel.Text = "Some Title: " + objDemo.DemoTitle.ToString();
return cell;
}
catch(Exception ex)
{
return null;
}
finally
{
}
}
}
#endregion
Hope it helps.

Calling Stored procedure inside a thread to update multiple records

I am trying to calla stored procedure for various unique entities . The stored procedure for a single entity takes about 33 secs. So I decided to call it using threads.
Here are some of trials I have done :
public bool ExecuteTaxRateLinkingParallel(int mapID, int createdBy)
{
try
{
int snapshotID = (int)(HttpContext.Current.Session[GlobalConstant.snapShotID]);
List<TaxEntity> taxEntities = new List<TaxEntity>();
List<Task> tasks = new List<Task>();
using (var ctx = new TopazDbContainer())
{
taxEntities = ctx.TaxEntities.AsParallel().Where(t => t.IsActive == true).ToList<TaxEntity>();
}
Parallel.ForEach<TaxEntity>(taxEntities, (entity) =>
{
//SqlConnection connection; SqlTransaction trans; SqlCommand command;
// break this into pieces of 5
var task = Task.Factory.StartNew(() =>
{
using (var pctx = new TopazDbContainer())
{
try
{
int taxEntityID = entity.TaxEntityID;
pctx.CommandTimeout = 5000;
//string connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["TOPAZDBConnectionStringParallel"].ConnectionString;
//connection = new SqlConnection(connectionString);
//command = new SqlCommand("dbo.[Usp_TaxRatesLinkingParallel]", connection);
//trans = connection.BeginTransaction();
//command.CommandType = CommandType.StoredProcedure;
//command.Parameters.AddWithValue("#MapID", mapID);
//command.Parameters.AddWithValue("#UserID", createdBy);
//command.Parameters.AddWithValue("#TaxEntityID", taxEntityID);
//command.Parameters.AddWithValue("#SnapshotID", snapshotID);
//connection.Open();
//command.CommandTimeout = 5000;
//command.ExecuteReader().AsParallel();
pctx.ContextOptions.LazyLoadingEnabled = true;
//pctx.ExecuteStoreCommand("Exec [Usp_TaxRatesLinkingParallel] #MapID={0},#UserID={1},#TaxEntityID={2},#SnapshotID{3}", new SqlParameter("MapID", mapID), new SqlParameter("UserID", createdBy), new SqlParameter("TaxEntityID", taxEntityID), new SqlParameter("SnapshotID", snapshotID));
var param = new DbParameter[] { new SqlParameter("UserID", createdBy), new SqlParameter("TaxEntityID", taxEntityID), new SqlParameter("SnapshotID", snapshotID) };
pctx.ExecuteStoreCommand("Exec [Usp_TaxRatesLinkingParallel] #MapID,#UserID,#TaxEntityID,#SnapshotID", param);
//var result = output.FirstOrDefault();
}
catch (TaskCanceledException tx)
{
}
catch (Exception e)
{
}
finally
{
pctx.SaveChanges();
pctx.Connection.Close();
}
}
}, TaskCreationOptions.PreferFairness);
tasks.Add(task);
try
{
Task.WaitAll(tasks.ToArray());
}
catch (AggregateException ae)
{
ae.Handle((x) =>
{
if (x is UnauthorizedAccessException)
{
return true;
}
else
{
return false;
}
});
}
catch (Exception ex)
{
throw ex;
}
});
return true;
}
catch (Exception ex)
{
TopazErrorLogs.AddTopazErrorLogBL(ex, 1, 1);
throw new TopazCustomException(GlobalConstant.errorMessage);
}
}
For some the above statements the SP seems like it runs fine but when I check from the application or from backend the records doesn't get updated.
Need help!
If you are not on .NET 4.5 yet, you can use these extension methods to execute your commands async.
using System.Diagnostics.Contracts;
using System.Threading.Tasks;
using System.Xml;
namespace System.Data.SqlClient
{
public static class SqlCommandExtensions
{
public static Task<SqlDataReader> ExecuteReaderAsync(this SqlCommand command)
{
Contract.Requires(command != null);
return ExecuteReaderAsync(command, null);
}
public static Task<SqlDataReader> ExecuteReaderAsync(this SqlCommand command, object state)
{
Contract.Requires(command != null);
return Task.Factory.FromAsync<SqlDataReader>(command.BeginExecuteReader, command.EndExecuteReader, state);
}
public static Task<XmlReader> ExecuteReaderXmlAsync(this SqlCommand command)
{
Contract.Requires(command != null);
return ExecuteReaderXmlAsync(command, null);
}
public static Task<XmlReader> ExecuteReaderXmlAsync(this SqlCommand command, object state)
{
Contract.Requires(command != null);
return Task.Factory.FromAsync<XmlReader>(command.BeginExecuteXmlReader, command.EndExecuteXmlReader, state);
}
public static Task<int> ExecuteNonQueryAsync(this SqlCommand command)
{
Contract.Requires(command != null);
return ExecuteNonQueryAsync(command, null);
}
public static Task<int> ExecuteNonQueryAsync(this SqlCommand command, object state)
{
Contract.Requires(command != null);
return Task.Factory.FromAsync<int>(command.BeginExecuteNonQuery, command.EndExecuteNonQuery, state);
}
}
}
It is not an asynchronous database query that you are doing here. Please have a look:
Asynchronous Database Calls With Task-based Asynchronous Programming Model (TAP) in ASP.NET MVC 4
Here is an example of an asynchronous database call with new async / await features:
public async Task<IEnumerable<Car>> GetCarsAsync() {
var connectionString =
ConfigurationManager.ConnectionStrings["CarGalleryConnStr"].ConnectionString;
var asyncConnectionString = new SqlConnectionStringBuilder(connectionString) {
AsynchronousProcessing = true
}.ToString();
using (var conn = new SqlConnection(asyncConnectionString)) {
using (var cmd = new SqlCommand()) {
cmd.Connection = conn;
cmd.CommandText = selectStatement;
cmd.CommandType = CommandType.Text;
conn.Open();
using (var reader = await cmd.ExecuteReaderAsync()) {
return reader.Select(r => carBuilder(r)).ToList();
}
}
}
}
You may find the detailed info inside the blog post.

Display Multiple Notes on Same Date of Calender

I want to display calendar with some notes/events which i stored in database.
In some date more than one notes are added.
Now when page is load i want that all in my calendar control.
I done that BUT It displays only one(1st entered) note in the calendar although i saved more than one notes on that same DATE.
It looks like below image..
In this Image On Date 7 i added 2 Notes but it displays only one...
My code is as below...
public partial class _Default : System.Web.UI.Page
{
public static ArrayList MyColllection;
//Structure
public struct My_Date
{
public DateTime Cal_Date;
public string Cal_Type;
public string Cal_Title;
}
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
MyColllection = Get_Event();
}
}
public ArrayList Get_Event()
{
SqlConnection myCon = new SqlConnection(ConfigurationManager.AppSettings["ConnectionString"]);
SqlCommand myComd = new SqlCommand("SELECT * FROM Cal_Event",myCon);
SqlDataReader myDataReader;
try
{
myCon.Open();
myDataReader = myComd.ExecuteReader();
MyColllection = new ArrayList();
My_Date temp;
//Iterate through the data reader
while(myDataReader.Read())
{
temp.Cal_Title = myDataReader.GetValue(1).ToString();
temp.Cal_Date = Convert.ToDateTime(myDataReader.GetValue(2));
temp.Cal_Type = myDataReader.GetValue(3).ToString();
MyColllection.Add(temp);
}
}
catch
{}
finally
{
myCon.Close();
}
return MyColllection;
}
public void Calendar1_DayRender(object o, DayRenderEventArgs e)
{
string FontColor;
string compDate = "01/01/1900"; // Date to compare initially
DateTime DayVal = Convert.ToDateTime(compDate);
bool mItemDay = false;
bool dayTextChanged = false;
StringBuilder strTemp = new StringBuilder();
foreach (My_Date temp_dt in MyColllection)
{
if ("01/01/1900" != temp_dt.Cal_Date.ToShortDateString())
{
if (dayTextChanged == true)
{
break;
}
mItemDay = false;
DayVal = temp_dt.Cal_Date;
}
else
{
mItemDay = true;
}
if (e.Day.Date == Convert.ToDateTime(temp_dt.Cal_Date.ToString("d")))
{
switch (temp_dt.Cal_Type)
{
case "1" :
FontColor = "Blue";
break;
case "2":
FontColor = "Red";
break;
default:
FontColor = "Black";
break;
}
if (mItemDay == false)
{
strTemp = new StringBuilder();
}
else
{
strTemp.Append("<br>");
}
strTemp.Append("<span style='font-family:verdana;font-size:10px;font-weight:bold;color'");
strTemp.Append(FontColor);
strTemp.Append("'><br>");
strTemp.Append(temp_dt.Cal_Title.ToString());
strTemp.Append("</span>");
e.Cell.BackColor = System.Drawing.Color.Yellow;
dayTextChanged = true;
}
}
if (dayTextChanged == true)
{
e.Cell.Controls.Add(new LiteralControl(strTemp.ToString()));
}
}
}
So I need to display multiple Notes on same day...
So How can I do this??
Thanks in Advance....
Calendars are basically date pickers and using them to display data is one of the most common mistakes people make. Use a ListView to display your data/events; calendars were never meant for that.
At some stage the calendar cells are going to stretch as events are added for the same day, breaking the entire display. And if you try to set a limit, then people are going to complain and start asking why other events are listed and theirs aren't, etc.
In your code, you're basically swallowing the exception instead of handling it. Comment out the try-catch-finally (leave the Close()) and check what error you get then :)

Resources