Como ler a string de conexão no .NET Core?

108

Quero ler apenas uma string de conexão de um arquivo de configuração e, para isso, adicionar um arquivo com o nome "appsettings.json" ao meu projeto e adicionar este conteúdo nele:

{
"ConnectionStrings": {
  "DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-

 WebApplica71d622;Trusted_Connection=True;MultipleActiveResultSets=true"
  },
    "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
    "Default": "Debug",
    "System": "Information",
    "Microsoft": "Information"
   }
 }
}

No ASP.NET, usei isto:

 var temp=ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString;

Agora, como posso ler "DefaultConnection" em C # e armazená-lo em uma variável de string no .NET Core?

motevalizadeh
fonte

Respostas:

101

Você pode fazer isso com o método de extensão GetConnectionString:

string conString = Microsoft
   .Extensions
   .Configuration
   .ConfigurationExtensions
   .GetConnectionString(this.Configuration, "DefaultConnection");

System.Console.WriteLine(conString);

ou com uma classe estruturada para DI:

public class SmtpConfig
{
    public string Server { get; set; }
    public string User { get; set; }
    public string Pass { get; set; }
    public int Port { get; set; }
}

Comece:

public IConfigurationRoot Configuration { get; }


// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
    // http://developer.telerik.com/featured/new-configuration-model-asp-net-core/
    // services.Configure<SmtpConfig>(Configuration.GetSection("Smtp"));
    Microsoft.Extensions.DependencyInjection.OptionsConfigurationServiceCollectionExtensions.Configure<SmtpConfig>(services, Configuration.GetSection("Smtp"));

E então no home-controller:

public class HomeController : Controller
{

    public SmtpConfig SmtpConfig { get; }
    public HomeController(Microsoft.Extensions.Options.IOptions<SmtpConfig> smtpConfig)
    {
        SmtpConfig = smtpConfig.Value;
    } //Action Controller


    public IActionResult Index()
    {
        System.Console.WriteLine(SmtpConfig);
        return View();
    }

com isso em appsettings.json:

"ConnectionStrings": {
"DefaultConnection": "Server=(localdb)\\mssqllocaldb;Database=aspnet-WebApplica71d622;Trusted_Connection=True;MultipleActiveResultSets=true"
},

"Smtp": {
    "Server": "0.0.0.1",
    "User": "[email protected]",
    "Pass": "123456789",
    "Port": "25"
  }
Stefan Steiger
fonte
9
Configureé um método de extensão. Deve ser usado mais comumente assim: services.Configure<SmtpConfig>(Configuration.GetSection("Smtp"));Claro, é quase a mesma coisa, mas acho que as pessoas que não estão cientes vão simplesmente começar a fazer da maneira "errada", usando a linha não comentada, então talvez seja melhor remover a linha. ;)
James Wilkins
@James Wilkins: Preocupações muito válidas. No entanto, na verdade, prefiro essa notação em vez de usá-la como método de extensão - dessa forma, eu sei o que está sendo feito e onde posso copiar e colar de um lugar para outro, sem ter problemas devido à falta de namespaces de importação. O único problema é que a MS usa namespaces para taxonomia em vez de prevenção de colisão de nomes - por causa disso, os namespaces são muito longos. Além disso, se você remover os namspaces e usar os métodos de extensão, o mesmo tipo de pessoa começará a reclamar sobre o código não estar compilando. Nem todo mundo usa um IDE, então é melhor assim.
Stefan Steiger,
3
@JedatKinports: Não, apenas injeção. Mesmo se você escrever um método estático, ainda precisará da configuração. Você pode simplesmente ler um arquivo JSON / YAML manualmente, no entanto. Mas isso eliminará sobrescrições, como segredos do usuário ou outros (por exemplo, configuração do registro).
Stefan Steiger
1
Estou recebendo um erro: "MyClass contém uma definição para 'Configuração' ..."
Robert Smith
3
A que "this.Configuration" está se referindo na parte da string de conexão? GetConnectionString (this.Configuration, "DefaultConnection")
MC9000
111

A resposta postada está bem, mas não respondeu diretamente à mesma pergunta que eu tinha sobre a leitura em uma string de conexão. Por meio de muitas pesquisas, descobri uma maneira um pouco mais simples de fazer isso.

Em Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    ...
    // Add the whole configuration object here.
    services.AddSingleton<IConfiguration>(Configuration);
}

Em seu controlador, adicione um campo para a configuração e um parâmetro para ele em um construtor

private readonly IConfiguration configuration;

public HomeController(IConfiguration config) 
{
    configuration = config;
}

Agora, mais tarde em seu código de visualização, você pode acessá-lo como:

