I am creating a web application using ASP.NET MVC 4.
I want to display the user's nickname on all of pages, so I have to load it in _layout.cshtml.
Please note that I'm storing user's nickname manually. (In my own database and my own tables.)
I can add user's User name by Membership.GetUser().UserName, but I want to load his nickname from database and show it in _layout.cshtml.
How to do that?
Let me give a simple solution for what you want:
write an action in a controller (mine is CommonController):
public ActionResult NickName()
{
SqlConnection cn = new SqlConnection(cnstr);
SqlCommand cmd = new SqlCommand(cmdStr, cn);
cn.Open();
SqlDataReader dr = cmd.ExecuteReader();
string nickName = string.Empty;
while (dr.Read())
{
nickName = dr["nick_Name"].ToString();
}
dr.close()
return Content(nickName);
}
put the below line in everywhere you want in _Layout:
nickname = #{Html.RenderAction("NickName", "Common");}
Finished!
Thanks to #SergRogovtsev for recommending:
nickname = #Html.Action("NickName", "Common")
first asked:
Are you using entity framework?
You can use partial views in _Layout either using EF or ADO.
If you mean you can't access aspnet_membership table by using entity framework, you should ask your question in another way!
let me know more about your problem by giving some sample of your code.
I would advise you to upon logging in, store the username in a session variable (which is done by accessing the Session object, which implements a key=value pair architecture allowing you to store and retrieve your data at will). It's a drag on performance to have to make a database call for EVERY page that loads, and a single nickname string variable in session won't take up that much space on your server.
As far as loading the variable you could use the code posted by Vahid, but I would recommend you if your site is still in its infancy to take the extra time to learn and implement Entity Framework. It is cleaner, easier and Microsoft is really pushing data connection management in that direction.
I have used a combination of Mr_Creostoe and Vahid answers.
I am saving nickname in a session (as Mr_Cresotoe said), and if there isn't such session (for example, if user ticked remember me checkbox and is visiting after many time), I'll create that session using RenderAction. (As Vahid said).
Thank you guys!
Related
We have a website in classic asp that we are slowly migrating to ASP.NET as necessary.
The problem of course is how classic asp and ASP.NET handle Sessions. After spending the last few hours researching the web, I found many articles, but not one that stood out over the others.
Is there a best practice for transferring session variables from and to classic asp and asp.net? Security is a must and any explanation with examples is much appreciated.
A simple bridge to pass a single session variable from classic asp to .net serverside (hiding your sessionvalue from the client), would be this:
On the ASP end: An asp page to output your session, call it e.g. asp2netbridge.asp
<%
'Make sure it can be only called from local server '
if (request.servervariables("LOCAL_ADDR") = request.servervariables("REMOTE_ADDR")) then
if (Request.QueryString("sessVar") <> "") then
response.write Session(Request.QueryString("sessVar"))
end if
end if
%>
On the .net end, a remote call to that asp page. :
private static string GetAspSession(string sessionValue)
{
HttpWebRequest _myRequest = (HttpWebRequest)WebRequest.Create(new Uri("http://yourdomain.com/asp2netbridge.asp?sessVar=" + sessionValue));
_myRequest.ContentType = "text/html";
_myRequest.Credentials = CredentialCache.DefaultCredentials;
if (_myRequest.CookieContainer == null)
_myRequest.CookieContainer = new CookieContainer();
foreach (string cookieKey in HttpContext.Current.Request.Cookies.Keys)
{
' it is absolutely necessary to pass the ASPSESSIONID cookie or you will start a new session ! '
if (cookieKey.StartsWith("ASPSESSIONID")) {
HttpCookie cookie = HttpContext.Current.Request.Cookies[cookieKey.ToString()];
_myRequest.CookieContainer.Add(new Cookie(cookie.Name, cookie.Value, cookie.Path, string.IsNullOrEmpty(cookie.Domain)
? HttpContext.Current.Request.Url.Host
: cookie.Domain));
}
}
try
{
HttpWebResponse _myWebResponse = (HttpWebResponse)_myRequest.GetResponse();
StreamReader sr = new StreamReader(_myWebResponse.GetResponseStream());
return sr.ReadToEnd();
}
catch (WebException we)
{
return we.Message;
}
}
I've used an ajax bridge (for want of a better term), specifically, a classic asp page that reads all session vars into a database with a guid, it then redirects to a .net page passing the guid in the querystring, the asp.net page reads from sql for the given guid and created those vars as sessions.
Eg, in classic asp (pseudocode code - just to give you an idea, use parameterised queries in yours etc):
'#### Create GUID
Dim GUID 'as string
GUID = CreateWindowsGUID() '#### Lots of methods on http://support.microsoft.com/kb/320375
'#### Save session to sql
For Each SessionVar In Session.Contents
db.execute("INSERT INTO SessionBridge (GUID, Key, Value) VALUES ('" & GUID & "', '" & SessionVar & "', '" & session(SessionVar) & "')")
Next
Then, in a .net page:
'#### Fetch GUID
Dim GUID as string = Request.QueryString("GUID")
session.clear
'#### Fetch from SQL
db.execute(RS, "SELECT * FROM SessionBridge WHERE GUID = '" & GUID & "'")
For Each db_row as datarow in RS.rows
Session(db_row("Key")) = db_row("Value")
Next
As i say, this is very rough pseudocode, but you can call the asp with a simple background ajax function, then call the .net page for the given GUID.
This has the advantage of not exposing all your vars and values to the client (as post methods do etc).
They use different sessions, so you'll need to devise some way of transferring the vars yourself. You could include them in cookies, or send them via HTTP POST (i.e. a form with hidden fields) to the asp.net side.
Alternatively, you could scrap using session storage and stick everything in a database for each user/session, then just pass a session key from classic ASP to ASP.NET via one of the above suggestions. I know this sounds like you're reinventing the wheel, but this might be one of those cases where you just can't get around it.
I have a website that does that exact action. The secret is to use an intermediate page with the asp function response.redirect
<%
client_id = session("client_id")
response.redirect "aspx_page.aspx?client_id=" & client_id
%>
This is an example to pull the classic asp session variable client_id and pass it to an aspx page. Your aspx page will need to process it from there.
This needs to be at the top of a classic asp page, with no HTML of any type above. IIS will process this on the server and redirect to the aspx page with the attached query string, without sending the data to the client machine. It's very fast.
In case anyone else stumbles here looking for some help, another possible option is to use cookies. The benefit of a cookie is that you can store reasonable amounts of data and then persist that data to your .Net application (or another web application). There are security risks with exposing a cookie since that data can be easily manipulated or faked. I would not send sensitive data in a cookie. Here the cookie is only storing a unique identifier that can be used to retrieve data from a table.
The approach:
Grab the session data you need from your classic asp page. Store
this data in a table along with a unique hash and a timestamp.
Store the value of the hash in a short-lived cookie.
Redirect to whatever page you need to go and read the hash in the cookie.
Check that the hash in the cookie hasn't expired in the database. If it is valid, send back the data you need to your page and then expire the hash so it can't be reused.
I used a SHA 256 hash that was a combination of the user's unique identifier, session ID, and current timestamp. The hash is valid for only a few minutes and is expired upon reading. The idea is to limit the window for an attacker who would need to guess a valid hash before it expired.
I don't know how to loop through my local database and add the values to this string:
string credentials = #"server = 127.0.0.1;
user id = system;
port = 3308;
Password = 975315";
https://i.imgur.com/6B4YFw7.png
I kind of need something like this:
string credentials = #"server = IDindb;
user id = IDindb;
port = Portindb;
Password = Pwindb";
foreach(rowofdata in localdb)
{
MySqlConnection con = new MySqlConnection(credentials);
con.Open(); //Opens the connection
MySqlCommand cmd = new MySqlCommand(sqlQuery, con); //Sends the
query to "show slave status"
Create a new table in browser that shows if server is running or not.
}
This is quite a good homework assignment - It touches frontend, database, networking and middleware, and importantly it forces you to properly think through all the little decisions of what might go wrong, e.g.
what do you do when the server doesn't respond (write "server down
into your html table)
how do you trap this without your own code failing.
What if the servers take a really long time to respond? Timeout?
Should you be doing this to each server in succession, or
all at once, adding their responses into the table as you go?
What I'm saying is you should think about your overall solution some more before diving into the code.
To answer the question, assuming you have some code to connect to the local db and query the table, rowofdata will be a recordset, with each row populated per the row in your image.
Extract the server, user, password etc credentials from it:
var masterHost = rowofdata["Master_Host"].ToString();
and create the connection string inside the for-loop.
var credentials = $"server={masterHost};user id={userId}; port={portId}; Password={password}";
The Create new Table in browser part will depend on which platform/language you're writing in. And in any case shouldn't be done here, unless you're intent on mixing db access with html (#Razor? classic asp?).
Store the server / status values in a list (of server object, with status etc), then subsequently use them to populate the html.
(Or build the html table and render that, and use ajax to request the status of each).
(unrelated - how do you plan on implementing the stop/start/fix button code?)
There seems to be no answer online as to how you can use Oracle Data Provider for .NET (ODP.NET) to connect to Oracle (12G and later) in a very specific scenario:
User is identified externally on a database
User is granted access to another schema (application user) by proxy connect
User has been set up like this:
CREATE USER user_in_question
IDENTIFIED EXTERNALLY
-- etc.
And connect by proxy has been set up like this:
ALTER USER specified_app_user GRANT CONNECT THROUGH user_in_question
The logical approach when creating the ODP.NET OracleConnection string would be something like this (using the user friendly OracleConnectionStringBuilder):
var connBuilder = new OracleConnectionStringBuilder
{
UserID = "/", // External login using the user running the program
ProxyUserId = "specified_app_user",
DataSource = "database",
};
This does not work. Nor does providing blank "Password" or blank "Proxy Password". Nor does removing the UserId.
So how do you connect using ODP.NET in these circumstances?
The answer (which I spend an hour searching for without any luck) is actually really simple, yet not very user friendly:
var connBuilder = new OracleConnectionStringBuilder
{
UserID = "[specified_app_user]",
DataSource = "database",
};
//connBuilder.ToString() output:
//"USER ID=[specified_app_user];DATA SOURCE=database"
This works in .NET 4.5+ on Oracle 12G+, but probably also on earlier platforms of .NET/Oracle/ODP.NET. I did not test it in ASP.NET, but it should work there too.
This way the UserId actually functions just like the ProxyUserId, just enclosed within brackets, just as you would normally log in on the Oracle Database using, say, Toad or SQlPlus.
It might also be possible using this format (but in my case the connection string had to be compatible with the OraOLEDB format so that did not work):
//Without the use of the conn string builder class, just for the fun of it...
var connString = "User Id=specified_app_user;Data Source=database;Proxy User Id=/";
EDITED 2nd March 2017: The line above does not seem to work in certain cases. Added comment about it and here is the code that IS working:
USER ID=[specified_app_user];DATA SOURCE=database
This info does not seem to exist anywhere - else I overlooked it, and in that case PLEASE do correct me.
I'm struggling with API calls of Kentico forms using ASP.NET MVC, so that I can use AngularJS to display the return data (JSON format).
Specifically, my client is using Kentico on their server to create data using "Forms" on Kentico and I want to get the records stored in these forms via API calls using ASP.NET MVC. What I'm thinking is that in the general section of the "Forms", I see the "Form code name" showing that "Code name is a string identifier of the object that can be used by developers in API calls or URLs". But it seems to be there's no good example of it on internet. Keep trying to search it but no luck. I also tried to access data directly in SQL Server in which kentico stores the data. But the table's name that Kentico uses in SQL Server to store the data is different from the ones in "Forms" or "Custom tables" in Kentico.
Hope someone can show me how to do it and I really appreciate it. Thanks in advance.
There is a very good example in the official documentation of Kentico.
Please note that Forms have been renamed a few times in the past (they were called BizForms and On-Line forms) that's the reason why the code below references CMS.OnlineForms and uses BizFormInfoProvider. It might also very well be the reason why you didn't find any good example :)
The example below shows how to retrieve Form's definition (metadata), get all the data and iterate through it.
using CMS.OnlineForms;
using CMS.DataEngine;
using CMS.SiteProvider;
using CMS.Helpers;
...
// Gets the form info object for the 'ContactUs' form
BizFormInfo formObject = BizFormInfoProvider.GetBizFormInfo("ContactUs", SiteContext.CurrentSiteID);
// Gets the class name of the 'ContactUs' form
DataClassInfo formClass = DataClassInfoProvider.GetDataClassInfo(formObject.FormClassID);
string className = formClass.ClassName;
// Loads the form's data
ObjectQuery<BizFormItem> data = BizFormItemProvider.GetItems(className);
// Checks whether the form contains any records
if (!DataHelper.DataSourceIsEmpty(data))
{
// Loops through the form's data records
foreach (BizFormItem item in data)
{
string firstNameFieldValue = item.GetStringValue("FirstName", "");
string lastNameFieldValue = item.GetStringValue("LastName", "");
// Perform any required logic with the form field values
// Variable representing a custom value that you want to save into the form data
object customFieldValue;
// Programatically assigns and saves a value for the form record's 'CustomField' field
item.SetValue("CustomField", customFieldValue);
item.SubmitChanges(false);
}
}
UPDATE:
The example above assumes that you're using the API from within the running Kentico instance. If you want to use Kentico API (DLLs) from an external application please follow the steps I described in another answer.
You also asked about the site identifier (siteId or siteName params of the BizFormInfoProvider.GetBizFormInfo() method). They refer to the SiteInfo object in Kentico (DB table CMS_Site). You can find site name if you navigate to Site->Edit site->General->Site code name.
If you don't want to use Kentico DLLs there is another option - using Kentico REST endpoint.
In the class I execute a stored procedure and return a DataTable.
public DataTable getUserInfo(int abid)
{
DataTable tbl = new DataTable();
string constring =ConfigurationManager.ConnectionStrings["myconn"].ConnectionString;
using (SqlConnection con = new SqlConnection(constring))
{
using (SqlCommand cmd = new SqlCommand("getUserInfo", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#ABID", abid);
SqlDataAdapter adap = new SqlDataAdapter(cmd);
adap.Fill(tbl);
}
}
return tbl;
}
Then in the code behind of the default.aspx.cs page I call the class and using a foreach loop I get all the data I need.
DataTable tbl = new DataTable();
tbl = u.getUserInfo(abid);
foreach (DataRow row in tbl.Rows)
{
string firstName = row["firstName"].ToString();
string lastName = row["lastName"].ToString();
string fullname = row["fullname"].ToString();
string Phone = row["phone"].ToString();
}
This solution works if I only had to use the data in this page only. I need the same data to use in different pages in the project. Of course, I could call the class every time and create different data tables and store them in different variables, but I know it's not very efficient. I'm sure there's a better way to do this.
Is there a way that I could create global variables? For instances I load the datatable into those variables and I can use them throughout the project? Or any other solution?
Thanks
If that data is shared among different users then use Cache object. See: ASP.NET Caching: Techniques and Best Practices.
But if that data is unique to each user then store that information in a Session object. But remember, Sessions are maintained for each user on Server, If you keep too much data in Session then it will require more resources from the Server.
See: ASP.NET Session State Overview
To store information in Session
//To store
Session["UserInfo"] = tbl;
To retrieve
DataTable tbl = Session["UserInfo"] as DataTable;
if (tbl != null)
{
//Datatable found;
}
Session object can be accessed on multiple pages.
You also have other options to maintain state across pages in ASP.Net, like Cookies. See
ASP.NET State Management Overview
Web is stateless, which means a new instance of a web page class is re-created each time the page is posted to the server. As we all know, HTTP is a stateless protocol, it can't hold client information on a page.
If the user inserts some information and move to the next page, that data will be lost and the user would not be able to retrieve that information. We need to store information. Session provides a facility to store information on server memory. It can support any type of object to store along with our own custom objects. For every client, session data is stored separately, which means session data is stored on a per client basis. Have a look at the following diagram:
State management using session is one of the best ASP.NET features, because it is secure, transparent from users, and we can store any kind of object in it.
Advantages:
It helps maintain user state and data all over the application.
It is easy to implement and we can store any kind of object.
Stores client data separately.
Session is secure and transparent from the user.
Disadvantages:
Performance overhead in case of large volumes of data/user, because session data is stored in server memory.
Overhead involved in serializing and de-serializing session data, because in the case of StateServer and SQLServer session modes, we need to serialize the objects before storing them.
Reference:
1.http://www.codeproject.com/Articles/32545/Exploring-Session-in-ASP-Net
I suggest that you implement a lazy-loading solution to this.
Since static member are shared across all requests to the application, you can cache data that you know isn't going to change. Obviously you have to be careful about caching too much or for too long, or you're going to run int RAM issues. You'll also have to consider concurrency.
Here's a simplified example: create a class that represents a user, and then create a static method, LoadByID(int id), and a static Dictionary to stored already-loaded users. Then, when a page requests a user, serve them the item from the cache if it already exists.
//... user instance fields ...
private static Dictionary<int, User> cache = new Dictionary<int, User>();
private static object lockObj = new object();
public static User LoadByID(int id)
{
lock (lockObj) //Prevent double-adding items
{
if (cache.ContainsKey(id))
{
return cache[id]; //We've already loaded the record.
}
else
{
//Some function that actually calls the database
//and constructs user objects
User loaded = LoadUserInternal(id);
cache.Add(id, loaded)
return loaded;
}
}
}
private static User LoadUserInternal(int id)
{
//Load and construct the user
}