I am developing my Razor.Pages web application in .Net Core 3.1 and I configured the authentication using my company AD. I can use without any problem the User.Identity.Name to get the user#domain value but I need to get the full name of the person that is logged in so that I can filter some results of a query to an SQL DB based on the user's full name.
I tried googling around but didn't find anything a solution to my problem. Thanks!
After doing some digging around I finally managed to create a method that receives the User.Identity.Name of the logged in user and returns the full name.
Bellow is a snippet of the method!
public static string GetFullName(string domainName)
{
string fullName = "";
UserPrincipal principal;
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
principal = UserPrincipal.FindByIdentity(ctx, domainName);
}
if (principal != null)
fullName = $"{principal.GivenName} {principal.Surname}";
else
fullName = domainName;
return fullName;
}
I want to allow people by registering with their email id, password and confirming password in my asp.net 4.0 application. How can I send the confirmation link to their entered email, and there by showing the profile strength in their individual profiles? with the backend as sql server 2010
You have to send the confirmation link with unique confirmation id as query string parameter in link. When user clicks on that link you can validate that link for -
Is link already used?
Is link has valid confirmation number.
Then if it is valid link then allow user to confirm there email id. The unique confirmation id needs to be stored in the database for given email id. So that you can validate for it. Also in the same database table you can have additional field where it will record the time stamp when that id is generated and email send to user.
Introduction
Authentication and authorization as fundamental part of a web application was tremendously simplified with arrival of .NET 2.0. Basic authentication and authorization can be performed using different DBMS systems. There are numerous examples implementing authentication using Access database. One such example can be found in the article ASP.NET 2.0 Authentication using Access Database. In this article the example implements bare minimum to achieve desired goal, namely authentication and authorization using access database. However, authentication and authorization is only first part of the user management system. Second fundamental part of user management is allowing users to create an account at will. In such instances, users can sign up and become members of the community without administrator intervention. Furthermore, the user should be able to provide contact information (email) so that he/she can be contacted if necessary. Contact information must be verified. This article focuses on very simple ways to achieve such goal.
CreateUserWizard
As already suspected, .NET 2.0 provides necessary tools for quick and effective implementation of user registration. The component of interest is CreateUserWizard control that can be found under Login components. CreateUserWizard component provides preformatted set of components that provide the user with opportunity to enter necessary information. By default, CreateUserWizard provides user with option to enter name, password, email, security question, and answer to security question. In addition, CreateUserWizard provides the user with function to reenter the password to confirm user intentions.
In our example, we will focus on minimalistic approach to implement user signup and email conformation. As such we will not implement security question, but rather focus on username, password, and email to be confirmed. This article is continuation of ASP.NET 2.0 authorization using Access Database and it reuses Role and Membership provider code as presented in that article. Here, I’ll only present additions to the above mentioned article. In addition, full source code is included and demonstration can be found in demo section.
Extending Roles and Membership Providers
As already mentioned, I’ll focus on additional implementation necessary for CreateUserWizard implementation. Methods implemented in ASP.NET 2.0 authentication and authorization using Access Database are explained in mentioned article. However, there are some modifications that will be stressed at relevant time.
Looking at AccessMembershipProvider, I quickly realized that there are multiple methods that must be implemented to correctly use CreateUserWizardcontrol. First we need to be able to eliminate security question option. In order to eliminate security question, membership provider must return false for RequiresQuestionAndAnswer property of membership provider. Implementation of this property is similar to implementation of connection string property. We simply add variable of type bool that retrieves its value from web configuration file. Web configuration file must contain requiresQuestionAndAnswer as shown below:
<membership defaultProvider="AccessMembershipProvider">
<providers>
<clear/>
<add name="AccessMembershipProvider"
type="AccessProvider.AccessMembershipProvider"
connectionStringName="UsersDB"
requiresQuestionAndAnswer="false"/>
</providers>
</membership>
And the setting is parsed within Initialize method as following:
public override void Initialize(string name,
System.Collections.Specialized.NameValueCollection config)
{
base.Initialize(name, config);
m_strDBConnection =
ConfigurationManager.ConnectionStrings[config["connectionStringName"]].ConnectionString;
m_bRequiresQuestionAndAnswer =
(config["requiresQuestionAndAnswer"].ToLower().CompareTo("true") == 0);
}
As we can see, the code above simply extracts the setting from the web.config file and applies it to appropriate property. CreateUserWizard control reads the same property and displays security question according to the property value. Now that security question does not have to be entered, we can look at what happens when user enters the data and tries to create a user. Through experiment, I realized that the AccessMembershipProvider method CreateUser is called (obviously). Intuitively, I concluded that this method is responsible for the code that adds the user to the database. Following is method implementation:
public override MembershipUser CreateUser(string username, string password, string email,
string passwordQuestion, string passwordAnswer,
bool isApproved, object providerUserKey,
out MembershipCreateStatus status)
{
MembershipUser user = null;
using (OleDbConnection conn = new OleDbConnection(m_strDBConnection))
{
try
{
OleDbCommand command = new OleDbCommand("INSERT INTO Users " +
"(UUSERNAME, UPASSWORD, EMAIL, PROVIDER_KEY) "+
"VALUES (#Param1, #Param2, #Param3, #Param4)",
conn);
Guid guid = Guid.NewGuid();
command.Parameters.AddWithValue("#Param1", username);
command.Parameters.AddWithValue("#Param2", password);
command.Parameters.AddWithValue("#Param3", email);
command.Parameters.AddWithValue("#Param4", guid.ToString());
conn.Open();
command.ExecuteNonQuery();
string[] users = {username};
Roles.AddUsersToRole(users, "User");
conn.Close();
user = new MembershipUser("AccessMembershipProvider",
username, guid, email, null, null, false, false,
DateTime.Now, DateTime.Now, DateTime.Now,
DateTime.Now, DateTime.Now);
status = MembershipCreateStatus.Success;
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
status = MembershipCreateStatus.UserRejected;
}
}
return user;
}
CreateUser method simply adds the user to the database and returns MembershipUser object filled with the information as entered in CreateUserWizard. My first implementation of the method did not include adding the user to the “User” group using role provider. However, later investigation showed that the user was simply added without group assignment. Realizing that the user must be in a group, I added the following implementation to AccessRoleProvider code:
public override void AddUsersToRoles(string[] usernames, string[] roleNames)
{
using (OleDbConnection conn = new OleDbConnection(m_strDBConnection))
{
try
{
for (int i = 0; i < usernames.Length; ++i)
{
OleDbCommand command = new OleDbCommand("INSERT INTO UsersInRoles "+
"(ROLE_NAME, UUSERNAME) "+
"VALUES (#Param1, #Param2)",
conn);
command.Parameters.AddWithValue("#Param1", roleNames[i]);
command.Parameters.AddWithValue("#Param2", usernames[i]);
conn.Open();
command.ExecuteNonQuery();
conn.Close();
}
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
}
}
Now that the user is added to the database and assigned to appropriate group, we need to implement code to confirm user information, particularly email. Searching through MSDN documentation I found that CreateUserWizard provides method for automatic email notification. However, such approach was not appropriate because of lack of information provided within the event. Our conformation will utilize GUID that is written to DB when the user is created. The user will be activated only when the activation with such GUID is performed. Finding out GUID was impractical using send email event and easier solution was found, namely CreatedUser event of CreateUserWizard component.
Email Notification
As already mentioned, the user should be able to use the account only after successful email conformation. For conformation, the user should receive an email containing the link that will automatically activate the account. Once the account is activated, the account is ready to be used. Following is CreatedUser event implementation:
protected void CreateUserWizard1_CreatedUser(object sender, EventArgs e)
{
CreateUserWizard wizard = (CreateUserWizard)sender;
MembershipUser user = Membership.GetUser(wizard.UserName);
if (user != null)
{
try
{
SmtpClient smtpClient = new SmtpClient("smtpServer");
smtpClient.UseDefaultCredentials = true;
smtpClient.Send("yourEmail", user.Email, "Account Conformation Email",
"hst/Confirm.aspx?id="+user.ProviderUserKey.ToString());
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
}
}
Implementation of email notification is very simple. This is due to the fact that .NET library provides very simple means to communicate with any SMTP server. It is important to note the line smtpClient.UseDefaultCredentials = true. In this way, smtpClient object looks into web.config for SMTP server settings, i.e. username, password, and the host to be used. Following section is expected by SmtpClient object to be present in web.config file:
<system.net>
<mailSettings>
<smtp>
<network
host="smtp.hst.com "
userName="username"
password="password" />
</smtp>
</mailSettings>
</system.net>
Settings are self explanatory. The smtpClient simply needs the host name, username, and password to be used. Once the user is created, CreatedUser event is raised and email is sent. The content of the email is simply a link to Confirm.aspx page with an id parameter. The id parameter is GUID assigned specifically for that user. It is important to note that username could be used too, but GUID provides slightly more security.
Another extension necessary for CreatedUser event to function properly is capability of AccessMembershipProvider object to be able to provide user information based on username. In order to achieve such functionality, AccessMembershipProvider contains method that takes username as parameter and reads user information from database. Following is implementation:
public override MembershipUser GetUser(string username, bool userIsOnline)
{
MembershipUser user = null;
using (OleDbConnection conn = new OleDbConnection(m_strDBConnection))
{
try
{
/* Create command */
OleDbCommand command =
new OleDbCommand("SELECT UUSERNAME, PROVIDER_KEY, EMAIL FROM Users " +
"WHERE UUSERNAME=#Param1", conn);
command.Parameters.AddWithValue("#Param1", username);
/* Open connection */
conn.Open();
/* Run query */
OleDbDataReader reader = command.ExecuteReader();
/* Check if we have something */
bool bResult = reader.HasRows;
if (bResult)
{
reader.Read();
user = new MembershipUser("AccessMembershipProvider", reader.GetString(0),
new Guid(reader.GetString(1)),
reader.GetString(2), "", "", true, false,
DateTime.Now, DateTime.Now, DateTime.Now,
DateTime.Now, DateTime.Now);
}
/* Close connection */
conn.Close();
return user;
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
return user;
}
}
Once again, the implementation is trivial. We simply find info about user with specified username by running query against our users table.
Email Confirmation
Once the email is sent the user receives an email with a link to confirm his/her signup and email. The link is of the form http://"hst"/Confirm.aspx?id=XXXXXXXXXXXXXXXXXX, where XXXXXXXXXXXXXXXX is GUID determined in CreateUser method. Once the user clicks on the email the browser loads Confirm.aspx page with appropriate parameter. As suspected, Confirm.aspx is responsible for account activation. The account activation is performed by modifying ACTIVATED flag within user table. Following is Confirm.aspx implementation:
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["id"] != null)
{
using (OleDbConnection conn = new OleDbConnection(
ConfigurationManager.ConnectionStrings["UsersDB"].ConnectionString))
{
try
{
OleDbCommand command =
new OleDbCommand("UPDATE Users SET ACTIVATED=#Param1 "+
"WHERE PROVIDER_KEY=#Param2", conn);
command.Parameters.AddWithValue("#Param1", true);
command.Parameters.AddWithValue("#Param2", Request.QueryString["id"]);
conn.Open();
command.ExecuteNonQuery();
conn.Close();
Response.Write("Your account has been activated. "+
"Please log in <a href='Default.aspx'>here</a>");
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
}
}
}
The implementation is self explanatory. The code simply modifies activated flag of the user with specified GUID.
At this point it is important to state somewhat obvious fact. The AccessMembershipProvider’s ValidateUser method must be modified to consider activated flag. In other words, only activated users can be validated and consequently logged in. For completeness, following is the implementation:
public override bool ValidateUser(string username, string password)
{
using (OleDbConnection conn = new OleDbConnection(m_strDBConnection))
{
try
{
/* Create command */
OleDbCommand command = new OleDbCommand("SELECT UUSERNAME, UPASSWORD FROM Users " +
"WHERE UUSERNAME=#Param1 " +
"AND UPASSWORD=#Param2 " +
"AND ACTIVATED=#Param3",
conn);
command.Parameters.AddWithValue("#Param1", username);
command.Parameters.AddWithValue("#Param2", password);
command.Parameters.AddWithValue("#Param3", true);
/* Open connection */
conn.Open();
/* Run query */
OleDbDataReader reader = command.ExecuteReader();
/* Check if we have something */
bool bResult = reader.HasRows;
/* Close connection */
conn.Close();
return bResult;
}
catch (Exception ex)
{
System.Diagnostics.Trace.WriteLine(ex.Message);
}
return false;
}
}
Access Database
Access database utilized is extended version of the database utilized in ASP.NET 2.0 Forms Authentication article with addition of GUID and ACTIVATED fields. GUID is stored in PROVIDER_KEY field. In addition, some fields like username and password had to be renamed because of the conflict with Access DB system.
Source
Click here to demo
I created one database and tables to store the user login values and credentials.
asp.net is providing aspnet_regsql tool to create a database for the membership related activities. But I dont want to use it. Thats why I created another database. Now I want to connect this database to my project. I changed in web.config file for the connectionstring parameter to my newly created database. But I am unable to login. It is giving following error message.
Could not find stored procedure 'dbo.aspnet_CheckSchemaVersion'
How to work with this. Is there any step by step procedures are there!! If so please provide.
Is there any thing to change rather than the connection string in the web.config file?
You need to create a membership provider to connect to your custom tables for authentication. MSDN has some documentation on the subject. You can also view a video on the subject at ASP.NET. Here are the links.
http://msdn.microsoft.com/en-us/library/f1kyba5e(v=vs.100).aspx
http://www.asp.net/web-forms/videos/how-do-i/how-do-i-create-a-custom-membership-provider
The main method for validation is going to be the ValidateUser method, you will override this method to provide authentication.
public sealed class CustomMembershipProvider : MembershipProvider
{
// implement other methods
public override bool ValidateUser(string username, string password)
{
try
{
var user = // GET USER OBJECT HERE
if (user != null)
{
string name = // set username
// Set your forms authentication ticket
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, user.ID.ToString(), DateTime.Now, DateTime.Now.AddMinutes(30), false, name, FormsAuthentication.FormsCookiePath);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(ticket));
HttpContext.Current.Response.Cookies.Add(authCookie);
return true;
}
}
catch
{
}
return false;
}
// Other implementations
}
If you have roles in your application you may also want to implement a custom role provider:
http://msdn.microsoft.com/en-us/library/8fw7xh74(v=vs.100).aspx
I get an error by a website, on which I use Windows Authentication.
Strange things:
Only occurs if user is not yet saved into database (new unknown user)
Appears only on live system, everything fine on local development environment
This is what I get in a logging mail:
Source : System.DirectoryServices
Message: The server is not operational.
Trace:
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindOne()
at Smarthouse.Labs.DataAccess.UserListManager.SaveUser(String windowsUserName)
This is how I implement DirectorySearch:
private void SaveUser(string windowsUserName)
{
string[] domainAndUser = windowsUserName.Split('\\');
string domain = domainAndUser[0];
string username = domainAndUser[1];
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain);
DirectorySearcher search = new DirectorySearcher(entry);
try
{
// Bind to the native AdsObject to force authentication.
search.Filter = "(SAMAccountName=" + username + ")";
search.PropertiesToLoad.Add("cn");
search.PropertiesToLoad.Add("sn");
search.PropertiesToLoad.Add("givenName");
search.PropertiesToLoad.Add("mail");
SearchResult result = search.FindOne();
if (result == null)
{
throw new Exception("No results found in Windows authentication.");
}
User userToSave = new User();
userToSave.FirstName = (String) result.Properties["givenName"][0];
userToSave.LastName = (String) result.Properties["sn"][0];
userToSave.Email = (String) result.Properties["mail"][0];
userToSave.Username = windowsUserName;
userToSave.Guid = Guid.NewGuid();
SaveUser(userToSave);
}
catch (Exception ex)
{
throw new Exception("Error authenticating user. " + ex.Message, ex);
}
finally
{
//Dispose service and search to prevent leek in memory
entry.Dispose();
search.Dispose();
}
}
If more code examples are needed just tell me.
Your problem is that you're using a "plain" domain name to bind - this won't work in LDAP. Actually, if you try to bind to LDAP://MyDomain, what you're really doing is trying to bind to the server called MyDomain.
You need a valid LDAP bind string - something like LDAP://dc=yourdomain,dc=local or something.
To find out what your default LDAP binding context is, use this code snippet:
DirectoryEntry deRoot = new DirectoryEntry("LDAP://RootDSE");
if (deRoot != null)
{
string defaultNamingContext = deRoot.Properties["defaultNamingContext"].Value.ToString();
}
Once you have that string - use that as your bind string to your LDAP server.
And if you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context -- no domain name needed, uses default domain
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username);
if(user != null)
{
// do something here....
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
You can use bind strings in the format LDAP://mydomain.com:389. I kept getting "Access is Denied" when trying to use the format LDAP://DC=mydomain,DC=com. Once I switched to the LDAP://mydomain.com:389 format, and bound using the AuthenticationTypes.ServerBind flag when constructing my DirectoryEntry, it worked great. This was in Azure App Service.
To add to marc_s's answer above, I needed to search multiple domains.
So for each Domain I did the following:
DirectoryEntry deRoot = new DirectoryEntry("LDAP://" +"DomainName"+ "/RootDSE");
string defaultNamingContext = "LDAP://" + deRoot.Properties["defaultNamingContext"].Value.ToString();
DirectoryEntry mySearchRoot = new DirectoryEntry(defaultNamingContext);
DirectorySearcher myDirectorySearcher = new DirectorySearcher(mySearchRoot);
Similar Error Happened to me (though it happened all the time and not in specific cases like pointed out here) because of a wrong Active Directory connection string. i used the corp instead the prod one .
Use something that works for another app in your organization if exists.
Note: I DON't want to write custom membership provider.
I want to write my own Provider class so I can define it in web.config and access it like Membership class.
Here is a sample of my class (it has many other static methods):
public static class MySqlHelper
{
private static string constring = ConfigurationManager.ConnectionStrings["MyConnString"].ConnectionString;
public static int ExecuteNonQuery(string mysqlquery)
{
SqlConnection conn = new SqlConnection(connString);
SqlCommand cmd = new SqlCommand(mysqlquery, conn);
int result;
try
{
conn.Open();
result= cmd.ExecuteNonQuery();
}
finally
{
conn.Close();
}
return result;
}
}
Usage: MySqlHelper.ExecuteNonQuery("select * from customers");
Now as you see I have hard-coded the name of connectionstring i.e. "MyConnString". I am planning to make it dynamic.
So I was wondering if I can make it like static built-in Membership class, where I can define the connectionStringName in web.config. This way the class can be made re-usable without always naming my connectionstring in web.config to "MyConnString".
1: I DON'T want to pass connectionstring in every static method as a parameter.
2: I must be able to access the methods similar to Membership.CreateUser i.e. static.
I am looking over the web in parallel but any inputs/guidance will help.
Edited: I have updated my code sample, to clear some confusion about issues using static class. Here is a new question I posted to clarify that. Sorry about confusion.
the only thing i can think of that meets the qualifications you laid out is to use dependency injection, a static constructor, and inject in an something like an IConnectionStringProvider. this seems like about the most convoluted thing i can think of, so you might like it. :)
edit
after reading your comment, it seems like you just want to be able to reference any connection string, but only one connection string per application. i'd say just add an element to appSettings named MySqlProviderConnection with the value being the name of the connection string you want to use.
then in your helper, check for the existence of the appsetting, get its value, and pass it in to your ConfigurationManager.ConnectionStrings call. that way your provider could use any connection you want, without changing any code.
I typically discourage sharing one SqlConnection instance across several requests. Even if you enable MARS, you can run into performance issues. I think when your connection receives a non-read command, the connection buffer will pause all current reads until the write finishes. The only thing you're really saving is the time it takes to establish a connection.
SqlConnections are pooled so you can configure the provider to have a min / max number of instances available to soliciting clients. Keep in mind this is also controlled by whatever database you're connecting to; assuming you're connecting to a SQL Server instance, SQL Server has its own maximum connections allowed setting.
Instead of allowing clients to determine when to open/close a shared SqlConnection instance, I suggest having your public members take in either a command string or command parameters. Then, similar to what your sample has suggested, open a connection from the pool and execute the command.
public IEnumerable<SqlResults> ExecuteStoredProcedure(string procedure, params SqlParameter[] parameters) {
using(SqlConnection connection = new SqlConnection(MyConnectionStringProperty)) {
try {
connection.Open();
using(SqlCommand command = new SqlCommand(procedure, connection)) {
command.CommandType = CommandType.StoredProcedure;
if(parameters != null) {
command.Parameters.AddRange(parameters);
}
// yield return to handle whatever results from proc execution
// can also consider expanding to support reader.NextResult()
using(SqlDataReader reader = command.ExecuteReader()) {
yield return new SqlResults {
Reader = reader;
};
}
}
}
finally {
if(connection.State != ConnectionState.Closed) {
connection.Close();
}
}
}
}
The sample code above is just that - a sample of a concept I use at work. The sample does now have maximized error handling but is very flexible in how results are returned and handled. The SqlResults class simply contains a SqlDataReader property and can be expanded to include errors.
As far as making any of this static, it should be fine as long as you enable a way to make a singleton instance of the provider class and continue to not have any mutable properties be shared (potentially across various requests/threads). You may want to consider some sort of IoC or Dependency Injection approach for providing the connection string given your request.
EDIT
Yield allows the caller to use the returned object before the execution context returns to the method yielding the return for continued execution. So in the sample above, a caller can do something like this:
// Since it's an IEnumerable we can handle multiple result sets
foreach(SqlResults results in MySqlHelper.ExecuteStoredProcedure(myProcedureName, new SqlParameter("myParamName", myParamValue)) {
// handle results
}
without the connection closing while we handle the results. If you notice in the sample, we have using statements for our SqlClient objects. This approach allows result set handling to be decoupled from MySqlHelper as the provider class will take care of the would-be-duplicate SQL provision code, delegate result handling to the caller, then continue with what it has to do (i.e. close the connection).
As for IoC/DI, I personally use Castle Windsor. You can inject dependency objects as properties or construction parameters. Registering an Inversion of Control container as your dependency resource manager will allow you to (among other things) return the same object when a type of resource is requested. Basically, for every caller class that needs to use MySqlHelper, you can inject the same instance when the caller class is instantiated or when the caller class references its public MySqlHelper property. I, personally, prefer constructor injection whenever possible. Also, when I say inject, I mean you don't have to worry about setting the property value as your IoC/DI does it for you (if configured properly). See here for a more in depth explanation.
As another note, the IoC/DI approach would really only come into play if your class is non-static such that each application can have its own singleton instance. If MySqlHelper is static, then you could only support one connection string unless you pass it in, which in your original question, you'd prefer not to do so. IoC/DI will allow you to use your MySqlHelper property member as if it were static though since the registered container would ensure that the property has a proper instance.
Here is the complete code of a SqlHelper that I'd used on some small projects.
But carefull with static for this kind of class. If you will use it for Web project, remember that the connection will be shared at the same instance for all users, which can cause bad problems...
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;
public class SqlHelper
{
private SqlConnection connection;
public SqlHelper()
{
connection = new SqlConnection();
}
public void OpenConnection()
{
// Updated code getting the ConnectionString without hard naming it.
// Yes, if you have more than 1 you'll have problems... But, how many times it happens?
if (WebConfigurationManager.ConnectionStrings.Length == 0)
throw new ArgumentNullException("You need to configure the ConnectionString on your Web.config.");
else
{
connection.ConnectionString = WebConfigurationManager.ConnectionStrings[0].ConnectionString;
connection.Open();
}
}
public void CloseConnection()
{
if (connection != null && connection.State != ConnectionState.Closed)
connection.Close();
}
public DataTable ExecuteToDataTable(string sql)
{
DataTable data;
SqlCommand command = null;
SqlDataAdapter adapter = null;
try
{
if (connection.State != ConnectionState.Open)
OpenConnection();
command = new SqlCommand(sql, connection);
adapter = new SqlDataAdapter(command);
retorno = new DataTable();
adapter.Fill(data);
}
finally
{
if (command != null)
command.Dispose();
if (adapter != null)
adapter.Dispose();
CloseConnection();
}
return data;
}
public int ExecuteNonQuery(string sql)
{
SqlCommand command = null;
try
{
if (connection.State != ConnectionState.Open)
OpenConnection();
command = new SqlCommand(sql, connection);
return command.ExecuteNonQuery();
}
finally
{
if (command != null)
command.Dispose();
CloseConnection();
}
}
public object ExecuteScalar(string sql)
{
SqlCommand command = null;
try
{
if (connection.State != ConnectionState.Open)
OpenConnection();
command = new SqlCommand(sql, connection);
return command.ExecuteScalar();
}
finally
{
if (command != null)
command.Dispose();
CloseConnection();
}
}
}
Sample usage:
SqlHelper sql = new SqlHelper();
DataTable data = sql.ExecuteToDataTable("SELECT * FROM Customers");
int affected = sql.ExecuteNonQuery("INSERT Customers VALUES ('Test')");
But if you really want static (if you is on a single user enviroment), just put static on all methods.