Static function of database in Asp .net - asp.net

I have a class that gets tables from Sql Server. the class is static, but the variables are not. I want to know if it is OK in Asp net, because I had read not to use static at database in Asp net.
My Class: (There are more functions in the class, I put here one for example)
public static class DataBase
{
public static bool TableChange(string sqlCreate)
{
using (SqlConnection connection = new SqlConnection(Global.ConnectionString))
{
using (var cmd = new SqlCommand(sqlCreate, connection))
{
try
{
connection.Open();
cmd.ExecuteNonQuery();
}
catch (Exception ex)
{
Log.WriteLog(ex.Message + "\n" + sqlCreate, ex, HttpContext.Current.Request);
return false;
}
}
}
return true;
}
}
Thanks in advance

What you have read is most probably something to do with this approach:
public static EntityContext Database = new EntityContext();
// or
public static SqlConnection Database = new SqlConnection("...");
Here you store the database connection in a static variable and thus all parallel requests would want to use the same connection which is a very bad approach if it even works at all (it will probably work sort of fine until the page is under load).
You do not have this problem, because in your case only the methods are static, not the variables. Your code follows the recommended path - open connection (retrieve it from the pool), execute query, close the connection (return it to the pool).

Related

App Service to EntityFramework using MSI

I'm trying to retrofit MSI to an existing app.
The original app's DbContext used only a Constructor that found a ConnectionString by the same name in the web.config.
I've modified it to use a DbConnectionFactory to inject an AccessToken.
public class AppCoreDbContext : DbContext {
public AppCoreDbContext() : this("AppCoreDbContext")
{
}
public AppCoreDbContext(string connectionStringOrName) : base( OpenDbConnectionBuilder.Create(connectionStringOrName).Result, true)
{
}
...etc...
}
The class that it is invoking looks like:
public static class OpenDbConnectionBuilder
{
public static async Task<DbConnection> CreateAsync(string connectionStringName)
{
var connectionStringSettings = ConfigurationManager.ConnectionStrings[connectionStringName];
var dbConnection = DbProviderFactories
.GetFactory(connectionStringSettings.ProviderName)
.CreateConnection();
dbConnection.ConnectionString = connectionStringSettings.ConnectionString;
await AttachAccessTokenToDbConnection(dbConnection);
// Think DbContext will open it when first used.
//await dbConnection.OpenAsync();
return dbConnection;
}
static async Task AttachAccessTokenToDbConnection(IDbConnection dbConnection)
{
SqlConnection sqlConnection = dbConnection as SqlConnection;
if (sqlConnection == null)
{
return;
}
string msiEndpoint = Environment.GetEnvironmentVariable("MSI_ENDPOINT");
if (string.IsNullOrEmpty(msiEndpoint))
{
return;
}
var msiSecret = Environment.GetEnvironmentVariable("MSI_SECRET");
if (string.IsNullOrEmpty(msiSecret))
{
return;
}
string accessToken = await AppCoreDbContextMSITokenFactory.GetAzureSqlResourceTokenAsync();
sqlConnection.AccessToken = accessToken;
}
}
Which invokes
// Refer to: https://winterdom.com/2017/10/19/azure-sql-auth-with-msi
public static class AppCoreDbContextMSITokenFactory
{
private const String azureSqlResource = "https://database.windows.net/";
public static async Task<String> GetAzureSqlResourceTokenAsync()
{
var provider = new AzureServiceTokenProvider();
var result = await provider.GetAccessTokenAsync(azureSqlResource);
return result;
}
}
The result of the above is that when tracking it with a debugger, it gets to
var result = await provider.GetAccessTokenAsync(azureSqlResource);
then hangs for ever.
Note: I'm working on a personal machine, not joined to the organisation domain -- but my personal MSA has been invited to the organisation's domain.
Admittedly, I've taken a hiatus from development for a couple of years, and the hang is probably due to having made a mistake around await (always been rough on understanding that implicitly)... but while trying to figure that out, and the documentation is pretty sparse, would appreciate feedback as to whether the above was the intended approach for using MSI.
I'm wondering:
When deploying to Azure, we can tell the ARM to create the Identity -- when developing, how do we tell the local machine to use MSI?
If on the dev machine the connection string is to a local db, and I create and add the token anyway, will it ignore it, or raise an exception.
This is a bit beyond the scope of discussing MSI, but I've never before created a dbConnection to use within a DbContext. Does anyone know the pros/cons of the DbContext 'owning' the connection? I'm assuming that it would be wiser to own & close the connection when the dbcontext is closed.
Basically...this is all new, so would appreciate any advice on getting this working -- the concept of being able to deploy without secrets would be awesome and would really like to get this demo working.
Thanks very much!
Hello user9314395: Managed Service Identity only works with resources running on Azure. While we don't support the local development scenario, you might consider looking into using the following (preview) library: https://learn.microsoft.com/en-us/azure/key-vault/service-to-service-authentication

