The connection string for our app is set in appsettings.json
"Data": {
"DefaultConnection": {
"ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Customers;Trusted_Connection=True;MultipleActiveResultSets=true",
In ConfigureServices we have
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<CustomersContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
This seems to work in cases like this
var membershipUser = await _userManager.FindByEmailAsync(email);
and this
var result = await _userManager.CreateAsync(newUser);
but falls over when I try this
using (var customers = new CustomersContext())
{
var deviceList = customers.Devices.Where(d => d.UserId == membershipUser.Id);
The error is InvalidOperationException: No database providers are configured. Configure a database provider by overriding OnConfiguring in your DbContext class or in the AddDbContext method when setting up services.
If I try this
public partial class CustomersContext : IdentityDbContext<ApplicationUser>
// note this inherits from IdentityDbContext<ApplicationUser> not DbContext
// refer http://stackoverflow.com/questions/19902756/asp-net-identity-dbcontext-confusion
{
protected override void OnConfiguring(DbContextOptionsBuilder options)
{
options.UseSqlServer(#"Server=(localdb)\\mssqllocaldb;Database=Customers;Trusted_Connection=True;MultipleActiveResultSets=true");
}
I get this error
Local Database Runtime error occurred. Specified LocalDB instance name is invalid
Why is it my app can find the database in some cases but not others?
The problem is that although you've configured a CustomerContext with the DI services as shown here:
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<CustomersContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
You are not having the CustomerContext injected, instead you are newing it up like this:
using (var customers = new CustomersContext())
{
...
}
using a constructor that takes no parameters, so your CustomersContext is not configured like the one in startup and it has no connection string.
Since you mention you need it in the AccountController, then all you need to do is add CustomersContext to the constructor of AccountController, so that the one you configured in startup will get injected. Like this:
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ISmsSender _smsSender;
private readonly ILogger _logger;
private CustomersContext _customerContext;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory,
CustomersContext customerContext)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
_customerContext = customerContext;
}
That way you get a properly configured CusotmersContext and you don't have to new it up yourself. If for some reason you did want to new it up yourself you need to do so using a constructor that takes IServiceProvider and DbContextOptions. So you would receive those objects in the constructor of AccountController and you would pass them in as you new up the CustomersContext like this:
using (var customers = new CustomersContext(serviceProvider, dbContextOptions))
{
...
}
Related
I need to migrate an MVC project to .net Core, I know it has System.Web removed from ASP.net Core.
I need to convert
HttpContext.Current.Session ["name"]! = Null at asp.net core.
I added:
using Microsoft.AspNetCore.Http
but I have an error.
Use like this:
HttpContext.Session.SetString("priceModel", JsonConvert.SerializeObject(customobject));
var priceDetails = HttpContext.Session.GetString("priceModel");
Make sure below points in startup class:
AddSession in ConfigureServices method
services.AddSession();
Usesession in configure method:
app.UseSession();
you don't have System.Web.HttpContext.Current.Session in ASP.NET Core. To access session in non-controller class
step1:
First, register the following service in Startup.ConfigureServices;
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
step2:
register a class (example - TestOrder) where you want to access the Session in
Startup.ConfigureServices;
services.AddScoped<TestOrder>();
Now, in TestOrderclass, add the following code.
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly ISession _session;
public TestOrder(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
_session = _httpContextAccessor.HttpContext.Session;
}
The above code is receiving IHttpContextAccessor object through dependency injection and then, it is storing Sessions in a local variable.
The recommended approach is to register a dependency using the built-in dependency injection container. Inject IHttpContextAccessor into the corresponding service.
public class UserRepository : IUserRepository
{
private readonly IHttpContextAccessor _httpContextAccessor;
public UserRepository(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void LogCurrentUser()
{
var username = _httpContextAccessor.HttpContext.Session.GetString("UserName");
service.LogAccessRequest(username);
}
}
For more details, refer to this link
Did you test Microsoft doc, a sample is like below
public const string SessionKeyName = "_Name";
public const string SessionKeyAge = "_Age";
const string SessionKeyTime = "_Time";
// Requires: using Microsoft.AspNetCore.Http;
if (string.IsNullOrEmpty(HttpContext.Session.GetString(SessionKeyName)))
{
HttpContext.Session.SetString(SessionKeyName, "The Doctor");
HttpContext.Session.SetInt32(SessionKeyAge, 773);
}
var name = HttpContext.Session.GetString(SessionKeyName);
var age = HttpContext.Session.GetInt32(SessionKeyAge);
I've been following the NServiceBus samples, specifically for how to use an entity framework (core) DbContext integrated with Sql Persistence so that I can save dbcontext state changes along with the outbox messages. This is the sample: https://docs.particular.net/samples/entity-framework-core/
I've modified the unit of work code a little to support creation of an aspnet core DI scoped DbContext. The relevant code follows:
public class UnitOfWork<TDbContext>
where TDbContext : DbContext
{
private Func<SynchronizedStorageSession, IServiceProvider, TDbContext> _contextFactory;
private TDbContext _context;
private IServiceProvider _serviceProvider;
public UnitOfWork(Func<SynchronizedStorageSession, IServiceProvider, TDbContext> contextFactory, IServiceProvider serviceProvider)
{
_contextFactory = contextFactory;
_serviceProvider = serviceProvider;
}
public TDbContext GetDataContext(SynchronizedStorageSession storageSession)
{
if (_context == null)
{
_context = _contextFactory(storageSession, _serviceProvider);
}
return _context;
}
}
public class UnitOfWorkSetupBehavior<TDbContext> : Behavior<IIncomingLogicalMessageContext>
where TDbContext : DbContext
{
private readonly Func<SynchronizedStorageSession, IServiceProvider, TDbContext> _contextFactory;
private readonly IServiceScopeFactory _serviceScopeFactory;
public UnitOfWorkSetupBehavior(Func<SynchronizedStorageSession, IServiceProvider, TDbContext> contextFactory, IServiceScopeFactory serviceScopeFactory)
{
_contextFactory = contextFactory;
_serviceScopeFactory = serviceScopeFactory;
}
public override async Task Invoke(IIncomingLogicalMessageContext context, Func<Task> next)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var uow = new UnitOfWork<TDbContext>(_contextFactory, scope.ServiceProvider);
context.Extensions.Set(uow);
await next().ConfigureAwait(false);
context.Extensions.Remove<UnitOfWork<TDbContext>>();
}
}
}
public static class EndpointConfigurationExtensions
{
public static void RegisterUnitOfWork<TDbContext>(this EndpointConfiguration endpointConfiguration, IServiceScopeFactory serviceScopeFactory)
where TDbContext : DbContext
{
var pipeline = endpointConfiguration.Pipeline;
pipeline.Register(new UnitOfWorkSetupBehavior<TDbContext>((storageSession, serviceProvider) =>
{
var dbConnection = storageSession.SqlPersistenceSession().Connection;
var dbContextFactory = serviceProvider.GetService<IDbContextConnectionFactory<TDbContext>>();
var dbContext = dbContextFactory.GetDbContext(dbConnection);
//Use the same underlying ADO.NET transaction
dbContext.Database.UseTransaction(storageSession.SqlPersistenceSession().Transaction);
//Call SaveChanges before completing storage session
storageSession.SqlPersistenceSession().OnSaveChanges(x => dbContext.SaveChangesAsync());
return dbContext;
}, serviceScopeFactory), "Sets up unit of work for the message");
}
}
public static class UnitOfWorkContextExtensions
{
public static TDbContext DataContext<TDbContext>(this IMessageHandlerContext context)
where TDbContext : DbContext
{
var uow = context.Extensions.Get<UnitOfWork<TDbContext>>();
return uow.GetDataContext(context.SynchronizedStorageSession);
}
}
For this to work the behavior needs an injected IServiceScopeFactory.
Now all examples I've been able to find of behavior registration only show the type manually instantiated and passed in to the endpointconfiguration's pipeline.
Is there a way to either gain access to an IServiceScopeFactory via the behavior's Invoke method (maybe by the context via some extension perhaps?), or is it possible to register the behavior itself such that I can construct it with services created by the DI container?
FYI I took a look at this Q&A which gave me the idea of injecting the IServiceScopeFactory. Unfortunately, the answer doesn't show how to actually get an instance of the interface.
You would use context.builder.Build<T>(); within the Invoke method to resolve any objects like IServiceScopeFactory.
https://docs.particular.net/samples/multi-tenant/di/
Make sure that the IServiceScopeFactory is registered in the DI container. For example, during your endpoint initialization:
endpointConfiguration.RegisterComponents(registration: x =>
{
x.ConfigureComponent<IServiceScopeFactory>(yourServiceScopeFactory);
});
https://docs.particular.net/nservicebus/dependency-injection/
You can also do this by creating a Feature
https://docs.particular.net/nservicebus/pipeline/features
I want to use Repository with AspNetCore.Identity UserManager. But I am getting error when defined in Controller.
Repository
public class TestRepository
{
private readonly UserManager<tblApplicationUser> _userManager;
public TestRepository(UserManager<tblApplicationUser> userManager)
{
this._userManager = userManager;
}
}
Controller:
private TestRepository _testRepository;
public TestController()
{
this._testRepository = new TestRepository(new UserManager<tblApplicationUser>);
}
I am getting error in controller at new UserManager
It seems you are missing braces (for UserManager constructor) before the last brace?
this._testRepository = new TestRepository(new UserManager<tblApplicationUser>());
You should let the DI handle instantiation of UserManager and Repository. You can check out this article on official docs for ASP.NET Core.
I have this seeder class which is called at the end of the Startup.cs file in the Configure method:
public class UserSeeder
{
private readonly ApplicationDbContext _context;
private readonly UserManager<ApplicationUser> _userManager;
public UserSeeder(ApplicationDbContext context, UserManager<ApplicationUser> userManager)
{
_context = context;
_userManager = userManager;
}
public async Task Seed()
{
if (!await _context.Users.AnyAsync())
{
var user = new ApplicationUser()
{
UserName = "admin",
Email = "admin#test.com"
};
await _userManager.CreateAsync(user, "passwort4admin");
}
}
}
The code is executed and I even put a try/catch around the method call but no error happens AND no user is inserted into the database!
Why not?
The problem is the complexity of the password. Add capital and numbers and symbols the issue will solve
Behind the scenes the UserManager<> uses a IUserStore did you configure this userstore in the startup.cs in the IOC container?
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<MyContext, Guid>()
.AddUserStore<ApplicationUserStore>() //this one provides data storage for user.
.AddRoleStore<ApplicationRoleStore>()
.AddUserManager<ApplicationUserManager>()
.AddRoleManager<ApplicationRoleManager>()
.AddDefaultTokenProviders();
In my case, it was a space in the user name. It's possible that you have other constraints set up that make the user creation operation illegal.
In most cases, you can obtain explicit information on the exact cause of the error by investigating the message in the returned object from the operation.
IdentityUser userToBe = ...
IdentityResult result = await UserManager.CreateAsync(userToBe);
if(!result.Succeeded)
foreach(IdentityError error in result.Errors)
Console.WriteLine($"Oops! {error.Description} ({error.Code}));
I forgot to set "Username", it cannot be empty.
I set UserName=userEmail and it works
How would you seed users? I am following their documents here, but they only show how to seed data that is inserted directly by the ApplicationDbContext.
In the Account controller, the UserManager is created through DI. How would I instantiate a UserManager in the Seed method?
public class SeedData
{
public static void Initialize(IServiceProvider serviceProvider)
{
var context = serviceProvider.GetService<ApplicationDbContext>();
var userManager = serviceProvider.GetService<UserManager<ApplicationUser>>();
Then in Startup.cs in the Configure method:
SeedData.Initialize(app.ApplicationServices);
In the startup.cs in the configure method, you can add the following code to get the UserManager and from there seed the users.
var userManager = app.ApplicationServices.GetService<UserManager<ApplicationUser>>();
You would create a class in the lines of
public class UserSeed
{
private ApplicationDbContext _context;
private UserManager<ApplicationUser> _mgr;
public UserSeed(ApplicationDbContext context,UserManager<ApplicationUser> userManager)
{
_context = context;
_mgr = users;
}
public void UserSeedData()
{
var user = new ApplicationUser { UserName = "foo#foo.com", Email = "foo#foo.com" };
var result = _mgr.CreateAsync(user,"fooPassword");
......
......
}
}
In the configure method of your startup.cs take userSeed through DI like
public async void Configure(...., UserSeed userSeedData)
and then inside the method you call
userSeedData.UserSeedData();
Don't use this code as is, you would probably want to check if the user already exists before you create it.
Note: This method will run once every time your application starts.