Login failed for user ''. using UserAssignedManagedIdentity while fetching data from AzureSQL - azure

I have created a Managed Identity (User Assigned) using Azure portal.
I attached that MSI with Azure App Service
Added appropriate permissions for the MSI at Azure SQL (Database)
In this implementation I am using Microsoft.EntityFrameworkCore version 2.2.6
I have the following code :
IDBAuthTokenService.cs
public interface IDBAuthTokenService
{
Task<string> GetTokenAsync();
}
AzureSqlAuthTokenService.cs
public class AzureSqlAuthTokenService : IDBAuthTokenService
{
public readonly IConfiguration _configuration;
public AzureSqlAuthTokenService(IConfiguration configuration)
{
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
}
public async Task<string> GetTokenAsync()
{
var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions{ManagedIdentityClientId = _configuration[C.AppKeys.UserAssignedClientId]});
var tokenRequestContext = new TokenRequestContext(new[]{_configuration[C.AppKeys.AzureSQLResourceId]});
var token = await credential.GetTokenAsync(tokenRequestContext, default);
return token.Token;
}
}
TestDbContext.cs:
public partial class TestDbContext : DbContext
{
public TestDbContext()
{
}
public TestDbContext(IDBAuthTokenService tokenService, DbContextOptions<TestDbContext> options) : base(options)
{
var connection = this.Database.GetDbConnection() as SqlConnection;
connection.AccessToken = tokenService.GetTokenAsync().Result;
}
public virtual DbSet<HealthCheckData> HealthCheckData { get; set; }
}
TestReportServiceProvider.cs
public class TestReportServiceProvider : IReportService
{
private readonly TestDbContext _objDBContext;
public TestReportServiceProvider(TestDbContext objDBContext)
{
_objDBContext = objDBContext;
}
public dynamic GetDataDetails(ReportDTO filters)
{
var response = new TestReponseExcelDto();
var ds = new DataSet();
using (var connection = new SqlConnection(_objDBContext.Database.GetDbConnection().ConnectionString))
{
connection.Open();
using (var command = new SqlCommand())
{
command.Connection = connection;
command.CommandType = CommandType.StoredProcedure;
command.CommandText = "[CR].[LoadProcedureDetailPopup]";
using (var sda = new SqlDataAdapter())
{
sda.SelectCommand = command;
sda.Fill(ds);
}
}
connection.Close();
}
if (ds.Tables.Count > 0)
{
response.Data = GetData(ds.Tables[0]);
response.TotalEngagements = response.Data.Select(d => d.TestReviewId).Distinct().Count();
}
return response;
}
}
In the above code while debugging I found error: Login failed for user ''. just after the control passes the code snippet connection.Open();. Even though the AccessToken was setup at the constructor within the TestDbContext , in this case I noticed that it is assigned with null value.
I added the below code before opening the connection and it started working fine as expected:
connection.AccessToken = ((SqlConnection)_objDBContext.Database.GetDbConnection()).AccessToken;
Even though my fix is solving the issue, I wanted to know whether it is correct way of doing it or are there better ways to manage it.
Can anyone help me to resolve this issue?

Related

Unable to find WebHook filters for the 'xx' receiver. Add the required configuration by calling a receiver method that calls ''AddWebHooks'

