I'm in the process of building a user management microservice using an API.NET Web API. I've added EntityFrameworkCore and using SQL Server as the database. I've made multiple services at this point, but this service does not seem to work the way I want it to.
FYI I'm using .NET 6.
The code you see below is how I add the AddDbContext to my Services in the Program.cs file.
builder.Services.AddDbContext<AppDbContext>(opt =>
{
// Getting the ConnectionString from the AppSettings-file.
string connectionString = builder.Configuration.GetConnectionString("Connection1");
Console.WriteLine("=====CONNECTION STRING=====");
Console.WriteLine("ConnectionString: " + connectionString + "\n");
Console.WriteLine("=====IT Asset Management=====");
Console.WriteLine("Service running: User Service");
if (builder.Environment.IsProduction())
Console.WriteLine("Environment is: PRODUCTION");
else
Console.WriteLine("Environment is: DEVELOPMENT");
// Configuring the DBContext to connect to the SQL server.
opt.UseSqlServer(connectionString);
});
When i run the code, my Console.WriteLines does not print, and it does not seem that the AddDbContext service gets initialized.
Below is my DbContext.
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using UserService.Models;
namespace UserService.Data
{
public class AppDbContext : IdentityDbContext<AppUser>
{
public AppDbContext(DbContextOptions<AppDbContext> options)
: base(options) { }
}
}
As of now I have tried everything I can think of and gotten help from colleagues, but we can't seem to find out what's wrong. I have another service running the exact same code, but with a different purpose (Only the Program.cs files are the same), so I've tried to copy paste the file. I have tried to reinstall all the related NuGet-packages, which did not work.
Then i tried to create a new ASP.NET Web API project and only installing the packages needed to make the DbContext and setup the service in the Program.cs file. Below is the Program.cs file from the new project.
The funny thing is that it does not work aswell in the new project and I have no idea why.
using UserManagement.Data;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddDbContext<AppDbContext>(opt =>
{
Console.WriteLine("=====IT Asset Management=====");
Console.WriteLine("Service running: User Service");
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
I cannot think of anything I have done differently between these three projects.
UPDATE 1:
I found this post: AddDbContext doesn't call DbContext constructor
and one of the answers was that I needed to use migrations. I have not migrated anything from this project, since there is no tables to be made. I am using the default Identity tables, and they are created by another service. But when I added the migrations the Console.WriteLines got printed. Then i ran the project with "dotnet run" but then the prints were gone. Why is this?
So I seemed that one of the answers inside the post in UPDATE 1, actually was the solution to the issue. I did indeed have to use the DbContext in some context. I added a dataseeding class which is called from the program.cs file, and it seems that the console.writelines are printed every time now.
Related
I'm using a clear architecture for a NET7 project with Blazor. In the Persistence layer, I have a function to register the database and all the repositories
public static class PersistenceServiceRegistration
{
public static IServiceCollection AddPersistenceServices(
this IServiceCollection services,
IConfiguration configuration,
string cnnStringName = "LIUContextConnection")
{
var cnnString = configuration.GetConnectionString(cnnStringName);
services.AddDbContext<LIUContext>(options =>
options.UseSqlServer(cnnString)
);
services.AddScoped<IArticleRepository, ArticleRepository>();
return services;
}
}
So, in the Program.cs I can register the persistence like
builder.Services.AddPersistenceServices(builder.Configuration);
I want to be sure that the database is created before the application starts. I added the following code an the end of the Program.cs
var app = builder.Build();
LIUContext dbcontext = app.Services.GetRequiredService<LIUContext>();
dbcontext.Database.EnsureCreated();
await app.RunAsync();
When I run the application, I get an error because
Microsoft.Data.SqlClient is not supported on this platform
I added in the Client project and in the Persistence project the NuGet package but I get the some error.
If I create the database from the Package Manager Console is working.
"is not supported on this platform" is of course the main point.
The platform here is dotnet in the Browser and a lot of APIs are not (cannot be) supported. The SqlClient needs sockets and they are not allowed in the browser. Also, you wouldn't be able to keep the credentials secret.
There is some limited support for SqLite and you have the built-in IndexedDb.
For a full SQL Db, the common approach is to use a WebService (Blazor Wasm Hosted template) to handle the Db access.
I am currently trying to teach myself ASP.NET, as I will need it on the job soon. For testing purpose, I want to create a simple project with 1 or 2 RazorPages, which derives data from a MySQL database on my localhost. I am using the Visual Studio Community version. I started by creating a new ASP.NET Core Web Application project, then added a "New Connection" (see screenshot)
I also installed the packages "MySqlData", "MySqlData.EntityFrameworkCore" and "MySQLConnector". In appsettings.json, I added
"ConnectionStrings": {
"RazorPagesPlayersContext": "server=localhost;user=root;password=password;database=players;"
}
and in Startup.cs, I configured
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddDbContext<RazorPagesPlayersContext>(options => options.UseSqlite(Configuration.GetConnectionString("RazorPagesPlayersContext")));
}
However, when I to go to the create page and post a new "player" into the database, I am getting error
ArgumentException: Connection string keyword 'server' is not supported
My context file looks like this
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using RazorPagesPlayers.Models;
namespace RazorPagesPlayers.Data
{
public class RazorPagesPlayersContext : DbContext
{
public RazorPagesPlayersContext (DbContextOptions<RazorPagesPlayersContext> options)
: base(options)
{
}
public DbSet<RazorPagesPlayers.Models.Player> Player { get; set; }
}
}
When I check "Connected Services", I can only see this
I can see, that the connection string of this service has nothing to do with the connection string I added in appsettings.json. When I try to change it, it will just switch back. So I am guessing the connection to MySQL failed or am I confusing things here? I am not even sure if I am looking in the right direction, but every hint would be most welcome. Thank you very much in advance
Edit: When I change the Service config in Startup.cs to
services.AddDbContext<RazorPagesPlayersContext>(options => options.UseMySql(Configuration.GetConnectionString("RazorPagesPlayersContext")));
it tells me "DbContextOptionsBuilder" does not contains a defintion for 'UseMySql' and recommends to change it to UseMySQL. This however results in an error:
TypeLoadException: Method 'Create' in type 'MySql.Data.EntityFrameworkCore.Query.Internal.MySQLSqlTranslatingExpressionVisitorFactory' from assembly 'MySql.Data.EntityFrameworkCore, Version=8.0.22.0, Culture=neutral, PublicKeyToken=c5687fc88969c44d' does not have an implementation.
is there a point in installing Pomelo?
I have created a simple ASP.NET Core MVC application in Visual Studio. I also created a database using EF Core code first approach. The database uses Windows authentication.
The connection string I used was
Server=(local)\\sqlexpress;Database=LibraryEmployeeDB;Trusted_Connection=True;
I am supposed to send this project to my professor but when I tried to run the project from a different user on my computer it doesn’t work because I can’t connect to the database with the other user.
I tried to change to Windows and SQL Server authentication and create a new user and add that to the connection string but that didn’t work either. I would be so grateful for any tips on how to solve this problem so that my professor can run the project as it is supposed to. Thank you!
You should run init command to create the database :
"Update-Database" in the Package manager console in the Visual studio.
Your Connection String shulde be like this:
"ConnectionStrings": {
"ConnStr": "Data Source=(local)\\sqlexpress;Initial Catalog=LibraryEmployeeDB;Integrated Security=False;ApplicationIntent=ReadWrite;MultiSubnetFailover=False;Trusted_Connection=false;User ID=yourUsername;Password=yourPassword;"
}
and in Startup.cs you have to use this section:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<YourContext>(options => options.UseSqlServer(Configuration.GetConnectionString("ConnStr")));
//and other things
}
I have a .net core solution that contains a database project (class library) and a console application. The database project contains EF Migrations and to do Add-Migration, most methods use a hard-coded connection string in one place or the other.
To avoid hard-coding (and/or duplication) I have created a shared appsettings.json file in the solution root and I use it in my Main method and the class library
In the console application
static void Main(string[] args)
{
var settingPath = Path.GetFullPath(Path.Combine(#"../appsettings.json"));
var builder = new ConfigurationBuilder()
.AddJsonFile(settingPath, false);
var configuration = builder.Build();
var services = new ServiceCollection()
.AddDbContext<MyContext>(options => options.UseSqlServer(configuration["ConnectionStrings:MyDatabase"]))
.BuildServiceProvider();
}
And in the class library to use migrations
public class DesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyContext>
{
public MyContext CreateDbContext(string[] args)
{
var settingPath = Path.GetFullPath(Path.Combine(#"../appsettings.json"));
var builder = new ConfigurationBuilder()
.AddJsonFile(settingPath, false);
var configuration = builder.Build();
var optionsBuilder = new DbContextOptionsBuilder<MyContext>()
.UseSqlServer(configuration["ConnectionStrings:MyDatabase"]);
return new MyContext(optionsBuilder.Options);
}
}
This is working well for development purposes when I use dotnet run but when I publish the console application, it doesn't include the appsettings file. Other than running a powershell script as part of dotnet publish, is there any other cleaner way of including this file when the project is published?
IDesignTimeDbContextFactory is exactly for the purpose its name describes. You shouldn't be running migrations against your production database in the first place, and if you do, you should be generating specific migrations for production into your app (instead of the class library) and using your app for the migrations. See the docs on using a separate project for migrations. That, then, negates the need to share your appsettings.json. Just leave the connection string hard-coded in your factory, since it's only for development anyways.
Now, you might have an issue I suppose in a team environment. However, even if you're using something like SQLite, you can use project-relative paths that won't be developer-specific, and with LocalDB, you can use a normal SQL Server connection string to the MSSQLLocalDB instance, which will be same for every developer using Visual Studio. Regardless, even if you do need to specify the connection specifically by developer, at that point it would make more sense to use user secrets, anyways, since you wouldn't want that info be committed to source control. Otherwise, each developer would end up clobbering the other's copy of appsettings.json, and you'd have a mess on your hands.
Long and short, just hard-code the connection string in your factory, or if you can't or won't, use user secrets for the connection string. In either case, you do not need to share appsettings.json.
The way I've done this before is to specify the startup project when you run dotnet ef (with the -s switch - the options are at https://learn.microsoft.com/en-us/ef/core/miscellaneous/cli/dotnet#common-options)
It gets messy quickly, and it's probably easiest to write some wrapper scripts for the project that deal with this kind of thing.
I've just started my first MVC 6 project in visual studio 2015.
I'm fairly new to MVC and have been working on various projects using web-forms in visual studio 2013 for the past year, but seeing as web forms is fairly outdated I decided to jump in with both feet into the newest version on MVC.
Every time I try to run the project or dnx ef database update I get the same error.
The server was not found or was not accessible. Verify that the
instance name is correct and that SQL Server is configured to allow
remote connections
I've created all my models with entity framework (code first) and set them to the context
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
//UserModels
public DbSet<AppUser> Users { get; set; }
public DbSet<UserAddress> UserAddresses { get; set; }
//Other Models...
}
and set up my initial migration which all looks as it should.
I expected the database to be generated for me automatically in server explorer the first time I ran the application but I've seen that this is not something that's set up by default in MVC 6.
I've been following various tutorials and currently have in my appsettings.json
{
"Data": {
"DefaultConnection": {
"ConnectionString": "Server=(localdb)\\MSSQLLocalDB;Database=TestDb;Trusted_Connection=True;MultipleActiveResultSets=true"
}
},
and startup.cs
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddMvc();
// Add application services.
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
I assume the problem is something to do with with either the way my connection string is formatted or being passed into ConfigureServices as my localDb is set to allow remote connections.
Sorry for the long winded question, but I've been banging my head off the wall for most of the day!