RavenDB Catch 22 - Optimistic Concurrency AND Seeing Changes from Other Clients - ravendb

With RavenDB, creating an IDocumentSession upon app start-up (and never closing it until the app is closed), allows me to use optimistic concurrency by doing this:
public class GenericData : DataAccessLayerBase, IGenericData
{
public void Save<T>(T objectToSave)
{
Guid eTag = (Guid)Session.Advanced.GetEtagFor(objectToSave);
Session.Store(objectToSave, eTag);
Session.SaveChanges();
}
}
If another user has changed that object, then the save will correctly fail.
But what I can't do, when using one session for the lifetime of an app, is seeing changes, made by other instances of the app (say, Joe, five cubicles away), to documents. When I do this, I don't see Joe's changes:
public class CustomVariableGroupData : DataAccessLayerBase, ICustomVariableGroupData
{
public IEnumerable<CustomVariableGroup> GetAll()
{
return Session.Query<CustomVariableGroup>();
}
}
Note: I've also tried this, but it didn't display Joe's changes either:
return Session.Query<CustomVariableGroup>().Customize(x => x.WaitForNonStaleResults());
Now, if I go the other way, and create an IDocumentSession within every method that accesses the database, then I have the opposite problem. Because I have a new session, I can see Joe's changes. Buuuuuuut... then I lose optimistic concurrency. When I create a new session before saving, this line produces an empty GUID, and therefore fails:
Guid eTag = (Guid)Session.Advanced.GetEtagFor(objectToSave);
What am I missing? If a Session shouldn't be created within each method, nor at the app level, then what is the correct scope? How can I get the benefits of optimistic concurrency and the ability to see others' changes when doing a Session.Query()?

You won't see the changes, because you use the same session. See my others replies for more details

Disclaimer: I know this can't be the long-term approach, and therefore won't be an accepted answer here. However, I simply need to get something working now, and I can refactor later. I also know some folks will be disgusted with this approach, lol, but so be it. It seems to be working. I get new data with every query (new session), and I get optimistic concurrency working as well.
The bottom line is that I went back to one session per data access method. And whenever a data access method does some type of get/load/query, I store the eTags in a static dictionary:
public IEnumerable<CustomVariableGroup> GetAll()
{
using (IDocumentSession session = Database.OpenSession())
{
IEnumerable<CustomVariableGroup> groups = session.Query<CustomVariableGroup>();
CacheEtags(groups, session);
return groups;
}
}
Then, when I'm saving data, I grab the eTag from the cache. This causes a concurrency exception if another instance has modified the data, which is what I want.
public void Save(EntityBase objectToSave)
{
if (objectToSave == null) { throw new ArgumentNullException("objectToSave"); }
Guid eTag = Guid.Empty;
if (objectToSave.Id != null)
{
eTag = RetrieveEtagFromCache(objectToSave);
}
using (IDocumentSession session = Database.OpenSession())
{
session.Advanced.UseOptimisticConcurrency = true;
session.Store(objectToSave, eTag);
session.SaveChanges();
CacheEtag(objectToSave, session); // We have a new eTag after saving.
}
}
I absolutely want to do this the right way in the long run, but I don't know what that way is yet.
Edit: I'm going to make this the accepted answer until I find a better way.

Bob, why don't you just open up a new Session every time you want to refresh your data?
It has many trade-offs to open new sessions for every request, and your solution to optimistic concurrency (managing tags within your own singleton dictionary) shows that it was never intended to be used that way.
You said you have a WPF application. Alright, open a new Session on startup. Load and query whatever you want but don't close the Session until you want to refresh your data (e.g. a list of order, customers, i don't know...). Then, when you want to refresh it (after a user clicks on a button, a timer event is fired or whatever) dispose the session and open a new one. Does that work for you?

Related

A confusing situation on my way to understand DDD