I am implementing webhook using asp.net core 3.1 webhook package. This is a custom webhook poc and I need to expose this webhook to external users. During runtime I am facing below error and unable to solve it.
What can I try next?
Error:
Unable to find WebHook filters for the 'jr4o27tr2r472' receiver. Add the required configuration by calling a receiver-specific method that calls 'Microsoft.Extensions.DependencyInjection.IMvcBuilder.AddWebHooks' or 'IMvcCoreBuilder.AddWebHooks' in the application startup code. For example, call 'IMvcCoreBuilder.AddGitHubWebHooks' to configure a minimal GitHub receiver.
When I hit this url (http://localhost:49846/api/webhooks/incoming/jr4o27tr2r472/teleported), I am getting this issue in eventviewer.
Note: I have added required webhook services as part of configurationservice method.
public static class UnicornServiceCollectionSetup
{
public static void AddUnicornServices(IServiceCollection services)
{
WebHookMetadata.Register<UnicornMetadata>(services);
services.AddSingleton<UnicornSignatureFilter>();
}
}
public static class UnicornMvcCoreBuilderExtensions
{
public static IMvcCoreBuilder AddUnicornWebHooks(this IMvcCoreBuilder builder)
{
UnicornServiceCollectionSetup.AddUnicornServices(builder.Services);
return builder.AddWebHooks();
}
}
public class UnicornMetadata : WebHookMetadata, IWebHookFilterMetadata
{
private readonly UnicornSignatureFilter _verifySignatureFilter;
public UnicornMetadata(UnicornSignatureFilter verifySignatureFilter)
: base(UnicornConstants.ReceiverName)
{
_verifySignatureFilter = verifySignatureFilter;
}
public override WebHookBodyType BodyType => WebHookBodyType.Json;
public void AddFilters(WebHookFilterMetadataContext context)
{
context.Results.Add(_verifySignatureFilter);
}
}
public class UnicornSignatureFilter : WebHookVerifySignatureFilter,
IAsyncResourceFilter
{
private readonly byte[] _secret;
public UnicornSignatureFilter(//IOptions<UnicornConfig> options,
IConfiguration configuration,
IHostingEnvironment hostingEnvironment,
ILoggerFactory loggerFactory)
: base(configuration, hostingEnvironment, loggerFactory)
{
//_secret = Encoding.UTF8.GetBytes(options.Value.SharedSecret);
_secret = Encoding.UTF8.GetBytes("secret");
}
public override string ReceiverName => UnicornConstants.ReceiverName;
public async Task OnResourceExecutionAsync(ResourceExecutingContext context,
ResourceExecutionDelegate next)
{
if (context == null) throw new ArgumentNullException(nameof(context));
if (next == null) throw new ArgumentNullException(nameof(next));
var request = context.HttpContext.Request;
if (!HttpMethods.IsPost(request.Method))
{
await next();
return;
}
var errorResult = EnsureSecureConnection(ReceiverName, request);
if (errorResult != null)
{
context.Result = errorResult;
return;
}
var header = GetRequestHeader(request,
UnicornConstants.SignatureHeaderName,
out errorResult);
if (errorResult != null)
{
context.Result = errorResult;
return;
}
byte[] payload;
using (var ms = new MemoryStream())
{
HttpRequestRewindExtensions.EnableBuffering(request);
await request.Body.CopyToAsync(ms);
payload = ms.ToArray();
request.Body.Position = 0;
}
if (payload == null || payload.Length == 0)
{
context.Result = new BadRequestObjectResult("No payload");
return;
}
var digest = FromBase64(header, UnicornConstants.SignatureHeaderName);
var secretPlusJson = _secret.Concat(payload).ToArray();
using (var sha512 = new SHA512Managed())
{
if (!SecretEqual(sha512.ComputeHash(secretPlusJson), digest))
{
context.Result =
new BadRequestObjectResult("Signature verification failed");
return;
}
}
await next();
}
}
Note: I am attaching source code in this webhookpoc.

Testing Batch SendAll ServiceStack

I am getting an error on SendAll in a unittest
This works fine...
using (var service = HostContext.ResolveService<DeviceService>(authenticatedRequest))
{
service.Put(new AddConfig { ConfigName = key.KeyName, ConfigValue = key.Value, DeviceId = 0 });
}}
ServiceStack.WebServiceException: 'The operation 'AddConfig[]' does not exist for this service'
//DeviceConfig
/// <summary>
/// To insert new Config
/// </summary>
/// <returns> New row Id or -1 on error</returns>
public long Any(AddConfig request)
{
try
{
//convert request to model
var perm = request.ConvertTo<DeviceConfig>();
//log user
perm.AuditUserId = UserAuth.Id;
//insert data
var insert = Db.Insert(perm, selectIdentity:true);
//log inserted data
LogInfo(typeof(DeviceConfig), perm, LogAction.Insert);
return insert;
}
//on error log error and data
catch (Exception e)
{
Log.Error(e);
}
return -1;
}
[Route("/Config", "PUT")]
public class AddConfig : IReturn<long>
{
public int DeviceId { get; set; }
public string ConfigName { get; set; }
public string ConfigValue { get; set; }
}
public const string TestingUrl = "http://localhost:5123/";
public void DeviceX400Test(string deviceTemaplateFile)
{
//Resolve auto-wired service
WireUpService<DeviceService>();
var requests = new[]
{
new AddConfig { ConfigName = "Foo" },
new AddConfig { ConfigName = "Bar" },
new AddConfig { ConfigName = "Baz" },
};
var client = new JsonServiceClient(TestingUrl);
var deviceConfigs = client.SendAll(requests);
}
MY ServiceBase for Unit Testting that builds from my .netcore appsettings.Json file
public abstract class ServiceTestBase: IDisposable
{
//private readonly ServiceStackHost appHost;
public BasicRequest authenticatedRequest;
public const string TestingUrl = "http://localhost:5123/";
public SeflHostedAppHost apphost;
public ServiceTestBase()
{
var licenseKeyText = "********************************";
Licensing.RegisterLicense(licenseKeyText);
apphost = (SeflHostedAppHost) new SeflHostedAppHost()
.Init()
.Start(TestingUrl);
//regsiter a test user
apphost.Container.Register<IAuthSession>(c => new AuthUserSession { FirstName = "test", IsAuthenticated = true });
}
public void WireUpService<T>() where T : class
{
//var service = apphost.Container.Resolve<T>(); //Resolve auto-wired service
apphost.Container.AddTransient<T>();
authenticatedRequest = new BasicRequest
{
Items = {
[Keywords.Session] = new AuthUserSession { FirstName = "test" , UserAuthId="1", IsAuthenticated = true}
}
};
}
public virtual void Dispose()
{
apphost.Dispose();
}
}
//Create your ServiceStack AppHost with only the dependencies your tests need
/// <summary>
/// This class may need updates to match what is in the mvc.service apphost.cs
/// </summary>
public class SeflHostedAppHost : AppSelfHostBase
{
public IConfigurationRoot Configuration { get; set; }
public SeflHostedAppHost() : base("Customer REST Example", typeof(StartupService).Assembly) { }
public override void Configure(Container container)
{
var file = Path.GetFullPath(#"../../../../cbw.services");
var builder = new ConfigurationBuilder().SetBasePath(file).AddJsonFile("appsettings.json").AddJsonFile("appsettings.LocalSQLServer.json", optional: true);
Configuration = builder.Build();
var sqlString = Configuration["ConnectionString"];
RegisterServiceStack();
//container.Register<ServiceStack.Data.IDbConnectionFactory>(new OrmLiteConnectionFactory(sqlString,SqlServerDialect.Provider));
container.Register<IDbConnectionFactory>(new OrmLiteConnectionFactory(":memory:", SqliteDialect.Provider));
container.RegisterAutoWired<DatabaseInitService>();
var service = container.Resolve<DatabaseInitService>();
container.Register<IAuthRepository>(c =>
new MyOrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())
{
UseDistinctRoleTables = true,
});
container.Resolve<IAuthRepository>().InitSchema();
var authRepo = (OrmLiteAuthRepository)container.Resolve<IAuthRepository>();
service.ResetDatabase();
SessionService.ResetUsers(authRepo);
service.InitializeTablesAndData();
//Logging
LogManager.LogFactory = new SerilogFactory(new LoggerConfiguration()
.ReadFrom.Configuration(Configuration)
.Destructure.UsingAttributes()
.CreateLogger());
Serilog.Debugging.SelfLog.Enable(msg => Debug.WriteLine(msg));
Serilog.Debugging.SelfLog.Enable(Console.Error);
ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
//ILog Log = LogManager.GetLogger(typeof(StartupService));
log.InfoFormat("Applicaiton Starting {Date}", DateTime.Now);
}
public void RegisterServiceStack()
{
var licenseKeyText = "****************************";
Licensing.RegisterLicense(licenseKeyText);
}
}
My Xunit Test
public class DeviceTemplateTest : ServiceTestBase
{
//Post Data
//Device Sends State.XML
[Theory]
[InlineData("C:\\DeviceTemplate.txt")]
public void DeviceX400Test(string deviceTemaplateFile)
{
//Resolve auto-wired service
WireUpService<DeviceService>();
var parser = new FileIniDataParser();
IniData data = parser.ReadFile(deviceTemaplateFile);
List<AddConfig> batch = new List<AddConfig>();
//Iterate through all the sections
foreach (SectionData section in data.Sections)
{
Console.WriteLine("[" + section.SectionName + "]");
//Iterate through all the keys in the current section
//printing the values
foreach (KeyData key in section.Keys)
{
batch.Add(new AddConfig { ConfigName = key.KeyName, ConfigValue = key.Value, DeviceId = 0 });
// using (var service = HostContext.ResolveService<DeviceService>(authenticatedRequest))
//{
// service.Any(new AddConfig { ConfigName = key.KeyName, ConfigValue = key.Value, DeviceId = 0 });
//}
}
}
var client = new JsonServiceClient(TestingUrl);
var deviceConfigs = client.SendAll(batch.ToArray());
}
}
Firstly, you should never return value types in Services, your Request DTO says it returns a DeviceConfig Response Type DTO:
public class AddConfig : IReturn<DeviceConfig> { ... }
Which your Service should be returning instead.
I'm unclear how this can work or compile:
using (var service = HostContext.ResolveService<DeviceService>(authenticatedRequest))
{
service.SendAll(new AddConfig {
ConfigName = key.KeyName, ConfigValue = key.Value, DeviceId = 0
});
}
Since it's calling methods on the DeviceService Service class directly and there is no SendAll() method on the Service class (or in your example), were you using the Service Gateway instead?
I can't tell what the issue is from here without seeing the full source code and being able to repro the issue but it sounds like AddConfig is not recognized as a Service, is it appearing in the /metadata page? If not do you have it a class that inherits Service?
Otherwise if you can post a minimal repro on GitHub, I'll be able to identify the issue.