connectionString = configuration.GetConnectionString("DefaultConnection");
Brad Patton
fonte
2
Não faria assim. Se você trabalha sem estrutura de entidade, é melhor registrar um connection factory como singleton, por exemplo, para usar com dapper. Você ainda pode expor uma propriedade connectionString se precisar, mas aposto que não seria necessário em 99% dos casos.
Stefan Steiger,
2
Mas como acessar a configuração em modelos em vez de controlador?
Tanmay
2
Quanto mais leio e tento as coisas, mais percebo que obter uma string de conexão é uma tarefa importante. Eu só consigo nulos, não importa o que eu tente.
MC9000
7
Sim. Muitos cientistas da computação criando frutas enormes apenas para dizer "Olá, mundo". Inacreditável. A entropia é melhor.
JustJohn
2
@JustJohn: Eu entendo sua reclamação, mas o design adequado pode ser testado, e isso significa que você precisa passar dependências no construtor, caso contrário, seu aplicativo / estrutura não pode ser testado em unidade. Este também é um design adequado, já que você pode apenas substituir um componente por outro, sem ter que alterar uma grande quantidade de código. Se você não quiser passar 100 argumentos, você também pode passar System.IServiceProvider para a classe, então você pode buscar as dependências lá. Mas o outro lado da moeda é que isso vem com complexidade adicional.
Stefan Steiger,
18

Veja o link para mais informações: https://docs.microsoft.com/en-us/ef/core/misc Miscellaneous / connection - strings

JSON

    {
      "ConnectionStrings": {
        "BloggingDatabase": "Server=(localdb)\\mssqllocaldb;Database=EFGetStarted.ConsoleApp.NewDb;Trusted_Connection=True;"
      },
    }

C # Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<BloggingContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("BloggingDatabase")));
}

EDIT: aspnetcore, começando 3.1: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/configuration/?view=aspnetcore-3.1

markokstate
fonte
Por que o arquivo JSON deveria ter em ConnectionStringsvez de ConnectionString? Porque quando eu usei ConnectionString, então estamos ficando nulos.
Vijay
@Vijay Tente usar o método prescrito;) Por favor, consulte o link em anexo.
markokstate
1
Este método parece desatualizado em Microsoft.Extensions.Configuration(3.1.5)
Ju66ernaut
7

A maneira que encontrei para resolver isso foi usar AddJsonFile em um construtor no Startup (que permite encontrar a configuração armazenada no arquivo appsettings.json) e, em seguida, usar isso para definir uma variável _config privada

public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        _config = builder.Build();
    }

E então eu poderia definir a string de configuração da seguinte maneira:

var connectionString = _config.GetConnectionString("DbContextSettings:ConnectionString"); 

Isso está no dotnet core 1.1

Alex White
fonte
5
como posso acessar _config em meu controle?
ensolarado
Adicionando-o ao contêiner DI em ConfigureServices em Startup.cs.
Stefan Steiger
3

ASP.NET Core ( no meu caso 3.1 ) nos fornece injeções de Construtor em Controladores , então você pode simplesmente adicionar o seguinte construtor:

[Route("api/[controller]")]
[ApiController]
public class TestController : ControllerBase
{
    private readonly IConfiguration m_config;

    public TestController(IConfiguration config)
    {
        m_config = config;
    }

    [HttpGet]
    public string Get()
    {
        //you can get connection string as follows
        string connectionString = m_config.GetConnectionString("Default")
    }
}

Aqui, qual pode ser a aparência de appsettings.json:

{
    "ConnectionStrings": {
        "Default": "YOUR_CONNECTION_STRING"
        }
}
antonpv
fonte
0

Existe outra abordagem. No meu exemplo, você vê alguma lógica de negócios na classe de repositório que uso com injeção de dependência no ASP .NET MVC Core 3.1.

E aqui eu quero obter connectiongStringessa lógica de negócios porque provavelmente outro repositório terá acesso a outro banco de dados.

Este padrão permite que você, no mesmo repositório de lógica de negócios, tenha acesso a diferentes bancos de dados.

C #

public interface IStatsRepository
{
            IEnumerable<FederalDistrict> FederalDistricts();
}

class StatsRepository : IStatsRepository
{
   private readonly DbContextOptionsBuilder<EFCoreTestContext>
                optionsBuilder = new DbContextOptionsBuilder<EFCoreTestContext>();
   private readonly IConfigurationRoot configurationRoot;

   public StatsRepository()
   {
       IConfigurationBuilder configurationBuilder = new ConfigurationBuilder().SetBasePath(Environment.CurrentDirectory)
           .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
       configurationRoot = configurationBuilder.Build();
   }

   public IEnumerable<FederalDistrict> FederalDistricts()
   {
        var conn = configurationRoot.GetConnectionString("EFCoreTestContext");
        optionsBuilder.UseSqlServer(conn);

        using (var ctx = new EFCoreTestContext(optionsBuilder.Options))
        { 
            return ctx.FederalDistricts.Include(x => x.FederalSubjects).ToList();
        }
    }
}

appsettings.json

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*",
  "ConnectionStrings": {
    "EFCoreTestContext": "Data Source=DESKTOP-GNJKL2V\\MSSQLSERVER2014;Database=Test;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}
Desenvolvedor
fonte
-1

Eu tenho uma biblioteca de acesso a dados que funciona com o .net core e .net framework.

o truque estava em projetos centrais .net para manter as strings de conexão em um arquivo xml chamado "app.config" (também para projetos web) e marcá-lo como 'copiar para o diretório de saída',

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="conn1" connectionString="...." providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>

ConfigurationManager.ConnectionStrings - lerá a string de conexão.

    var conn1 = ConfigurationManager.ConnectionStrings["conn1"].ConnectionString;
Shaig
fonte
Se você estiver usando o .NET Core, é melhor adotar seu padrão de configuração em vez de usar o padrão .NET Framework.
Simmetric