asp.net mvc global variables without cookies and session[""]

Is there any method for storing global variables without using cookies or session[""] in asp.net mvc ?
I know that cookies and session[""] have some disadvantages and I want to use the best method if exit.
If they are indeed global variables, you should implement the singleton pattern and have an Instance globally accessible that holds your variables.
Here is a simple example:
public sealed class Settings
{
private static Settings instance = null;
static readonly object padlock = new object();
// initialize your variables here. You can read from database for example
Settings()
{
this.prop1 = "prop1";
this.prop2 = "prop2";
}
public static Settings Instance
{
get
{
lock (padlock)
{
if (instance == null)
{
instance = new Settings();
}
return instance;
}
}
}
// declare your global variables here
public string prop1 { get; set; }
public string prop2 { get; set; }
}
The you can use them in your code like this:
var globalvar1 = Settings.Instance.prop1;
This class with its variables will be initialized only once (when the application starts) and it will be available in your application globally.
Basically you have following options:
Cookies - valid as long as you set, must be allowed by client's browser, can be deleted by user, stored on user's PC.
Session - valid for all requests, not for a single redirect, stored on server.
ViewData - after redirect it's cleared (lives only during single request).
TempData - it's useful for passing short messages to view, after reading a value it's deleted.
ViewBag - is available only during the current request, if redirection occurs then it’s value becomes null, is dynamic so you don't have intellisense and errors may occur only in runtime.
Here - http://www.dotnet-tricks.com/Tutorial/mvc/9KHW190712-ViewData-vs-ViewBag-vs-TempData-vs-Session.html - you can find fantastic article which describes them.
Sure: HttpContextBase.Application (no expiration) or HttpContextBase.Cache (with expiration). You can access the HttpContextBase instance through the HttpContext property of the Controller class.
So... HACK ALERT... There is no good way to do an MVC 5 or 6 web app using session variables that I have found (yet). MVC doesn't support Session variables or Cookies, which are implemented via session variables. Global variables will be set for ALL users, which is not how Session variables work.
However, you can store "session variables" based on the User.Identity.Name or the underlying User.Identity.Claims.AspNet.Identity.SecurityStamp into a database along with a timestamp and viola! You have implemented primitive session variables. I had a very specific need to save two weeks of programming by not interfering with the GUI that our user interface specialist had written. So I returned NoContent() instead of the normal View() and I saved my hacky session variable based on the user's login name.
Am I recommending this for most situations? No. You can use ViewBag or return View(model) and it will work just fine. But if you need to save session variables in MVC for whatever reason, this code works. The code below is in production and works.
To retrieve the data...
string GUID = merchdata.GetGUIDbyIdentityName(User.Identity.Name);
internal string GetGUIDbyIdentityName(string name)
{
string retval = string.Empty;
try
{
using (var con = new SqlConnection(Common.DB_CONNECTION_STRING_BOARDING))
{
con.Open();
using (var command = new SqlCommand("select GUID from SessionVariablesByIdentityName md where md.IdentityName = '" + name + "' and LastSaved > getdate() - 1", con))
{
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
retval = reader["GUID"].ToString();
}
}
}
}
}
catch (Exception ex)
{
}
return retval;
}
To save the data...
merchdata.SetGUIDbyIdentityName(User.Identity.Name, returnedGUID);
internal void SetGUIDbyIdentityName(string name, string returnedGUID)
{
RunSQL("exec CRUDSessionVariablesByIdentityName #GUID='" + returnedGUID + "', #IdentityName = '" + name + "'");
}
internal void RunParameterizedSQL(SqlConnection cn, SqlCommand cmd, object sqlStr)
{
string retval = string.Empty;
try
{
cn.Open();
cmd.ExecuteNonQuery();
cn.Close();
}
BTW: The SQL table (named SessionVariablesByIdentityName here) is fairly straightforward and can store lots of other things too. I have a LastSaved datetime field in there so I don't bother retrieving old data from yesterday. For example.

Using Web.Api to asynchronously log errors for asp.net mvc

I have a legacy logging DLL that logs errors into a database. Instead of consuming the DLL within each application in our environment, we would like to make web calls to log errors.
I have built up a web.api app that will log errors into a database. When tested with POSTMAN it works as advertised.
I have added a class within a demo MVC app and wired up one of my constructors to execute a log command, but the call not only does not make it to my web.api, but fiddler does not show a call even being made.
Any input on making this actually run would be greatly appreciated.
Here's my code:
Logging Utility Called within Web.API
public class Utilities
{
public void LogException(string exceptionMessage, string stackTrace, string appCode, string runMode, int entityId, int itmsUserID, string updateBy, string path, string method)
{
ErrorLog.Entry _error = new ErrorLog.Entry();
_error.ErrorMessage = exceptionMessage;
_error.StackTrace = stackTrace;
_error.AppCode = appCode;
_error.Path = path;
_error.Method = method;
_error.UpdateBy = updateBy;
_error.RunMode = runMode;
_error.EntityID = entityId;
//_error.Server = server; server will have to be changed to accept a setter
_error.ITMSUserID = CommonFunctions.Get_ITMSUserID(updateBy);
_error.Save();
}
}
Web.API
// POST: api/ErrorLog
public void Post([FromBody]ErrorLogEntryDTO item)
{
var utils = new Utilities();
utils.LogException(item.ErrorMessage, item.StackTrace, item.AppCode, item.RunMode, item.EntityID, item.ITMSUserID, item.UpdateBy, item.Path, item.Method);
}
MVC Controller Code
// GET: BillingRules/Create
public virtual ActionResult CauseHandledError()
{
try
{
throw new Exception("Handled exception test");
}
catch (Exception ex)
{
var utils = new Utilities();
utils.LogException(ex, "system", MVC.BillingRules.Name, MVC.BillingRules.ActionNames.CauseHandledError);
}
return RedirectToAction(MVC.BillingRules.ActionNames.Index, MVC.BillingRules.Name);
}
Utilities Code within MVC App
public void LogException(Exception exception, string updateBy, string path, string method)
{
try
{
var itmsUserID = CommonFunctions.Get_ITMSUserID(updateBy);
var errorDTO = new ErrorLogEntryDTO();
errorDTO.ITMSUserID = itmsUserID;
errorDTO.AppCode = _appCode.Value;
errorDTO.ErrorMessage = exception.Message;
errorDTO.StackTrace = exception.StackTrace;
errorDTO.Path = path;
errorDTO.Method = method;
errorDTO.UpdateBy = updateBy;
var client = new HttpClient();
client.BaseAddress = new Uri("http://localhost:52316");
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(
new MediaTypeWithQualityHeaderValue("application/json"));
var result = client.PostAsJsonAsync("api/ErrorLog", errorDTO).Result; //ContinueWith(readTask => client.Dispose()); //
}
catch (Exception ex)
{
var myError = ex;
throw;
}
}
I'm pretty sure calling .Result in this instance does not immediately invoke the PostAsJsonAsync method. Because you're not doing anything with the Result, it never actually executes. Since it doesn't appear you care about the response, you should be able to use:
client.PostAsJsonAsync("api/ErrorLog", errorDTO).Wait();
I think .Result invokes the PostAsJsonAsync call. You are waiting for the respsonse, so the call must be finished after this line. Regardless if you use the Result or not.
You can remove the [FromBody] attribute, because the complex type is per default read from the body.
And I can't reproduce your issue. I've created a new Web API project and a new console project. In the Web API I've changed the post of the valuescontroller to yours.
In the console project I'm yousing your LogException() method from the MVC app.
It hits my web api app.
Are both in the same host or in different hosts?
Edit:
To make your logging async you can use fire-and-forget with Task.Run() but it depends on the application you have. In ASP.Net Task.Run() is an anti-pattern according to Task.Run Etiquette Examples: Don't Use Task.Run in the Implementation.

Writing my own Provider Class in ASP.NET

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.

cleanest way to access sproc data in asp.net

I haven't accessed data using SqlCommand etc. for a while as I tend to use NHibernate these days. I am just wondering whether the following code could be improved. I have tried to use best practises (after some google-ing) and potential exceptions are caught at a higher layer.
[WebMethod]
public XmlDocument GetClassRegistrationReport()
{
XmlDocument doc = new XmlDocument();
using (SqlConnection connection = new SqlConnection(ConfigurationManager.ConnectionStrings["bla"].ToString()))
{
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = "bla";
command.CommandType = CommandType.StoredProcedure;
connection.Open();
doc.Load(command.ExecuteXmlReader());
}
}
return doc;
}
Thanks!
Best wishes,
Christian
There are a few ways you could improve it a little:
Although the WebMethod pulls data and returns it verbatim with no input parameters, I would suggest seperating service interface and the data into seperate classes. It may make things easier to maintain at a later date.
Assuming there are other DB calls in your framework you may want to consider a helper method in your data layer that wraps up the invocation of a stored procedure. This way you only have one method that all SP calls filter down into which again will make things easier to maintain in the future.
Make the 'bla' key for your connection string setting a constant, this way you can easily reuse and change.
The same applies to the name of the stored procedure, alternatively make it part of your web.config - this means you can change the stored proc name without having to recompile.
If an exception is throw there is no handling for this so the exception will bubble out to the caller, consider catching and handling/logging exceptions. That said you do mention that you are handling exceptions at a higher layer, so I assume this is being done in whatever is calling your webservices.
You should be disposing the SQL command object (in the finally of the try/catch/finally if you do implement exception handling)
EDIT : Code Sample
public class MyWebService
{
[WebMethod]
public XmlDocument GetClassRegistrationReport()
{
return DataLayer.GetClassRegistrationReport();
}
}
// Notice that this is a static internal class, internal to hide the
// data access class from everything but this library and static because
// we don't need instances and using statics will optimise a little.
internal static class DataLayer
{
private const string SP_GetRegistrationReport = "GetRegistrationReport";
private const string Config_DBConnectionString = "PrimaryDB";
private static string GetDB
{
get
{
string dbConnectionString = ConfigurationManager.ConnectionStrings[Config_DBConnectionString].ConnectionString;
if (string.IsNullOrEmpty(dbConnectionString))
{
// This error should could/should be in a resource file.
throw new ConfigurationException("Database connection string is not defined");
}
return dbConnectionString;
}
}
internal static XmlDocument GetClassRegistrationReport()
{
XmlDocument doc = new XmlDocument();
using (SqlConnection connection = new SqlConnection())
{
using (SqlCommand command = connection.CreateCommand())
{
command.CommandText = SP_GetRegistrationReport;
command.CommandType = CommandType.StoredProcedure;
connection.Open();
doc.Load(command.ExecuteXmlReader());
}
}
return doc;
}
}

Resources