Currently, this is how I am handling data within my MVC 3 application. Being pretty new to both MVC 3 and the Entity Framework I am not quite sure this is the best approach to handling data within the application. In fact, the call to check UserExists below sometimes gives a SQLConnectionTimeout issue which seems to be completely random. I’ve tried tracing the problem through SQL profiler and it appears that the timeout occurs right after the connection is being made from EF -> SQL.
I thought I had this solved in another question here on SO but it popped back up, so I wanted to get everyone’s opinion on whether or not below is the best way to attempt data handling in my application or is there a better way that may solve the timeout issue.
Here is a link to the other article if it helps: MVC 3/EF/SQL Server strange connection timeout issue
So to summarize my question(s):
- Is the code below acceptable?
- Should it work fine?
- Is there a better way?
- Will unnecessary connections to SQL remain open from EF? (SQL Profiler makes it look like it stays open a while even after the using statement has exited)
- Any idea on the timeout issue I posted in my other article?
Note: The repository implements IDisposable and has the dispose method listed below. It creates a new instance of the entity context in the repository constructor.
Controller (LogOn using Custom Membership Provider):
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
User newUser = new User();
using (AccountRepository repo = new AccountRepository())
{
newUser = repo.GetUser(model.UserName);
...
}
}
Membership Provider ValidateUser:
public override bool ValidateUser(string username, string password)
{
using (AccountRepository repo = new AccountRepository())
{
try
{
if (string.IsNullOrEmpty(password.Trim()) || string.IsNullOrEmpty(username.Trim()))
return false;
string hash = FormsAuthentication.HashPasswordForStoringInConfigFile(password.Trim(), "md5");
bool exists = false;
exists = repo.UserExists(username, hash);
return exists;
}catch{
return false;
}
}
}
Account Repository Methods for GetUser & UserExists:
Get User:
public User GetUser(string userName)
{
try
{
return entities.Users.SingleOrDefault(user => user.UserName == userName);
}
catch (Exception Ex)
{
throw new Exception("An error occurred: " + Ex.Message);
}
}
User Exists:
public bool UserExists(string userName, string userPassword)
{
if (userName == "" || userPassword == "")
throw new ArgumentException(InvalidUsernamePassword);
try
{
bool exists = (entities.Users.SingleOrDefault(u => u.UserName == userName && u.Password == userPassword) != null);
return exists;
}
catch (Exception Ex)
{
throw new Exception("An error occurred: " + Ex.Message);
}
}
Repository Snippets (Constructor, Dispose etc):
public class AccountRepository : IDisposable
{
private DbContext entities;
public AccountRepository()
{
entities = new DbContext();
}
...
public void Dispose()
{
entities.Dispose();
}
}
Thanks everyone – I realize that this question crit’s you for over 9000 with a giant wall of text!
We generally follow the pattern of controlling the instantiation and disposal of the context using an IActionFilter and providing a mechanism to inject that into dependent classes (using Ninject).
If you’re not using dependency injection / IoC you can get away with a base controller a little like the following:
Here we create an instance of your context and a transaction scope just before an action executes and then we cleanup once the action has finished up.
In your derived controller you can then do the following…
Passing the context into your repository is a little messy and can be tidied up using something like Ninject to inject the dependency rather than you providing it. http://stevescodingblog.co.uk/dependency-injection-beginners-guide/ provides a pretty reasonable starting point if you’re interested.
You can also mark up an action with the UnitOfWorkAttribute to control creation of the transaction used by the context. It’s recommended not to use implicit transaction when doing database work (http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions) so we always create a transaction scope when executing the action. This has little overhead because, unless the connection is opened, the transaction scope doesn’t do much.
Edit: Just to answer another of your questions…
Will unnecessary connections to SQL remain open from EF? (SQL Profiler makes it look like it stays open a while even after the using statement has exited)
Most likely reason here is connection pooling. ADO.NET will maintain open connections for a period of time which makes subsequent calls more efficient because you don’t have the latency of opening the connection.
Cheers,
Dean