I am creating custom membership provider for my asp.net application. I have also created a separate class "DBConnect" that provides database functionality such as Executing SQL statement, Executing SPs, Executing SPs or Query and returning SqlDataReader and so on...
I have created instance of DBConnect class within Session_Start of Global.asax and stored to a session. Later using a static class I am providing the database functionality throughout the application using the same single session. In short I am providing a single point for all database operations from any asp.net page.
I know that i can write my own code to connect/disconnect database and execute SPs within from the methods i need to override. Please look at the code below -
public class SGI_MembershipProvider : MembershipProvider
{
......
public override bool ChangePassword(string username, string oldPassword, string newPassword)
{
if (!ValidateUser(username, oldPassword))
return false;
ValidatePasswordEventArgs args = new ValidatePasswordEventArgs(username, newPassword, true);
OnValidatingPassword(args);
if (args.Cancel)
{
if (args.FailureInformation != null)
{
throw args.FailureInformation;
}
else
{
throw new Exception("Change password canceled due to new password validation failure.");
}
}
.....
//Database connectivity and code execution to change password.
}
....
}
MY PROBLEM -
Now what i need is to execute the database part within all these overriden methods from the same database point as described on the top. That is i have to pass the instance of DBConnect existing in the session to this class, so that i can access the methods.
Could anyone provide solution on this. There might be some better techniques i am not aware of that. The approach i am using might be wrong. Your suggessions are always welcome.
Thanks for sharing your valuable time.
Understanding the lifecycle of the membership provider would help clear this up.
An instance of the membership provider is spun up when the application is started and remains active for the lifetime of the application AppDomain, which in practice equates to the application lifecycle. e.g. If for some reason the AppDomain cycles, the application is disposed and a new instance is spun up. A new instance of the registered membership provider is spun up on first use.
You need to either instantiate an instance of you data access class within your membership provider implementation or access static methods from within your provider. I prefer to use an instance.
Separating the membership provider from it's data access by creating singletons or stashing it in application is a hack in my opinion and will lead to nothing but pain, sorrow, lost sleep and credibility amongst your peers.
Cheers and good luck.
Dont keep a seperate instance of the DBConnect class in session, you will end up creating a class for each user! This will seriously affect scalability.
You can do one of the following :
Place the class in Application state
Use the singleton pattern
Make the class and all the methods in the class static.
My recommendation is to go for number 3. You dont usually need to create an instance of a class that does database crud operations eg
public static class DBConnect
{
public static ChangePassword(string userId, string password)
{
//Implementation here
}
}
Then you can simply call this code in your provider without creating an instance:
DBConnect.ChangePassword(x,y);
Related
tl;dr How can I use Entity Framework in a multithreaded .NET Core API application even though DbContext is not threadsafe?
Context
I am working on a .NET Core API app exposing several RESTful interfaces that access the database and read data from it, while at the same time running several TimedHostedServices as background working threads that poll data regularly from other webservices and store them into the database.
I am aware of the fact that DbContext is not threadsafe. I read a lot of docs, blog Posts and answers here on Stackoverflow, and I could find a lot of (partly contradictory) answers for this but no real "best practice" when also working with DI.
Things I tried
Using the default ServiceLifetime.Scoped via the AddDbContext extension method results in exceptions due to race conditions.
I don't want to work with locks (e.g. Semaphore), as the obvious downsides are:
the code is polluted with locks and try/catch/finally for safely releasing the locks
it doesn't really seem 'robust', i.e. when I forget to lock a region that accesses the DbContext.
it seems redundant and 'unnatural' to artificially syncronize db access in the app when working with a database that also handles concurrent connections and access
Not injecting MyDbContext but DbContextOptions<MyDbContext> instead, building the context only when I need to access the db, using a using statement to immediatelly dispose it after the read/write seems like a lot of resource usage overhead and unnecessarily many connection opening/closings.
Question
I am really puzzled: how can this be achived?
I don't think my usecase is super special - populating the db from a Background worker and querying it from the web API layer - so there should be a meaningful way of doing this with ef core.
Thanks a lot!
You should create a scope whenever your TimedHostedServices triggers.
Inject the service provider in your constructor:
public MyServiceService(IServiceProvider services)
{
_services = services;
}
and then create a scope whenever the task triggers
using (var scope = _services.CreateScope())
{
var anotherService = scope.ServiceProvider.GetRequiredService<AnotherService>();
anotherService.Something();
}
A more complete example is available in the doc
Another approach to create own DbContextFactory and instantiate new instance for every query.
public class DbContextFactory
{
public YourDbContext Create()
{
var options = new DbContextOptionsBuilder<YourDbContext>()
.UseSqlServer(_connectionString)
.Options;
return new YourDbContext(options);
}
}
Usage
public class Service
{
private readonly DbContextFactory _dbContextFactory;
public Service(DbContextFactory dbContextFactory)
=> _dbContextFactory = dbContextFactory;
public void Execute()
{
using (var context = _dbContextFactory.Create())
{
// use context
}
}
}
With factory you don't need to worry about scopes anymore, and make your code free of ASP.NET Core dependencies.
You will be able to execute queries asynchronously, which not possible with scoped DbContext without workarounds.
You always be confident about what data saved when calling .SaveChanges(), where with scoped DbContext there are possibilities that some entity were changed in other class.
I'm in a situation where the classic functionality of vnext's DI container is not enough to provide me with the correct functionality. Let's say I have a DataService that gets data from a database like this:
public class DataService : IDataService, IDisposable {
public List<MyObject> GetMyObjects()
{
// do something to fetch the data...
return myObjects;
}
}
I can then register this service in the DI container during the configuration phase in Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddScoped(typeof(IDataService), typeof(DataService));
}
This ensures the correct lifecylce of the service (one per request scope), however, I need the service to access a different database when a different request is made. For simplicity reasons, let's say the following scenario applies:
when a request to my Web API is made, the DataService will access the currently logged in user, which contains a claim called Database which contains the information which database to use.
the DataService is then instantiated with the correct database connection.
In order to get the second step to work, I have created a constructor for the DataService like this:
public DataService(IHttpContextAccessor accessor)
{
// get the information from HttpContext
var currentUser = accessor.HttpContext.User;
var databaseClaim = currentUser.Claims.SingleOrDefault(c => c.Type.Equals("Database"));
if (databaseClaim != null)
{
var databaseId = databaseClaim.Value;
// and use this information to create the correct database connection
this.database = new Database(databaseId);
}
}
By using the currently logged in user and his claims, I can ensure that my own authentication middleware takes care of providing the necessary information to prevent attackers from trying to access the wrong database.
Of course adding the IDisposable implementation is required to cleanup any database connections (and gets called correctly using the scope lifecycle).
I can then inject the DataService into a controller like this
public MyController : Controller
{
private IDataService dataService;
public MyController(IDataService dataService)
{
this.dataService = dataService;
}
}
This all works fine so far.
My questions now are:
Is there another way to create the instance other than using the constructor of the DataService? Maybe accessing the object the IServiceCollection provides in a different place other than during the configration phase which runs only once? Maybe using my own OWIN middleware?
Is this method really safe? Could two requests made at the same time accidentally end up with the DataServiceintended for the other request and therefore end up giving out the wrong data?
What you have is fine.
Is there another way to create the instance other than using the constructor of the DataService? Maybe accessing the object the IServiceCollection provides in a different place other than during the configration phase which runs only once? Maybe using my own OWIN middleware?
Not really. You can use delegate registration but it's the same problem.
Is this method really safe?
Yes
Could two requests made at the same time accidentally end up with the DataServiceintended for the other request and therefore end up giving out the wrong data?
Nope. The IHttpContextAcessor uses AsyncLocal (http://blog.stephencleary.com/2013/04/implicit-async-context-asynclocal.html) to provide access to the "current" http context.
I am creating a login system and I want a way to sort of cache information without retrieving the same information from the database.
for example I would have a static class called tokenData. token data would be a private class to store login token, username, expireDate, etc. So every time I visit another page it would check the static class for the data. The token is then stored in session / cookie to produce the lookup. If the data is not in the token static class (e.g. application pool restart) then it would check the database for the record when the user logs in and creates another based on the data in the token table.
Can someone offer me any advice is this is acceptable practice or offer me anything to improve and issues that can arise?
an exmaple is
public class userToken
{
private string name;
private string tokenId;
private static List<userToken> userData = new List<userToken>();
public void add(userToken);
public userToken Find(string tokenId);
}
Never ever ever use static for user or session specific data. static is shared across ALL sessions! You might end up with user sessions sharing confidential data.
Use HttpContext.Session or HttpContext.Cache.
Your solution can introduce errors when run on more than a single server with a single user. The cache you are building is not thread safe. It will also introduce errors when your app is run across 2+ servers in a cluster (load balanced).
I would look into using a proper caching toolset (memcached, etc.)
We are using Ninject.MVC5 and Ninject.Extention.Conventions in a multi-tenant web environment with multiple databases, one for each tenant along with a primary EF database. When a user logins in, we find them in the primary database and determine what database they should work with so we can bind all our datacontexts to that DB. (We use EF for the primary database and Linq to SQL for the tenant DB).
Here is the initial bind:
private static void RegisterServices(IKernel kernel)
string TennantConnection= ConfigurationManager.AppSettings["DSN"] ?? "";
kernel.Bind<TenantDB>()
.ToSelf()
.InRequestScope()
.WithConstructorArgument(typeof(string), TennantConnection);
Where TennantConnection is a dummy default connection string initially
Here is the Rebind that is called after the login with the updated connection string
kernel.Rebind<TenantDB>().ToSelf().InRequestScope().WithConstructorArgument(typeof(string), ConfigConnection);
The kernel is injected into the constructor for the rebind class as follows:
public DataContextTennant(IKernel kernel)
All of the rest of the injections are done by convention.
The issue is that when we deploy the site (it happens to be an Azure Cloud app) many of the users get an error of an invalid SQL connection after first login which I believe is due to the rebind. But if they use a private browser session the rebind seems to work both for that session and subsequent sessions.
Although I was unable to resolve it with Ninject, I was able to resolve the issue with Unity. From the controller, after retrieving the tenant connection string, I call this:
public static void RegisterDBTypes(IUnityContainer container, string connection)
{
container.RegisterType<ADataContext>(new PerRequestLifetimeManager(), (new InjectionConstructor(connection)));
container.RegisterType<RDataContext>(new PerRequestLifetimeManager(), (new InjectionConstructor(connection)));
container.RegisterType<PDataContext>(new PerRequestLifetimeManager(), (new InjectionConstructor(connection)));
}
This rebinds the data contexts which flows through to the various services and repositories.
I suggest that Ninject is working as expected. You should look into why the TenantDB is instanciated before login is complete and rebind is done. This should be what's causing your issues.
To do so, you should start with removing your default TenantDB binding:
string TennantConnection= ConfigurationManager.AppSettings["DSN"] ?? "";
kernel.Bind<TenantDB>()
.ToSelf()
.InRequestScope()
.WithConstructorArgument(typeof(string), TennantConnection);
because after all, this binding only results in a TenantDB which is unusable, so why bother? It's just post-poning the issue to later - making it harder to detect.
It's much better to fail fast - have ninject throw an ActivationException! (which happens if there's no binding).
This should help you in finding out under which circumstances TenantDB is instanciated before login is complete.
Edit: Verification that IBindingRoot.Rebind works:
public class Test
{
[Fact]
public void Foo()
{
const string text1 = "Text1";
const string text2 = "Text2";
var kernel = new StandardKernel();
kernel.Bind<string>().ToConstant(text1);
kernel.Get<string>().Should().Be(text1);
kernel.Rebind<string>().ToConstant(text2);
kernel.Get<string>().Should().Be(text2);
}
}
Ninject's rebind works. I think you're making a configuration mistake and when using ninject, your building parts of your object tree - which depend on the DbContext before the Rebind is done. Thus "pre-login DbContext" leaks through to after login.
If i should be mistaken, you should create a minimal verifiable example and post it on Ninject's Issue tracker.
I have a WCF service that is using a custom UsernamePasswordValidator. The validator needs to access my entity framework context.
I would like to create one ObjectContext for the entire service call and then destroy/dispose it at the end of the call. So I created a singleton static class that provided this functionality, however, what's happening now is that if two service calls happen concurrently, one of the calls disposes the singleton.
I either keep a local reference to the ObjectContext, in which case the second service to use it sees it as disposed and throws and error, or, I put a wrapper property around the Singleton class wherever I need it and then all my changes get thrown away because I'm getting a new instance of the object if another call has disposed it.
So basically my question is how do I instantiate an ObjectContext per service call?
NOTE: The instance needs to be accesible in both the service code AND the custom UsernamePasswordValidator code.
I can't just do it in the constructor or use a using statement because then the custom UsernamePasswordValidator doesn't have access to it. Is there a way to have a static class per call? It does sound impossible, but what's the way around this? Should I be caching the object in a session?
My service is hosted in IIS.
UPDATE:
So I've nailed this down to storing state in the InstanceContext using an IExtension object. But How do I access the current InstanceContext in a UsernamePasswordValidator?
Ok, so in the end I solved it by using the following static class and relying on ASP.NET to cache the context for me.
I'm not sure if this is the best way to do things, but this allows me to use one ObjectContext per request so I'm not spinning up too many and this also means I don't have to use a lock on the object which would become a nightmare if many users were using the service.
public static class MyContextProvider
{
public static MyModel Context
{
get
{
if (HttpContext.Current.Items["context"].IsNull())
{
HttpContext.Current.Items["context"] = new MyModel();
}
return HttpContext.Current.Items["context"] as MyModel;
}
}
}
Then wherever I need an ObjectContext in the app I just call
var context = MyContextProvider.Context;
You have one instance per call, you also have 1 call per instance.
So it should be very simple, use a using () { } block in the toplevel of your OperationContract method.
Ok, here is the class with thread-safe static method that provides single ObjectContext entity model object for any WCF service call and automatically dispose it at the end of call:
public static class EntityModelProvider
{
private static readonly Dictionary<OperationContext, MyEntityModel> _entityModels = new Dictionary<OperationContext, MyEntityModel>();
public static MyEntityModel GetEntityModel()
{
if (OperationContext.Current == null)
throw new Exception("OperationContext is missing");
lock (_entityModels)
{
if (!_entityModels.ContainsKey(OperationContext.Current))
{
_entityModels[OperationContext.Current] = new MyEntityModel();
OperationContext.Current.OperationCompleted += delegate
{
lock (_entityModels)
{
_entityModels[OperationContext.Current].Dispose();
_entityModels.Remove(OperationContext.Current);
}
};
}
return _entityModels[OperationContext.Current];
}
}
For your service, you can specify a service behaviour which details the instance mode of the service:
[ServiceBehaviour(InstanceContextMode = InstanceContextMode.PerCall)]
public class MyService : IMyService {
ObjectContext context;
}
A cleaner way may be to use the ServiceAuthenticationManager, which is in .NET 4.
http://msdn.microsoft.com/en-us/library/system.servicemodel.serviceauthenticationmanager.aspx
From the Authenticate method (which you'll override) you can access the Message object and set properties on it. I've not used it in anger, so YMMV :)
EDIT the problem with this approach is that you don't have the Username and Password, so will still need the custom Authentication.
Take a look at the UsernameSecurityTokenAuthenticator...
http://msdn.microsoft.com/en-us/library/system.identitymodel.selectors.usernamesecuritytokenauthenticator(v=vs.90).aspx
Further reading from my research:
Answers to this question gives some hints about how to use it:
Custom WCF authentication with System.ServiceModel.ServiceAuthenticationManager?
If you can read (or ignore) the Russian, I found useful hints at:
http://www.sql.ru/forum/actualthread.aspx?tid=799046
This rather good CodeProject article goes further (encryption and compression as well as custom authorization)
http://www.codeproject.com/Articles/165844/WCF-Client-Server-Application-with-Custom-Authenti
Why not pass in the context into your CustomValidator when you assign to the service - store your object context in your validator, and in the overridden validation method new it up if need be. Then you still have access to the object through the Services CutomUserNameValidator ..
Depending on what you are asking :
Create your separate ObjectContext class as a dynamic object - add that as a property to you CustomValidator.
In your custom Validator - you can now check if the object is disposed and create the object again if need be.
Otherwise if this is not what you are after - just store the Context in the validator - you still have access on server side.
The code here is just generalized idea - I am just posting it as a frame of reference so you can have an idea of what I talking about.
public DynamicObjectContextObjectClass
{
ObjectContext internalObjectContext;
}
public class ServiceUserNamePasswordValidator : UserNamePasswordValidator
{
public DynamicObjectContextObjectClass dynamiccontext;
public override void Validate(string userName, string password)
{
if(dynamiccontext.internalObjectContext.isdisposed)
{
dynamiccontext.internalObjectContext = new Context;
}
try
{
if (string.IsNullOrEmpty(userName) || password == null)
{
//throw new ArgumentNullException();
throw new FaultException("Username cannot be null or empty; Password cannot be null and should not be empty");
}
}
}
}