I have the following:
interface IDefectRepository { /* ... */ }
class MyDefectRepository : IDefectRepository
{
public MyDefectRepository(string url, string userName, string password)
{
// ...
}
// ...
}
I'm using <parameters> to pass the constructor parameters from Web.config. Is there any way that I can store the password encrypted in the Web.config file? Other suggestions?
You could inject the password via a ISubDependencyResolver (sample1, sample2) which would get the password from an encrypted section in your web.config.
Try inheriting MyDefectRepositoryWithEncryptedPasswords from MyDefectRepository. In the MyDefectRepositoryWithEncryptedPasswords constructor decrypt the password and pass it to the MyDefectRepository constructor, like so:
class MyDefectRepositoryWithEncryptedPasswords : MyDefectRepository
{
public MyDefectRepositoryWithEncryptedPasswords(string url, string userName, string encryptedPassword)
: base(url, userName, Decrypt(encryptedPassword))
{
}
public static string Decrypt(string encrypted)
{
// Do whatever...
}
}
Anyway, I don't think you should store encrypted passwords with two-way encryption methods. You should use some sort of hashing (of the cryptographic kind) and compare the hashes. That would require changing your constructor to receive not the password, but its hash.
Related
I have an appsettings.json file with the following values
{
"MailOptions":
{
"Username": "ruskin",
"Password": "password"
}
}
When I read it via the ConfigurationBuilder I can only access the values via configuration["MailSettings:Username"]. I want to grab the entire MailOptions string, is there anyway to do that? I don't want to use Json to parse the file etc...I want to stick to configuration builder.
I would expect configuration.GetSection("MailOptions") to work? It simply returns null.
What I have tried
SomeSection aSection = new SomeSection();
ServiceCollection serviceCollection = new ServiceCollection();
serviceCollection.Configure<SomeSection>(options => configuration.GetSection("SomeSection").Bind(aSection));
var someSection = serviceCollection.BuildServiceProvider().GetService<IOptions<SomeSection>>();
// aSection is instantiated but no values in it
// someSection is null
My appsettings.json
{
"SomeSection": {
"UserName": "ruskin",
"Password": "dantra"
}
}
And my POCO class
public class SomeSection
{
public string UserName { get; set; }
public string Password { get; set; }
}
The configuration framework is an abstraction over the underlying source types. So MailOptions:Username could come from JSON, an environment variables or even INI files - and the configuration system can even be configured with multiple sources. If need a JSON string to configure your mail library and want to use the configuration abstraction, I suggest creating a class to hold the settings and serialize it to a JSON string again.
EDIT:
Using configuration.GetSection("SomeSection").Get<SomeSection>() I can successfully get the POCO from the app. see sample application.
I have the following dependency chain:
IUserAppService
IUserDomainService
IUserRepository
IUserDataContext - UserDataContextImpl(string conn)
All interfaces above and implementations are registered in a Windsor Castle container. When I use one connection string, everything works fine.
Now we want to support multiple databases, In UserAppServiceImpl.cs, we want to get different IUserRepository (different IUserDatabaseContext) according to userId as below:
// UserAppServiceImpl.cs
public UserInfo GetUserInfo(long userId)
{
var connStr = userId % 2 == 0 ? "conn1" : "conn2";
//var repo = container.Resolve<IUserRepository>(....)
}
How can I pass the argument connStr to UserDataContextImpl?
Since the connection string is runtime data in your case, it should not be injected directly into the constructor of your components, as explained here. Since however the connection string is contextual data, it would be awkward to pass it along all public methods in your object graph.
Instead, you should hide it behind an abstraction that allows you to retrieve the proper value for the current request. For instance:
public interface ISqlConnectionFactory
{
SqlConnection Open();
}
An implementation of the ISqlConnectionFactory itself could depend on a dependency that allows retrieving the current user id:
public interface IUserContext
{
int UserId { get; }
}
Such connection factory might therefore look like this:
public class SqlConnectionFactory : ISqlConnectionFactory
{
private readonly IUserContext userContext;
private readonly string con1;
private readonly string con2;
public SqlConnectionFactory(IUserContext userContext,
string con1, string con2) {
...
}
public SqlConnection Open() {
var connStr = userContext.UserId % 2 == 0 ? "conn1" : "conn2";
var con = new SqlConnection(connStr);
con.Open();
return con;
}
}
This leaves us with an IUserContext implementation. Such implementation will depend on the type of application we are building. For ASP.NET it might look like this:
public class AspNetUserContext : IUserContext
{
public string UserId => int.Parse(HttpContext.Current.Session["UserId"]);
}
You have to start from the beginning of your dependency resolver and resolve all of your derived dependencies to a "named" resolution.
Github code link:https://github.com/castleproject/Windsor/blob/master/docs/inline-dependencies.md
Example:
I have my IDataContext for MSSQL and another for MySQL.
This example is in Unity, but I am sure Windsor can do this.
container.RegisterType(Of IDataContextAsync, dbEntities)("db", New InjectionConstructor())
container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)("UnitOfWork", New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db")))
'Exceptions example
container.RegisterType(Of IRepositoryAsync(Of Exception), Repository(Of Exception))("iExceptionRepository",
New InjectionConstructor(New ResolvedParameter(Of IDataContextAsync)("db"),
New ResolvedParameter(Of IUnitOfWorkAsync)("UnitOfWork")))
sql container
container.RegisterType(Of IDataContextAsync, DataMart)(New HierarchicalLifetimeManager)
container.RegisterType(Of IUnitOfWorkAsync, UnitOfWork)(New HierarchicalLifetimeManager)
'brands
container.RegisterType(Of IRepositoryAsync(Of Brand), Repository(Of Brand))
controller code:
No changes required at the controller level.
results:
I can now have my MSSQL context do its work and MySQL do its work without any developer having to understand my container configuration. The developer simply consumes the correct service and everything is implemented.
I am used to JAX-RS and would like to have similar comfort when sending requests using Spring MVC and working with the responses, i.e. on the client side inside my tests.
On the server (controller) side I'm quite happy with the automatic conversion, i.e. it suffices to just return an object instance and have JSON in the resulting HTTP response sent to the client.
Could you tell me how to work around the manual process of converting objectInstance to jsonString or vice versa in these snippets? If possible, I'd also like to skip configuring the content type manually.
String jsonStringRequest = objectMapper.writeValueAsString(objectInstance);
ResultActions resultActions = mockMvc.perform(post(PATH)
.contentType(MediaType.APPLICATION_JSON)
.content(jsonStringRequest)
)
String jsonStringResponse = resultActions.andReturn().getResponse().getContentAsString();
Some objectInstanceResponse = objectMapper.readValue(jsonStringResponse, Some.class);
For comparison, with JAX-RS client API I can easily send an object using request.post(Entity.entity(objectInstance, MediaType.APPLICATION_JSON_TYPE) and read the response using response.readEntity(Some.class);
if you have lot's of response objects, you could create some generic JsonToObject mapper-factory. It could be then used to detect the object type from a generic response (all response objects inherit from the same generic class) and respond/log properly from a bad mapping attempt.
I do not have a code example at hand, but as a pseudocode:
public abstract GenericResponse {
public String responseClassName = null;
// get/set
}
In the server code, add the name of the actual response object to this class.
The JsonToObject factory
public ConverterFactory<T> {
private T objectType;
public ConverterFactory(T type) {
objectType = type;
}
public T convert(String jsonString) {
// Type check
GenericResponse genResp = mapper.readValue(result.getResponse().getContentAsString(),
GenericResponse.class);
if (objectType.getClass().getSimpleName().equals(genResp.getResponseClassName())) {
// ObjectMapper code
return mapper.readValue(result.getResponse().getContentAsString(),
objectType.class);
} else {
// Error handling
}
}
}
I think this could be extended to be used with annotation to do more automation magic with the response. (start checking with BeanPostProcessor)
#Component
public class AnnotationWorker implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(final Object bean, String name) throws BeansException {
ReflectionUtils.doWithFields(bean.getClass(), field -> {
// make the field accessible if defined private
ReflectionUtils.makeAccessible(field);
if (field.getAnnotation(MyAnnotation.class) != null) {
field.set(bean, log);
}
});
return bean;
}
}
The above code snippet is copied from my current project and it injects to fields, you need to change it so, that it works for methods, eg ... where you may need it.
Having this all implemented may be tricky and can't say it necessarily works even, but it's something to try if you don't mind a bit of educative work.
We are in the process of re-writing one of our applications using ASP.NET Core. The architecture we're trying for has a Web API running on a different URL from the presentation. The root URL for this API will change in different environments, of course, so I'm trying to figure out how I can set up configuration and access to the Web API root URL in the JavaScript that requires it for retrieving data. For example, say I have an AJAX call to fetch some data from the API:
$.ajax({
dataType: "json",
url: "http://this.url.will.change/api/whatever", //this will change!
success: function(response) {
//load the items
}
});
I've set up appsettings.json files for various build/deploy scenarios and have them reading and injecting nicely, so I can store the URL there.
{
"Data": {
"DefaultConnection": {
"ConnectionString": "whatever"
}
},
"AppSettings": {
"ApiRootUrl": "http://apiroot/api/"
}
}
I considered writing a UrlHelper extension to provide the Web API root, but I don't think there's a way to inject the IOptions object into a static extension method. So, my question is really this: How can I make a configuration setting globally available in my CSHTML and JavaScript?
Update your Startup.cs like below
public class Startup {
public IConfigurationRoot Configuration { get; set; }
public Startup(IHostingEnvironment env, IApplicationEnvironment appEnv) {
IConfigurationBuilder builder = new ConfigurationBuilder()
.SetBasePath(appEnv.ApplicationBasePath)
.AddJsonFile("appsettings.json");
Configuration = builder.Build();
}
public void ConfigureServices(IServiceCollection services) {
services.AddSingleton(_ => Configuration);
}
}
Then on your controller you can inject configuration like this
public class ConfigurationController : Controller {
private readonly IConfigurationRoot config;
public ConfigurationController (IConfigurationRoot config) {
this.config = config;
}
public string Test() {
return config.Get<string>("AppSettings:ApiRootUrl");
}
}
We've used to create a special configuration controller which was responsible for creating a dynamic javascript file from selected configurations settings. You can inject IOptions to the controller. Then from the options you can construct a new custom configuration object which will hold only the properties you want to expose (you probably don't want to expose anything like connection string to your db).
Use a json library (like json.net) to serialize this custom configuration object to a JSON string and create file content out of it like
string fileContent = "var globalConf =" + JsonConvert.SerializeObject(configObject);
Convert the string to array of bytes and return it as FileContentResult.
We were also setting some cache headers so the browser didn't hit the controller each time and used cache.
Of course you need to setup routing o the call to specific URL will hit your controller and return the javascript file you have dynamically created. You can reference it on a website using usual script tag.
As for the server side rendering you can always include IOptions in the model (or create a new model which will wrap both options and the original model)
I have seen several posts about this but have not been able to create a usable solution from the responses. Perhaps due to a lack of understanding.
The hosting provided requires that an identical code base be used on staging and production, including connection string.
How do I switch the connection string for DbContext?
I understand I can do something like this:
public FooEntities() : base("ApplicationServices") { }
But this is not dynamic - it merely sets it at runtime.
So how would I actually CHOOSE the connection string at runtime?
Yes public FooEntities() : base("ApplicationServices") { }
FooEntities inheriting from ObjectContext
You could also write
public FooEntities() : base(YourStaticMethodToGetConnectionString()) { }
Then you could pull the connection string from the web.config based on some environment setting
I'm reviewing this right now because I will dev local and then deploy to cloud. Therefore, want to dynamically switch connection strings being used by data context. My plan is to configure the needed connection strings in standard "connectionStrings" section of Web.config, and then place logic in the DbContext constructor, like:
public partial class MyApplicationDbContext : DbContext
{
public MyApplicationDbContext()
: base("name=cloud")
{
Database.Connection.ConnectionString =
ConnectionStringHelpers.GetHostBasedConnectionString();
}
// abbreviated..
}
Alternate:
public partial class MyApplicationDbContext : DbContext
{
public MyApplicationDbContext()
: base(ConnectionStringHelpers.GetHostBasedConnectionString())
{
}
// abbreviated..
}
Helper:
public class ConnectionStringHelpers
{
public static string GetHostBasedConnectionString()
{
return GetConnectionStringByName(GetHostBasedConnectiongStringName());
}
public static string GetHostBasedConnectiongStringName()
{
switch (System.Net.Dns.GetHostName())
{
case "myHostname": return "local"; // My local connection
case "ip-ABCD123": return "cloud"; // Cloud PaaS connection
default: return "cloud";
}
}
public static string GetConnectionStringByName(string name)
{
return ConfigurationManager.ConnectionStrings[name].ConnectionString;
}
}
And in my Web.config file:
<connectionStrings>
<add name="local" connectionString="..." providerName="System.Data.SqlClient" />
<add name="cloud" connectionString="..." providerName="System.Data.SqlClient" />
</connectionStrings>