Service Stack Razor View Not Found

I added the RazorPlugin along with a Test.cshtml in the root View folder (tried wwwroot as well along with TestGet.cshtml). This is an donet Core project. Whenever browsing to: /api/test the following error is generated:
Snapshot of TestGet generated by ServiceStack on 6/3/2017 4:20:40 PM
view json datasource from original url:
http://localhost:51550/api/test? in other formats: json xml csv jsv
Response Status Error CodeNullReferenceExceptionMessageObject
reference not set to an instance of an object.Stack Trace[TestGet:
6/3/2017 4:20:40 PM]: [REQUEST: {}] System.NullReferenceException:
Object reference not set to an instance of an object. at
ServiceStack.Mvc.RazorFormat.FindView(IEnumerable1 viewNames) in
/opt/lib/teamcity-agent/work/d09206570215629/src/ServiceStack.Mvc/RazorFormat.cs:line
174 at ServiceStack.Mvc.RazorFormat.ProcessRequest(IRequest req,
IResponse res, Object dto) in
/opt/lib/teamcity-agent/work/d09206570215629/src/ServiceStack.Mvc/RazorFormat.cs:line
138 at System.Linq.Enumerable.Any[TSource](IEnumerable1 source,
Func`2 predicate) at
ServiceStack.Formats.HtmlFormat.SerializeToStream(IRequest req, Object
response, IResponse res) in
/opt/lib/teamcity-agent/work/d09206570215629/src/ServiceStack/Formats/HtmlFormat.cs:line
63Errors
The other formats work (json/etc).
public class Test
{
public string ExternalId { get; set; }
}
[Authenticate, Route("/test")]
public class TestGet : IGet, IReturn<Test>
{
}
public class TestService : Service
{
public IAutoQueryDb _autoQueryDb { get; set; }
public IDbConnectionFactory _dbFactory { get; set; }
public TestService(IDbConnectionFactory dbFactory)
{
_dbFactory = dbFactory;
}
public Test Get(TestGet request)
{
var test = new Test();
test.ExternalId = "abc";
return test;
}
}
Test.cshtml
#using App.Shared.DomainModel
#model Test
<div>Test</div>
AppHost.cs
using App.DomainServices;
using App.FontEnd.Infrastructure.Configuration;
using App.FontEnd.Infrastructure.Core;
using App.Shared.DomainModel;
using Funq;
using LightInject;
using ServiceStack;
using ServiceStack.Admin;
using ServiceStack.Api.Swagger;
using ServiceStack.Auth;
using ServiceStack.Caching;
using ServiceStack.Configuration;
using ServiceStack.Data;
using ServiceStack.Mvc;
using ServiceStack.OrmLite;
using ServiceStack.Validation;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
namespace App.FrontEnd
{
public class AppHost : AppHostBase
{
/// <summary>
/// Base constructor requires a Name and Assembly where web service implementation is located
/// </summary>
public AppHost()
: base("TestApi", typeof(CompanyService).GetAssembly())
{
}
/// <summary>
/// Application specific configuration
/// This method should initialize any IoC resources utilized by your web service classes.
/// </summary>
public override void Configure(Container container)
{
this.GlobalRequestFilters.Add((httpReq, httpResp, requestDto) =>
{
var currentSession = httpReq.GetSession();
if (currentSession != null)
{
RequestContext.Instance.Items.Add("CurrentUserName", currentSession.UserName);
RequestContext.Instance.Items.Add("CurrentUserId", currentSession.UserAuthId);
}
});
ServiceContainer LightContainer = new ServiceContainer();
LightContainer.RegisterInstance<IDbConnectionFactory>
(
new OrmLiteConnectionFactory(
"removed",
SqlServer2014Dialect.Provider
)
);
LightContainer.Register<IDbConnection>(c =>
c.GetInstance<IDbConnectionFactory>().OpenDbConnection(),
new PerScopeLifetime()
);
LightContainer.Register<OrmLiteAppSettings>(c =>
new OrmLiteAppSettings(c.GetInstance<IDbConnectionFactory>()));
LightContainer.Register<ServiceStack.Web.IServiceGatewayFactory>(x => new ApiServiceGatewayFactory());
container.Adapter = new LightInjectAdapter(LightContainer);
var settings = LightContainer.GetInstance<OrmLiteAppSettings>();
settings.InitSchema();
AppSettings = new MultiAppSettings(
settings
);
container.Register<ICacheClient>(new OrmLiteCacheClient
{
DbFactory = LightContainer.GetInstance<IDbConnectionFactory>()
});
var cacheclient = container.Resolve<ICacheClient>();
cacheclient.InitSchema();
AuthConfig(container, AppSettings);
Plugins.Add(new RegistrationFeature());
Plugins.Add(new SwaggerFeature());
Plugins.Add(new RequestLogsFeature());
Plugins.Add(new PostmanFeature());
Plugins.Add(new CorsFeature(allowCredentials: true));
Plugins.Add(new ValidationFeature());
Plugins.Add(new RazorFormat());
OrmLiteConfig.InsertFilter = (dbCmd, row) =>
{
var auditRow = row as CoreModel;
if (auditRow != null)
{
var currentDate = DateTime.UtcNow;
var insertUserId = RequestContext.Instance.Items["CurrentUserId"] as string;
auditRow.Id = Guid.NewGuid();
auditRow.CreatedDate = currentDate;
auditRow.CreatedBy = insertUserId;
auditRow.UpdatedDate = currentDate;
auditRow.UpdatedBy = insertUserId;
}
};
OrmLiteConfig.UpdateFilter = (dbCmd, row) =>
{
var auditRow = row as CoreModel;
if (auditRow != null)
{
var updateUserId = RequestContext.Instance.Items["CurrentUserId"] as string;
auditRow.UpdatedDate = DateTime.UtcNow;
auditRow.UpdatedBy = updateUserId;
}
};
var aq = new AutoQueryFeature { MaxLimit = 100, EnableAutoQueryViewer = true };
aq.ImplicitConventions.Add("%neq", aq.ImplicitConventions["%NotEqualTo"]);
aq.ImplicitConventions.Add("%eq", "{Field} = {Value}");
Plugins.Add(aq);
Plugins.Add(new AdminFeature());
SetConfig(new HostConfig
{
HandlerFactoryPath = "api",
DebugMode = true
});
container.CheckAdapterFirst = true;
//Set up service stack validators
container.ValidatorsSetup();
}
public void AuthConfig(Container container, IAppSettings settings)
{
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[] {
new CredentialsAuthProvider(AppSettings),
new JwtAuthProvider(AppSettings)
{
AuthKeyBase64 = "abcdefgh"
},
new BasicAuthProvider()
}));
var authRepo = CreateOrmLiteAuthRepo(container, settings);
}
private static IUserAuthRepository CreateOrmLiteAuthRepo(Container container, IAppSettings appSettings)
{
//Store User Data into the referenced SqlServer database
container.Register<IAuthRepository>(c =>
new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>()));
//Use OrmLite DB Connection to persist the UserAuth and AuthProvider info
var authRepo = (OrmLiteAuthRepository)container.Resolve<IAuthRepository>();
//If using and RDBMS to persist UserAuth, we must create required tables
if (appSettings.Get("RecreateAuthTables", false))
authRepo.DropAndReCreateTables(); //Drop and re-create all Auth and registration tables
else
authRepo.InitSchema(); //Create only the missing tables
return authRepo;
}
}
}
I've created a minimal verifiable MVC test project to simulate your configuration which is working as expected at: https://github.com/NetCoreApps/scratch/tree/master/src/RazorApi
It includes the same Test Services, (sans [Authenticate] attribute):
public class Test
{
public string ExternalId { get; set; }
}
[Route("/test")]
public class TestGet : IGet, IReturn<Test>
{
}
public class TestService : Service
{
public Test Get(TestGet request)
{
var test = new Test { ExternalId = "abc" };
return test;
}
}
And the minimal AppHost configuration which just sets the HandlerFactoryPath to api and registers ServiceStack's RazorFormat plugin:
public class AppHost : AppHostBase
{
public AppHost()
: base("ServiceStack + .NET Core", typeof(MyServices).GetTypeInfo().Assembly) {}
public override void Configure(Funq.Container container)
{
SetConfig(new HostConfig
{
HandlerFactoryPath = "api",
DebugMode = true,
});
Plugins.Add(new RazorFormat());
}
}
With the Test.cshtml maintained in /Views/Test.cshtml:
#model Test
#{
Layout = "_Layout";
}
<h1>Test.cshtml</h1>
<p>#Model.ExternalId</p>
Which works as expected with the Razor View executed when calling:
http://localhost:5000/api/test
Which also works when renamed to match the Request DTO at TestGet.cshtml.
As the issue seems specific to your project I'd compare your layout with bare RazorApi Github Project to see if you can find any differences, failing that I'd recommend commenting out configuration to get it to a working state then uncomment sections at a time to find out which configuration is causing the issue.

How to register IUserAuthRepository when the OrmLiteConnectionFactory is using Named Connections

Here is the appHost configuration code:
OrmLiteConfig.DialectProvider = PostgreSQLDialectProvider.Instance;
var dbFactory = new OrmLiteConnectionFactory();
dbFactory.RegisterConnection("NamedKeyConnOne", new OrmLiteConnectionFactory("ConnOne"))
{
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
});
dbFactory.RegisterConnection("NamedKeyConnTwo", new OrmLiteConnectionFactory("ConnTwo")
{
ConnectionFilter = x => new ProfiledDbConnection(x, Profiler.Current)
});
container.Register<IDbConnectionFactory>(dbFactory);
and here is the authentication portion:
container.Register<IUserAuthRepository>(c => new OrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())); //Authentication and authorization
container.Resolve<IUserAuthRepository>().InitSchema();
So my question is "How do you go about passing the correct IDbConnectionFactory when there is no default connection string?"
Thank you,
Stephen
You can't inject a named IDbConnection connection but you can resolve it from the IDbConnectionFactory which you can access from your services like:
public class MyServices : Service
{
public IDbConnectionFactory DbFactory { get; set; }
public object Any(Request request)
{
using (var db = DbFactory.OpenDbConnection("NamedKeyConnOne"))
{
//...
}
}
}

Autofac resolving parameters in runtime

Let's get straight.
I have interface and class like this:
public interface IDataBase
{
DataTable GetSomeTableData();
}
My class:
public class DataBase : IDataBase
{
private readonly string _connectionString;
public DataBase(string connectionString)
{
this._connectionString = connectionString;
}
public DataTable GetSomeTableData()
{
using (SqlConnection cn = new SqlConnection(_connectionString))
{
cn.Open();
// some select
}
}
}
I'm using Autofac to inject that class:
var builder = new ContainerBuilder();
builder.RegisterType<DataBase>().As<IDataBase>).WithParameter("connectionString", "my connection string");
var container = builder.Build();
var database = container.Resolve<IDataBase>();
var tableData1 = database.GetSomeTableData();
// change connection string ?????????????????
var tableData2 = database.GetSomeTableData();
I need to get table data from one DB and another DB. How can I change connection string after have registered class? You may give another exapmle..
There are many ways to do it. One would be to create and inject a service instead of just plain connection string.
public interface IConnectionStringProvider
{
public string ConnectionString { get; set }
}
public class ConnectionStringProvider
{
public string ConnectionString { get; set }
}
var builder = new ContainerBuilder();
builder.RegisterType<DataBase>()
.As<IDataBase>);
builder.RegisterType<ConnectionStringProvider>)
.As<IConnectionStringProvider>
.SingleInstance();
var container = builder.Build();
var database = container.Resolve<IDataBase>();
var connStringProvider = container.Resolve<IConnectionStringProvider>();
var tableData1 = database.GetSomeTableData();
connStringProvider.ConnectionString = "...";
var tableData2 = database.GetSomeTableData();
The DataBase would then use that service:
public class DataBase : IDataBase
{
private readonly IConnectionStringProvider _connectionStringProvider;
public DataBase(IConnectionStringProvider connectionStringProvider)
{
this._connectionStringProvider = connectionStringProvider;
}
public DataTable GetSomeTableData()
{
using (SqlConnection cn = new SqlConnection(_connectionStringProvider.ConnectionString))
{
cn.Open();
// some select
}
}
}

Resources