Architecture of my application
this is surely a basic question for most of you but it still giving me headache when I think about it.
I have a repository class that takes a domain name to be instanciated :
public class RepositoryUserAD : IRepositoryUserAD , IDisposable
{
PrincipalContext context;
public RepositoryUserAD(string domainName)
{
if (string.IsNullOrEmpty(domainName))
throw new Exception("the domainName cannot be null or empty");
DomainName = domainName;
context = new PrincipalContext(ContextType.Domain, DomainName);
}
public UserPrincipal GetUser(string username)
{
UserPrincipal foundUser = null;
foundUser 开发者_如何学Python= UserPrincipal.FindByIdentity(context, username);
return foundUser;
}
public void Dispose()
{
context.Dispose();
}
}
And here is my problem. If I work like this it is ok but I do not like to have my context opened with the class and closed on the dispose of the class. I can also use a using block but then I am facing another problem because I lose my reference to the context and thus to the object, or at least to the properties I did not get first.
My architecture is the following
Repository r = new Repository();
Service s = new Service(r);
I am torn in two because in my general approach, I would have liked to be able to filter my query in the service and ask the repository to really fetch the data. But here with the AD, I cannot, open and close my connection at the Repository level, or I losse the flexibility and the repository is fetching everything.
Everything is not clear because it is not clear either in my head, I just hope someone might show me one way out of this s***.
Thanks for your support,
I'm assuming there's some reason you don't just create & destroy the context for each method, efficiency?
I would create a context factory that caches contexts somehow, e.g.
public class ContextFactory {
private List<PrincipalContext> contexts = new List<PrincipalContext>();
public PrincipalContext GetPrincipalContext(ContextType contextType, string domainName)
{
PrincipalContext existingContext = contexts.First(item=>item.ContextType==contextType &&
item.DomainName == domainName);
if (existingContext == null) {
existingContext = new PrincipalContext(contextType,domainName);
contexts.Add(existingContext);
}
return(existingContext);
}
}
public void Dispose()
{
foreach (PrincipalContext context in contexts) {
context.Dispose();
}
}
}
Then in whatever scope you want to use this, create a new instance of the class and use it to get a context, and dispose of it at the end. If this was a web app, it would be trickier to use it beyond the scope of a single page, but you could create (e.g.) a session cache of contexts, and have the object also periodically dispose of them if unused for some period of time. Also this code will have a race condition so you need to deal with that but this is the basic idea. This is essentially similar to the way connection pooling works.
What does the Service
class do ?
How about this:
public class RepositoryUserAD : IRepositoryUserAD
{
private readonly PrincipalContext context;
public RepositoryUserAD(PrincipalContext c)
{
context = c;
}
public UserPrincipal GetUser(string username)
{
return UserPrincipal.FindByIdentity(context, username);
}
}
By injecting the context into the repository, the repository is no longer responsible of deciding when to dispose the context. The 'caller' of the repository is responsible for it, and this is a good thing, since the repository does not know if the PrincipalContext is still necessary a little bit later (by another repository for instance).
精彩评论