Thank you in advance for your help and attentation!
My project is dedicated only for learning purposes and I'm totally confused with DDD and have the following situation:
There is the ubiquitous language of my domain where I have users and documents. It says the following:
- A user can create a document. One of the main purpose of my project is to provide users an ability to create different documents. I mean that the documents cannot exist without the users. So,I think that the process of a document creation belongs to my domain.
- A user can send a document for approval. It's one more thing that belongs to the domain. An approval process is one of the most important part of the project. It has its steps that other users must confirm.
- A user can approve a step of approval process.
- A user can reject a step of approval process.
That's enough to understand and answer my question:
Is it normal that a User can contain such methods as: CreateDocument(params), SendDocumentForApproval(docId), ApproveApprovalStepOfDocument(stepId)?
I'm comfused with it because It looks in code a bit strange.
For example for the document creatation process we have something like that:
public async Task<bool> CreateDocumentCommandHandler(CreateDocumentCommand command)
{
//We have our injected repositories
User user = await _userRepository.UserOfId(command.UserId);
Document document = User.CreateDocoment(command.*[Params for the document]);
_documentRepostiory.Add(document);
// It raises event before it makes a commit to the database
// It gets event from an entity. The entity keeps it as readonly collection.
// Here it raises DocumentCreatedEvent. This event contains logic which concerns
// creation some additional entities for the document and log actions.
await _documentRepository.UnitOfWork.SaveEntitiesAsync();
}
The approval process:
//The first try out to model this process:
public async Task<bool> SendDocumentForApprovalCommandHandler(SendDocumentForApprovalCommand command)
{
//We have our injected repositories
User user = await _userRepository.UserOfId(command.UserId);
//Here I have some problems.
//Is it okay that the method returns the document?
//The method that is placed inside the User has this logic:
//public Document SendDocumentForApproval(int docId)
//{
// Document document = this.GetDocument(docId);
//
// //Inside this method ChangedStatusToApproving is created
// document.SetStatusToApproving();
// return document;
//}
Document document = User.SendDocumentForApproval(command.DocId);
_documentRepostiory.Upadate(document);
// It raises event before it makes a commit to the database
// It gets event from an entity. The entity keeps it as readonly collection.
// Here it raises ChangedStatusToApproving. This event contains logic which concerns
// creation some additional entities for the document and log actions.
await _documentRepository.UnitOfWork.SaveEntitiesAsync();
}
//Is it okay to do something like the command handler above?
//The second one:
public async Task<bool> SendDocumentForApprovalCommandHandler(SendDocumentForApprovalCommand command)
{
//We have our injected repositories
User user = await _userRepository.UserOfId(command.UserId);
//The same one as we have in the previous method.
//But here I don't want to put the logic about the changing status of the doucnent inside it.
Document document = User.SendDocumentForApproval(command.DocId);
//I see that it breaks the method above (SendDocumentForApproval)
//Now It doesn't mean anything for our domain, does it?
//It is only getter like User.GetDocument or we can even do it
//by using repository - documentRepository.DocumentOfId(docId)
document.SetStatusToApproving();
_documentRepostiory.Upadate(document);
await _documentRepository.UnitOfWork.SaveEntitiesAsync();
}
// So, I think the first one is better, isn't it? It follows the ubiquitous language.
//And here is the final question: Why can't I do it like this:
public async Task<bool> SendDocumentForApprovalCommandHandler(SendDocumentForApprovalCommand command)
{
//Here we don't want to use the userRepository. We don't need at all
//Here as a consequence we also don't need a user entity
//Everything what we need is:
Document document = _documentRepository.DocOfId(command.DocId);
document.ForApproval();
_documentRepostiory.Upadate(document);
await _documentRepository.UnitOfWork.SaveEntitiesAsync();
}
//I think that the last approach breaks the ubiquitous language and we're about to having an anemic model.
//But here we have only two queries to the database because we don't need a user.
//Which of the approaches is better? Why? How can I do it more correctly if I want to apply DDD?
I want to explain my thoughts in more details.
Let's have a look at the user. They manage documents. A Document cannot exist without the user. Does it mean that the User is an aggregate root through we need to create, update, delete its aggregates.
And the document is also an aggregate root due to it contains an apporval process. The ApprovalProcess cannot exist without the document.
Does it mean that I need to do something like this:
public async Task<bool> SendDocumentForApprovalCommandHandler(SendDocumentForApprovalCommand command)
{
Document document = _documentRepository.DocumentOfId(command.DocId);
document.SendForApproval();
_documentRepository.SaveChangesAsync();//Raise a domain event - SentDocumentForApprovalEvent
}
// Here we have a handler for the event SentDocumentForApprovalEvent
public async Task SentDocumentForApprovalEventHandler(SentDocumentForApprovalEvent sentDocumentForApprovalEvent)
{
//Now I want to create an approval process for the document
//Can I do the next thing:
ApprovalProcess process = new ApprovalProcess(sentDocumentForApprovalEvent.DocId);
_approvalProcessRepository.Add(process);
_approvalProcessRepository.SaveEntitiesAsync();//Raise a domain event - InitiatedApprovalProcessEvent
//Or Should I create the approval process through Document?
//Looks terrible due to we need to call the repostiory amd
ApprovalProcess process = Document.InitiateApprovalProcess(sentDocumentForApprovalEvent.DocID);//Static method
_approvalProcessRepository.Add(process);
_approvalProcessRepository.SaveEntitiesAsync();
//log
}
// Here we have a handler for the event InitiatedApprovalProcessEvent
public async Task InitiatedApprovalProcesEventHandler(SentDocumentForApprovalEvent sentDocumentForApprovalEvent)
{
//The same question as we have with handler above.
//Should I create steps trough the approval process or just with the help of constructor of the step?
//log
}
Thank you so much and sorry for my terrible English!
Best regards
Is it normal that a User can contain such methods as: CreateDocument(params), SendDocumentForApproval(docId), ApproveApprovalStepOfDocument(stepId)?
In most domain models, the method belongs with the entity that manages the state that is going to change.
Document document = User.SendDocumentForApproval(command.DocId);
_documentRepository.Update(document);
The fact that your sample is updating the document repository here is a big hint that it is the document that is changing, and therefore we would normally expect to see SendDocumentForApproval as a method on the document.
document.SendDocumentForApproval(command.UserId)
_documentRepository.Update(document);
(Yes, the code doesn't read like written or spoken English.)
When creating a new document... creation patterns are weird. Udi Dahan suggests that there should always be some entity in your domain model that is responsible for creating the other entities, but I'm not convinced that the result is actually easier to work with in the long term.
How can we model the approval business process
General answer: business processes are protocols, which is to say that you can normally model them as a state machine. Here's the state we are in right now, here is some new information from the outside world, compute the consequences.
(Often, the data model for a process will just look like a history of events; the domain model's job is to then take the new information and compute the right events to store in the history. You don't have to do it that way, but there are interesting possibilities available when you can).
You are headed in a right direction, User and Document both are aggregates as they are created in separate transactions. When it comes to who references whom, IDDD principle of scalability says that aggregates should refer aggregates only via their IDs.
I think sticking to the ubiquitious, language your code should look something like this
class User {
private UserId id;
private String name;
User(String name) {
this.id = new UserId();
this.name = name;
}
Document createDocument(String name) {
Document document = new Document(name);
document.createdBy(this);
return document;
}
Document approve(Document document) {
document.approved();
return document;
}
}
class Document {
private DocumentId id;
private String name;
private UserId userId;
private Boolean isApproved;
Document(String name) {
this.id = new DocumentId();
this.name = name;
}
void createdBy(UserId userId) {
this.userId = userId;
}
void approved() {
this.isApproved = true;
}
}
// User creation
User user = new User("Someone");
userRepository.save(user);
//Document creation
User user = userRepository.find(new UserId("some-id"))
Document document = user.createDocument("important-document")
documentRepository.save(document)
// Approval
User user = userRepository.find(new UserId("some-id"))
Document document = documentRepository.find(new DocumentId("some-id"))
document = user.approve(Document)
I would highly recommend reading Vaughn Vernon's three part aggregate design paper series better aggregete design

How to span a ConcurrentDictionary across load-balancer servers when using SignalR hub with Redis

I have ASP.NET Core web application setup with SignalR scaled-out with Redis.
Using the built-in groups works fine:
Clients.Group("Group_Name");
and survives multiple load-balancers. I'm assuming that SignalR persists those groups in Redis automatically so all servers know what groups we have and who are subscribed to them.
However, in my situation, I can't just rely on Groups (or Users), as there is no way to map the connectionId (Say when overloading OnDisconnectedAsync and only the connection id is known) back to its group, and you always need the Group_Name to identify the group. I need that to identify which part of the group is online, so when OnDisconnectedAsync is called, I know which group this guy belongs to, and on which side of the conversation he is.
I've done some research, and they all suggested (including Microsoft Docs) to use something like:
static readonly ConcurrentDictionary<string, ConversationInformation> connectionMaps;
in the hub itself.
Now, this is a great solution (and thread-safe), except that it exists only on one of the load-balancer server's memory, and the other servers have a different instance of this dictionary.
The question is, do I have to persist connectionMaps manually? Using Redis for example?
Something like:
public class ChatHub : Hub
{
static readonly ConcurrentDictionary<string, ConversationInformation> connectionMaps;
ChatHub(IDistributedCache distributedCache)
{
connectionMaps = distributedCache.Get("ConnectionMaps");
/// I think connectionMaps should not be static any more.
}
}
and if yes, is it thread-safe? if no, can you suggest a better solution that works with Load-Balancing?
Have been battling with the same issue on this end. What I've come up with is to persist the collections within the redis cache while utilising a StackExchange.Redis.IDatabaseAsync alongside locks to handle concurrency.
This unfortunately makes the entire process sync but couldn't quite figure a way around this.
Here's the core of what I'm doing, this attains a lock and return back a deserialised collection from the cache
private async Task<ConcurrentDictionary<int, HubMedia>> GetMediaAttributes(bool requireLock)
{
if(requireLock)
{
var retryTime = 0;
try
{
while (!await _redisDatabase.LockTakeAsync(_mediaAttributesLock, _lockValue, _defaultLockDuration))
{
//wait till we can get a lock on the data, 100ms by default
await Task.Delay(100);
retryTime += 10;
if (retryTime > _defaultLockDuration.TotalMilliseconds)
{
_logger.LogError("Failed to get Media Attributes");
return null;
}
}
}
catch(TaskCanceledException e)
{
_logger.LogError("Failed to take lock within the default 5 second wait time " + e);
return null;
}
}
var mediaAttributes = await _redisDatabase.StringGetAsync(MEDIA_ATTRIBUTES_LIST);
if (!mediaAttributes.HasValue)
{
return new ConcurrentDictionary<int, HubMedia>();
}
return JsonConvert.DeserializeObject<ConcurrentDictionary<int, HubMedia>>(mediaAttributes);
}
Updating the collection like so after I've done manipulating it
private async Task<bool> UpdateCollection(string redisCollectionKey, object collection, string lockKey)
{
var success = false;
try
{
success = await _redisDatabase.StringSetAsync(redisCollectionKey, JsonConvert.SerializeObject(collection, new JsonSerializerSettings
{
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
}));
}
finally
{
await _redisDatabase.LockReleaseAsync(lockKey, _lockValue);
}
return success;
}
and when I'm done I just ensure the lock is released for other instances to grab and use
private async Task ReleaseLock(string lockKey)
{
await _redisDatabase.LockReleaseAsync(lockKey, _lockValue);
}
Would be happy to hear if you find a better way of doing this. Struggled to find any documentation on scale out with data retention and sharing.

NHibernate not persisting changes to my object

My ASP.NET MVC 4 project is using NHibernate (behind repositories) and Castle Windsor, using the AutoTx and NHibernate Facilities. I've followed the guide written by haf and my I can create and read objects.
My PersistenceInstaller looks like this
public class PersistenceInstaller : IWindsorInstaller
{
public void Install(Castle.Windsor.IWindsorContainer container, Castle.MicroKernel.SubSystems.Configuration.IConfigurationStore store)
{
container.AddFacility<AutoTxFacility>();
container.Register(Component.For<INHibernateInstaller>().ImplementedBy<NHibernateInstaller>().LifeStyle.Singleton);
container.AddFacility<NHibernateFacility>(
f => f.DefaultLifeStyle = DefaultSessionLifeStyleOption.SessionPerWebRequest);
}
}
The NHibernateInstaller is straight from the NHib Facility Quickstart.
I am using ISessionManager in my base repository...
protected ISession Session
{
get
{
return _sessionManager.OpenSession();
}
}
public virtual T Commit(T entity)
{
Session.SaveOrUpdate(entity);
return entity;
}
Finally, my application code which is causing the problem:
[HttpPost]
[ValidateAntiForgeryToken]
[Transaction]
public ActionResult Maintain(PrescriberMaintainViewModel viewModel)
{
if (ModelState.IsValid)
{
var prescriber = UserRepository.GetPrescriber(User.Identity.Name);
//var prescriber = new Prescriber { DateJoined = DateTime.Today, Username = "Test" };
prescriber.SecurityQuestion = viewModel.SecurityQuestion;
prescriber.SecurityAnswer = viewModel.SecurityAnswer;
prescriber.EmailAddress = viewModel.Email;
prescriber.FirstName = viewModel.FirstName;
prescriber.LastName = viewModel.LastName;
prescriber.Address = new Address
{
Address1 = viewModel.AddressLine1,
Address2 = viewModel.AddressLine2,
Address3 = viewModel.AddressLine3,
Suburb = viewModel.Suburb,
State = viewModel.State,
Postcode = viewModel.Postcode,
Country = string.Empty
};
prescriber.MobileNumber = viewModel.MobileNumber;
prescriber.PhoneNumber = viewModel.PhoneNumber;
prescriber.DateOfBirth = viewModel.DateOfBirth;
prescriber.AHPRANumber = viewModel.AhpraNumber;
prescriber.ClinicName = viewModel.ClinicName;
prescriber.ClinicWebUrl = viewModel.ClinicWebUrl;
prescriber.Qualifications = viewModel.Qualifications;
prescriber.JobTitle = viewModel.JobTitle;
UserRepository.Commit(prescriber);
}
return View(viewModel);
}
The above code will save a new prescriber (tested by uncommenting out the commented out line etc).
I am using NHProf and have confirmed that no sql is sent to the database for the Update. I can see the read being performed but that's it.
It seems to me that NHibernate doesn't recognise the entity as being changed and therefore does not generate the sql. Or possibly the transaction isn't being committed?
I've been scouring the webs for a few hours now trying to work this one out and as a last act of desperation have posted on SO. Any ideas? :)
Oh and in NHProf I see three Sessions (1 for the GetPrescriber call from the repo, one I assume for the update (with no sql) - and one for some action in my actionfilter on the base class). I also get an alert about the use of implicit transactions. This confuses me because I thought I was doing everything I needed to get an transaction - using AutoTx and the Transaction attribute. I also expected there to be only 1 session per webrequest, as per my Windsor config.
UPDATE: It seems, after spending the day reading through the source for NHibernateFacility and AutoTx Facility for automatic transactions, that AutoTx is not setting the Interceptors on my implementation of INHibernateInstaller. It seems this means whenever SessionManager calls OpenSession it is calling the default version with no parameter, rather than the one that accepts an Interceptor. Internally AutoTxFacility registers TransactionInterceptor with windsor, so that it can be added the Interceptor on my INHibernateInstaller concrete, by windsor making use of the AutoTx's TransactionalComponentInspector
AutoTxFacility source on github
To me it looks like creating sessions for every call to the repository. A session should span the whole business operation. It should be opened at the beginning and committed and disposed at the end.
There are other strange things in this code.
Commit is a completely different concept than SaveOrUpdate.
And you don't need to tell NH to store changes anyway. You don't need to call session.Save for objects that are already in the session. They are stored anyway. You only need to call session.Save when you add new objects.
Make sure that you use a transaction for the whole business operation.
There is one most likely "unintended" part in the code snippet above. And proven by observation made by NHProf
Oh and in NHProf I see three Sessions (1 for the GetPrescriber call
from the repo, one I assume for the update (with no sql) - and one for
some action in my actionfilter on the base class).
Calling the OpenSession() is triggering creation of a new session instances.
protected ISession Session
{
get { return _sessionManager.OpenSession(); }
}
So, whenever the code is accessing the Session property, behind is new session instance created (again and again). One session for get, one for udpate, one for filter...
As we can see here, the session returned by SessionManager.OpenSession() must be used for the whole scope (Unit of work, web request...)
http://docs.castleproject.org/Windsor.NHibernate-Facility.ashx
The syntaxh which we need, si to create one session (when firstly accessed) and reuse it until enf of scope (then later correctly close it, commit or rollback transaction...). Anyhow, first thing right now is to change the Session property this way:
ISession _session;
protected ISession Session
{
get
{
if (_session == null)
{
_session = sessionFactory.OpenSession();
}
return _session;
}
}
After spending a full day yesterday searching through the AutoTx and NHibernate facilities on github and getting nowhere, I started a clean project in an attempt to replicate the problem. Unfortunately for the replication, everything worked! I ran Update-Package on my source and brought down new version of Castle.Transactions and I was running correctly. I did make a small adjustment to my own code. That was to remove the UserRepository.Commit line.
I did not need to modify how I opened sessions. That was taken care of by the SessionManager instance. With the update to Castle.Transactions, the Transaction attribute is being recognised and a transaction is being created (as evidenced by no more alert in NHProf).

Relation many-to-one retrieved from custom cache

It's more like theoretical question.
I have one table to hold dictionary items, and the next one for hold Users data.
User table contains a lot reference collumns of type many to one indicated on dictionary item table. It's looks like:
public class User
{
public int Id;
public Dictionary Status;
public Dictionary Type;
public Dictionary OrganizationUnit;
......
}
I want retrieve all dictionary on startup of aplication, and then when i retrieved user and invoke reference property to dictionary the dictionary object should be taken from cache.
I know i can use a 2nd level cache in this scenario, but i'm interested about other solution. Is there any?
It's posible to make my custom type and said that: use my custom cache to retrieved value of dictionary??
Across multiple session the second level cache is the best answer, the only other solutions to populate objects from a cache without using second level cache i can think of would be to use an onLoad interceptor (and simply leave your dictionaries unmapped) or do it manually somewhere in your application.
But why don't you want to use the seocondlevel cache? If your views on caching is very different from the storages there are providers for in hibernate it is possible for you to implement your own provider?
Why not store it in the session? Just pull the record set one time and push it into session and retrieve it each time you want it. I do something similar for other stuff and I believe my method should work for you. In my code I have a session manager that I call directly from any piece of code needs the session values. I choose this method since I can query the results and I can manipulate the storage and retrieval methods. When relying on NHibernate to do the Caching for me, I don't have the granularity of control to cause specific record sets to only be available to specific sessions. I also find that NHibernate is not as efficient as using the session directly. When profiling the CPU and memory usage I find that this method is faster and uses a little less memory. If you want to do it on a site level instead of session, look into HttpContext.Current.Cache.
The following example works perfectly for storing and retrieving record sets:
// Set the session
SessionManager.User = (Some code to pull the user record with relationships. Set the fetch mode to eager for each relationship else you will just have broken references.)
// Get the session
User myUser = SessionManager.User;
public static class SessionManager
{
public static User User
{
get { return GetSession("MySessionUser") as User; }
set { SetSession("MySessionUser", value); }
}
private static object GetSession(string key)
{
// Fix Null reference error
if (System.Web.HttpContext.Current == null || System.Web.HttpContext.Current.Session == null)
{
return null;
}
else
{
return System.Web.HttpContext.Current.Session[key];
}
}
private static void SetSession(string key, object valueIn)
{
// Fix null reference error
if (System.Web.HttpContext.Current.Session[key] == null)
{
System.Web.HttpContext.Current.Session.Add(key, valueIn);
}
else
{
System.Web.HttpContext.Current.Session[key] = valueIn;
}
}
}

MVC 3/EF repository pattern and proper data access

Being rather new to MVC 3 and EF, I'm trying to understand the best architectural approach to developing an application for my company. The application will be a large-scale application that potentially handles hundreds of users at the same time, so I want to make sure I understand and am following proper procedures. So far, I've determined that a simple repository pattern (such as Controller -> Repository -> EF) approach is the best and easiest to implement, but I'm not sure if that is definitely the best way to do things. The application will basically return data that is shown to a user in a devexpress grid and they can modify this data/add to it etc.
I found this article and it is rather confusing for me at this time, so I'm wondering if there is any reason to attempt to work with a disconnected EF and why you would even want to do so: http://www.codeproject.com/Articles/81543/Finally-Entity-Framework-working-in-fully-disconne?msg=3717432#xx3717432xx
So to summarize my question(s):
Is the code below acceptable?
Should it work fine for a large-scale MVC application?
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)
Is the disconnected framework idea a better one and why would you even want to do that? I don't believe we'll need to track data across tiers ...
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.
Example Usage:
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();
}
}
What's acceptable is pretty subjective, but if you want to do proper data access I suggest you do NOT use the repository pattern, as it breaks down as your application gets more complex.
The biggest reason is minimizing database access. So for example look at your repository and notice the GetUser() method. Now take a step back from the code and think about how your application is going to be used. Now think about how often you are going to request data from the user table without any additional data. The answer is almost always going to be "rarely" unless you are creating a basic data entry application.
You say it your application will show a lot of grids. What data is in that Grid? I'm assuming (without knowing your application domain) that the grids will combine user data with other information that's relevant for that user. If that's the case, how do you do it with your repositories?
One way is to call on each repository's method individually, like so:
var user = userRepository.GetUser("KallDrexx");
var companies = companyRepository.GetCompaniesForUser(user.Id);
This now means you have 2 database calls for what really should be just one. As your screens get more and more complex, this will cause the number of database hits to increase and increase, and if your application gets significant traffic this will cause performance issues. The only real way to do this in the repository pattern is to add special methods to your repositories to do that specific query, like:
public class UserRepository
{
public User GetUser(string userName)
{
// GetUser code
}
public User GetUserWithCompanies(string userName)
{
// query code here
}
}
So now what happens if you need users and say their contact data in one query. Now you have to add another method to your user repository. Now say you need to do another query that also returns the number of clients each company has, so you need to add yet another method (or add an optional parameter). Now say you want to add a query that returns all companies and what users they contain. Now you need a new query method but then comes the question of do you put that in the User repository or the Company repository? How do you keep track of which one it's in and make it simple to choose between GetUserWithCompany and GetCompanyWithUsers when you need it later?
Everything gets very complex from that point on, and it's those situations that have made me drop the repository pattern. What I do now for data access is I create individual query and command classes, each class represents 1 (and only 1) query or data update command to the database. Each query class returns a view model that only contains the data I need for one specific user usage scenario. There are other data access patterns that will work too (specification pattern, some good devs even say you should just do your data access in your controllers since EF is your data access layer).
The key to doing data access successfully is good planning. Do you know what your screens are going to look like? Do you know how users are going to use your system? Do you know all the data that is actually going to be on each screen? If the answer to any of these is no, then you need to take a step back and forget about the data layer, because the data layer is (or should be for a good application) determined based on how the application is actually going to be used, the UI and the screens should not be dependent on how the data layer was designed. If you don't take your UI needs and user usage scenarios into account when developing the data access, your application will not scale well and will not be performant. Sometimes that's not an issue if you don't plan on your site being big, but it never hurts to keep those things in mind.
No matter what you do, you may consider moving instantiation and disposing of your context to your controller like this:
public class MyController : Controller
{
private Entities context = new Entities();
...
public override void Dispose()
{
context.Dispose();
}
}
You can then pass that context into any method that needs it without duplicating the overhead of creating it.
I disagree that the repository pattern is necessarily bad for the same reason. You create multiple classes to break up your code to make it manageable and still reuse the same context. That could look something like this:
repository.Users.GetUser(userName);
In this case "Users" is a lazy loaded instance of your user repository class which reuses the context from your repository. So the code for that Users property in your repository would look something like this:
private UserRepository users;
public UserRepository Users
{
get
{
If (users == null)
{
users = new UserRepository(this);
}
return users;
}
}
You can then expose your context to these other lazy loaded classes via a property.
I don't think this necessarily conflicts with KallDrexx's pattern. His method simply flips this so instead of
repository.Users.GetUser(userName);
You would have something like
UserQuery query = new UserQuery(repository.Users);
This then becomes an issue of syntax. Do you want this:
repository.Area.Query(value1, value2, ...);
Or this:
AreaQuery query = new AreaQuery { Property1 = value1, ... };
The latter actually works nicer with model binding but obviously is more verbose when you actually have to code it.
Best advice KallDrexx gave is to just put your code I your actions and then figure it out. If you are doing simple CRUD, then let MVC instantiate and populate your model, then all you have to do is attach and save. If you find you can reuse code, move it to where it can be reused. If your application starts getting too complicated, try some of these recommendations until you find what works for you.