this variable works fine if used by one user, but when used by two or more users then the "static" variable will be read by the next user, the first user instance when filling the gridview there are 5 rows of data and I try to access through other browser when entering the page, gridview on the second user already filled 5 rows of data in input by the first user. then how the solution to this problem? please see my code and give me an solutions. thanks.
static List<ServicesModels> _gridPackageDetail = new List<ServicesModels>();
private void AddListAction(string alfa, string beta)
{
ServicesModels data = new ServicesModels()
{
id_service_detail = Guid.NewGuid(),
scope_name = alfa,
detail_name= beta
};
_gridPackageDetail.Add(data);
}
public ActionResult GridPackageDetail()
{
ViewBag.DataListPackage = _gridPackageDetail.OrderBy(a => a.scope_name).ToList();
return PartialView();
}
my code in mvc3 controller.
The code is working fine, because this is what intended by "static", to have the same data for multi users. In your case you need to create a list or dictionary or multi-dimensional array (any data structure you are comfortABLE with) and save the data per use in it, and then retrieve the data when needed based on the user id.
static List<ServicesModels> _gridPackageDetail = new List<ServicesModels>();
private void AddListAction(string alfa, string beta)
{
ServicesModels data = new ServicesModels()
{
id_service_detail = Guid.NewGuid(),
scope_name = alfa,
detail_name= beta,
user_id = getTheID()// Get the id of the user
};
_gridPackageDetail.Add(data);
}
public ActionResult GridPackageDetail()
{
ViewBag.DataListPackage = _gridPackageDetail.OrderBy(a => a.scope_name && user_id ==getTheID()).ToList();
return PartialView();
}
replace getTheID() by your way of getting the id of the user.
This is used if you want to keep the data of all users. else you should remove the static keyword.
Related
I'm completely new to C# programming and I'm trying to learn on my own. Currently I'm building a mini-project to exercise.
I understand that the user layer should not have any data query for security reasons perhaps?
So I have created a separate Data Access class to retrieve data. This is what my data access class looks like(I'll be using stored procedures for better security once I learn how to use it):
public class DataAccess
{
public List<Customer> FilteredCustomersList(string name)
{
using (IDbConnection connection = new MySql.Data.MySqlClient.MySqlConnection(Helper.CnnVal("FineCreteDB")))
{
var output = connection.Query<Customer>($"SELECT * from `Customers` WHERE `Cust_Name` LIKE '{name}'").ToList();
return output;
}
}
Basically I send over a string from the user form to query the database, the data is retrieved and stored in a list. User form:
private void RetrieveData()
{
try
{
DataAccess db = new DataAccess();
filteredcustomers = db.FilteredCustomersList(CustomerNameTxtBox_AutoComplete.Text);
ntn_num = filteredcustomers.Select(x => x.Cust_NTN).ElementAt(0);
strn_num = filteredcustomers.Select(x => x.Cust_STRN).ElementAt(0);
address = filteredcustomers.Select(x => x.Cust_Address).ElementAt(0);
phone_num = filteredcustomers.Select(x => x.Cust_Phone).ElementAt(0);
id_num = filteredcustomers.Select(x => x.Cust_ID).ElementAt(0);
}
catch (Exception)
{
MessageBox.Show("Customer not found. If customer was recently added, try updating DB.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
DataAccess db = new DataAccess();
filteredcustomers = db.AllCustomersList();
ntn_num = "";
strn_num = "";
address = "";
phone_num = "";
}
}
On the user form side, "filteredcustomers" holds the list of data sent back, now here is the problem: I use the filteredcustomers list to extract the different column values like so:
address = filteredcustomers.Select(x => x.Cust_Address).ElementAt(0);
and then use them to populate the respective textboxes like:
Address_TxtBox.Text = address;
Everything works fine, but I don't want the userform to have these queries for all individual columns, because from what I've understood so far, this is bad programming and bad for security as well.
Can anyone guide me how I can keep the values in Data Access layer and just call them into my form?
I'm sorry if this is a long post, I'm just learning and wanted to be as detailed as possible.
You're already doing everything reasonably correctly as per how Dapper is to be used. Dapper doesn't maintain a local graph of entities from the db, track changes to it and automatically save them. If you want that, use something like EF
For dapper you retrieve data with a SELECT and send it back with an UPDATE
If you're only expecting one Customer for the name, do this:
var output = connection.QueryFirstOrDefault<Customer>($"SELECT * from `Customers` WHERE `Cust_Name` LIKE #n", new { n = name });
https://dapper-tutorial.net/queryfirst
This will return just one customer instance (or null; check it!) meaning you can tidy up your form code to:
c = db.FilteredCustomer(CustomerNameTxtBox_AutoComplete.Text);
ntn_num = c?.Cust_NTN;
strn_num = c?.Cust_STRN;
And so on
Your "if customer was recently added try updating db" doesn't really make sense- the query is done live, so the db is about as up to date as it can be
Here is the problem. User can come to set and enter in text in an upper and lower text box. After they have done so that text will then be stored in a datatable which will hold a Guid Id, a Title string, and a Body string.
How do I arrange it so that a if the page reloads (meaning the data gets sent to the data base) that if the user changes come text and hits submit again that the table will change accordingly and not make a new row.
I am thinking I will need an if statement to pull this off but I am not sure what to put within the statement. There is the code I have thus far in a .net mvc controller
[HttpPost]
public ActionResult ActName(ModelNameModel item)
{
if( ModelState.IsValid)
{
using (DB.DatabaseName db = new DB.DatabaseName())
{
DB.Model newRecord = new DB.Model();
newRecord.Title = item.Title;
newRecord.Body = item.Body;
newRecord.Id = Guid.NewGuid();
db.Models.Add(newRecord);
db.SaveChanges();
}
}
return View(item);
}
What other if statement can I use to verify the Guid Matches? Thank you!
public class MusicController : Controller
{
User currentUser;
public PartialViewResult UploadMusic()
{
return PartialView("_UploadMusic");
}
[HttpPost]
public ActionResult UploadMusic(List<HttpPostedFileBase> files)
{
EntityDBContext db = new EntityDBContext();
List<Song> uploadedSongs = new List<Song>();
foreach (var file in files)
{
if (file != null)
{
string songName = Path.GetFileName(file.FileName);
byte[] songAsBytes = new byte[file.ContentLength];
using (BinaryReader br = new BinaryReader(file.InputStream))
{
songAsBytes = br.ReadBytes(file.ContentLength);
}
//Save new record in database
Song song = new Song
{
SongName = songName,
SongBytes = songAsBytes
};
uploadedSongs.Add(song);
}
}
string userName = User.Identity.Name;
currentUser = db.Users.Where(x => x.Username == userName).First();
currentUser.UserSongs = uploadedSongs;
return ShowSongs(currentUser.UserSongs);
}
public ActionResult ShowSongs(List<Song> UserSongs)
{
return View("ShowSongs", UserSongs);
}
public ActionResult Publish()
{
EntityDBContext db = new EntityDBContext();
foreach (var song in currentUser.UserSongs)
{
if (song != null)
{
db.Songs.Add(song);
db.SaveChanges();
}
}
return View();
}
}
ShowSongs view:
#model List<Vidafo.Models.Song>
#Html.ActionLink("Publish", "Publish")
The Problem
So I declare currentUser at the top of the controller. I then assign a value to that with this line here currentUser.UserSongs = uploadedSongs; This works fine but when the code goes into Publish() currentUser.UserSongs is null.
I need to have access to currentUser.UserSongs in more than one action method after assigning a value but it seems that it resets to null when it enters another action.
Object state isn't maintained across requests, that's not how web applications work. Every time a request is sent to the server, a new instance of the controller object is created. So any instance-level values are new.
In order to persist information across requests you need to persist it somewhere. For something like a user context, session state is a common choice. You'll probably want to wrap it in a common provider interface so as to not couple your controllers to an HTTP context, but at its core storing in session is simple:
HttpContext.Current.Session["someKey"] = someValue;
(You could even re-fetch from the database with each request. It's slightly less performant, but very simple and robust.)
Don't count out the ASP.NET identity system for this, though. ASP.NET is pretty good at abstracting a lot of this for you. You're already using it here:
string userName = User.Identity.Name;
Then you use that value to get the user from the database. You could extend the identity system to store a custom user object which fits your needs. But that's a larger scope effort outside of this question.
For this you can make use of TempData i.e. store value in TempData dictionary. One problem here is MVC doesn't sore value of variable during postback i.e. during different action of same controller or calling another controller for this you can use temporary varialble TempData as suggested.
Currently, I'm sending some data to Parse.com. All works well, however, I would like to add a row if it's a new user or update the current table if it's an old user.
So what I need to do is check if the current Facebook ID (the key I'm using) shows up anywhere in the fbid column, then update it if case may be.
How can I check if the key exists in the column?
Also, I'm using C#/Unity.
static void sendToParse()
{
ParseObject currentUser = new ParseObject("Game");
currentUser["name"] = fbname;
currentUser["email"] = fbemail;
currentUser["fbid"] = FB.UserId;
Task saveTask = currentUser.SaveAsync();
Debug.LogError("Sent to Parse");
}
Okay, I figured it out.
First, I check which if there is any Facebook ID in the table that matches the current ID, then get the number of matches.
public static void getObjectID()
{
var query = ParseObject.GetQuery("IdealStunts")
.WhereEqualTo("fbid", FB.UserId);
query.FirstAsync().ContinueWith(t =>
{
ParseObject obj = t.Result;
objectID = obj.ObjectId;
Debug.LogError(objectID);
});
}
If there is any key matching the current Facebook ID, don't do anything. If there aren't, just add a new user.
public static void sendToParse()
{
if (count != 0)
{
Debug.LogError("Already exists");
}
else
{
ParseObject currentUser = new ParseObject("IdealStunts");
currentUser["name"] = fbname;
currentUser["email"] = fbemail;
currentUser["fbid"] = FB.UserId;
Task saveTask = currentUser.SaveAsync();
Debug.LogError("New User");
}
}
You will have to do a StartCoroutine for sendToParse, so getObjectID has time to look through the table.
It may be a crappy implementation, but it works.
What you need to do is create a query for the fbid. If the query returns an object, you update it. If not, you create a new.
I'm not proficient with C#, but here is an example in Objective-C:
PFQuery *query = [PFQuery queryWithClassName:#"Yourclass]; // Name of your class in Parse
query.cachePolicy = kPFCachePolicyNetworkOnly;
[query whereKey:#"fbid" equalTo:theFBid]; // Variable containing the fb id
NSArray *users = [query findObjects];
self.currentFacebookUser = [users lastObject]; // Array should contain only 1 object
if (self.currentFacebookUser) { // Might have to test for NULL, but probably not
// Update the object and save it
} else {
// Create a new object
}
I have a C# application where I need the list to "remember" what has been previously entered in it.
http://oi40.tinypic.com/2ivhcuw.jpg
So once the attendee has been added, the previous attendee will stay in the list if a new one is added. Currently it just displays the most recent attendee, I want them to save, until I decide to clear them (maybe in a session?)
List<Information> infoList = new List<Information>();
Information data = new Information();
firstName = resultEntry.Properties["givenname"].Value.ToString();
lastName = resultEntry.Properties["sn"].Value.ToString();
fullName = firstName + " " + lastName;
//data.CWID = resultEntry.Properties["username"].Value.ToString();
data.FullName = fullName;
// data.Email = resultEntry.Properties["email"].Value.ToString();
infoList.Add(data);
For storing items into a session:
Session["MyInformation"] = data;
receiving data out of a session
List<information> data = (List<information>)Session["MyInformation"];
But beware: Sessions ought to be forgotten.
One might consider viewstate but beware here to: viewstates do make a page slow. (easy testings in how big a html page gets when viewstate is added)
one last option might be to include cookies for getting a longer hold on the items.
Write a cookie: http://msdn.microsoft.com/en-us/library/78c837bd(v=vs.100).aspx
Read a cookie : http://msdn.microsoft.com/en-us/library/bd70eh18(v=vs.100).aspx
another option is to hold the data in database => this however means more traffic.
(also a small hint on the sessions, place them in a seperate static class so you can get them through the whole project instead of one page
public static class MySessions
{
public static List<Information> MyData
{
get{
//EDIT in the GET
if(HttpContext.Current.Session["MyInformation"] != null)
return (List<information>)HttpContext.Current.Session["MyInformation"];
else
{
HttpContext.Current.Session["MyInformation"] = new List<Information>();
return new List<Information>();
}
}
set{HttpContext.Current.Session["MyInformation"] = value;}
}
}
EDIT:
use the class as follows: (it's a static class, by entering the classname followed by the property, you can call for it instead of first instantiating the class.
//Set the value from Somewhere
MySessions.MyData = new List<Information>();
//get the values from somewhere
var myInfo = MySessions.MyData;
Depending on the length of the duration of "saving":
Use ViewState - if you want the list to be empty on a page load (not postback). (i.e. ViewState["data"] = infoList)
Use Session - if you want to manually empty the list based on some condition.