Property type of two classes - c#

I'm writing session manager class in .NET MVC 4 and I got stuck at the point of creating SqlConfiguration.
Here is one of the properties from the class:
public static MsSqlConfiguration SqlConfig { get; set; }
All working perfectly excluding the fact that I can manage sessions only from MS SQLServer.
I want to do something like this:
public static MsSqlConfiguration,SQLiteConfiguration SqlConfig { get; set; }
And I know it isn't possible so I don't know what to do.
Thanks.

You can create a class with these 2 properties and Use them. I know its very basic
class MyConfig
{
public static MsSqlConfiguration SqlConfig { get; set; }
public static SQLiteConfiguration SQLiteConfig { get; set; }
}
Use them like
public static MyConfig SqlConfig { get; set; }

What about a dictionary?
public static IReadOnlyDictionary<string, IPersistenceConfigurer> DbConfigurations =
new ReadOnlyDictionary<string, IPersistenceConfigurer>(
new Dictionary<string, IPersistenceConfigurer>
{
{ "azure", MsSqlConfiguration.MsSql2008
.ConnectionString("ConnectionString")
.Dialect<MsSqlAzure2008Dialect>()
.Driver<SqlAzureClientDriver>() },
{ "mssql", MsSqlConfiguration.MsSql2008
.ConnectionString("ConnectionString")
.Dialect<MsSql2008Dialect>() },
{ "sqlite", SQLiteConfiguration.Standard
.InMemory() },
// etc..
});
IPersistenceConfigurer is an interface that any database configuration must implement.
As it's a dictionary, you can always check if a database configuration is present by calling DbConfigurations.ContainsKey("mssql").
Another option is using a generic list of IPersistenceConfigurer (aka List<IPersistenceConfigurer>) and get a configuration using LINQ OfType<T> extension method as follows:
dbConfigs.OfType<MsSqlConfiguration >().Single()
...or
dbConfigs.Single(config => config is MsSqlConfiguration)
Another option, if you're using Dependency Injection and an IoC container such as Castle Windsor is to register a factory with the container that can provide an instance of IPersistenceConfigurer to any components that require it. This way you can register different components for the IPersistenceConfigurer service depending on which environment you are running in (as I assume that you only need one particular IPersistenceConfigurer for the application at any one time).

Related

Multiple instances of class with different parameters based on configuration file

So I have a simple configuration class PubsubSettings:
public class PubSubSettings
{
public string ProjectId { get; set; }
public string TopicId { get; set; }
public int PartnerId { get; set; }
public string SubscriptionId { get; set; }
}
I have previously only had one of these configured in my appsettings.json but now I want to be able to handle an arbitrary number of them.
I have another class, PubSub, that I usually inject an IOptions<PubSubSettings> into. And this, in turn, gets injected into my Worker class.
services.Configure<PubSubSettings>(configuration.GetSection(nameof(PubSubSettings)));
...
services.AddHostedService<Worker>();
So, what I want to do now, is add a new Worker as a hosted service for each entry in my AppSettings PubSubSettings section and inject the relevant IOptions<PubSubSettings> into each of these (along with the standard ILogger).
So in essence, I'd like this config block:
"PubsubSettings": [
{
"ProjectId": "project1",
"TopicId": "topic",
"PartnerId": 1,
"SubscriptionId": "sub1"
},
{
"ProjectId": "project2",
"TopicId": "topic2",
"PartnerId": 2,
"SubscriptionId": "sub2"
}
]
To end up with two hosted services being created, one with the first set of options and the other with the second.
I've seen a few questions looking for similar things but nothing I could find quite lined up with this so I'm a bit stumped. Any ideas?
The solution is Dotnet 5.
So from what I've been able to find, there's no way to do this out-of-the box.
However, This can be done manually using a combination of ActivatorUtilities and Configuration.Bind().
private void CreateWorkers(IServiceCollection services, IConfigurationRoot configuration)
{
List<PubSubSettings> pubsubSettings = new();
configuration.Bind(nameof(PubSubSettings), pubsubSettings);
foreach (PubSubSettings setting in pubsubSettings)
{
services.AddSingleton<IHostedService>(s => ActivatorUtilities.CreateInstance<Worker>(s, ActivatorUtilities.CreateInstance<PubSub.PubSub>(s, setting)));
}
}
Essentially, you can use Bind to get the configuration objects from the JSON. Then you can manually construct the Worker for the call to AddHostedService using CreateInstance.
Two calls are needed in this case, one to generate the PubSub for the worker (in which we pass the setting parameter) and the other to generate the Worker itself.
ActivatorUtilities essentially injects everything you need for the object except the parameters you've provided.
We need to use .AddSingleton<IHostedService> because of the way that the framework checks for dupes with AddHostedService().
Maybe you could try creating a class only for the object and let the PubSubSettings class only for the array:
public class PubSubSettings
{
public PubSubObject[] PubSubs { get; set; }
}
public class PubSubObject
{
public string ProjectId { get; set; }
public string TopicId { get; set; }
public int PartnerId { get; set; }
public string SubscriptionId { get; set; }
}
Then in the startup class you should use Bind to get the current value of the array to create a Worker for each PubSub:
PubSubSettings settings = new PubSubSettings();
Configuration.GetSection(nameof(PubSubSettings)).Bind(settings);
...
foreach(PubSubObject item in settings.PubSubs)
{
services.AddHostedService<Worker>();
}
Then in the PubSub class you need to search the PartnerId inside the Array.
Or you could follow the approach described in the section Named options support using IConfigureNamedOptions in the Microsoft docs: Options pattern in ASP.NET Core

How to access CRUD operations of single db class instance without static methods

I'm new to NoSql and MongoDB. I'm using the MongoDB C# driver inside Visual Studio.
I've read in different places that it's preferable to have a single instance of your database class that maintains the connection(s) to keep everything thread safe and that it's generally a bad idea to use static classes for database CRUD operations.
At the start of my program I instantiate my database class which opens a connection. Within that class and also in derived classes I can perform CRUD operations. But now I'm in a different part of my solution (same namespace, different class) and I need to do read operations to check if a user exists. I also need to compose a new document that I then want to insert.
Now I'm in a situation where that's only possible by creating a new instance of the database class to access its CRUD methods. I want to avoid static CRUD methods (that could be accessed from other classes) because then the base class of my database connection also needs to be static. I cannot figure out how to approach this and what would be the recommended way.
From the MongoDB website:
The MongoClient instance actually represents a pool of connections to the database; you will only need one instance of class MongoClient even with multiple threads.
http://mongodb.github.io/mongo-csharp-driver/2.2/getting_started/quick_tour/
Does this mean I should create a new MongoClient everytime I need to acces the database in others parts of my program?
UPDATE
It seems I was a bit mistaken about the static properties and how they can be used. I now have it setup like this:
class Database
{
const string MongoConnection = "mongodb+srv://user:password#cluster.mongodb.net";
public static MongoClient Client { get; set; }
public static IMongoDatabase Directory { get; set; }
public static IMongoCollection<User> Collection { get; set; }
public Database()
{
Client = new MongoClient(MongoConnection);
Directory= Client.GetDatabase("studentDB");
Collection = Directory.GetCollection<User>("users");
}
public static void InsertNewUser(User user)
{
Collection.InsertOne(user);
}
public static bool EmailHasAccount(string email)
{
return Collection.Find(x => x.Email == email).FirstOrDefault() == null ? false : true;
}
public static User RetrieveUserAccount(string email)
{
return Collection.Find(x => x.Email == email).FirstOrDefault();
}
}
public class User
{
public Guid Id { get; private set; }
public string Name { get; set; }
public string Email { get; set; }
public User(string name, string email)
{
Id = Guid.NewGuid();
Name = name;
Email = email;
}
}
And in my main program I can use it like this:
var db = new Database();
var user = new User("myName", "email#address");
Database.InsertNewUser(user);
Console.WriteLine(Database.EmailHasAccount("email#address")); // returns true
Console.WriteLine(Database.RetrieveUserAccount("email#address").Name); // returns "myName"
That's exactly what I was looking for. What would be the best way to handle multiple collections? Would it be safe to change the Collection property or is it better to create separate properties? Is a Generic even possible?

Too Many Dependency Inject

I currently have a class with around 40 dependency injection. It is a hard to maintain and unit test. I am not sure a good way around.
The code is done for any type of application process that is needed to process (New License, License Renewal, Student Registration, ...), there are around 80 different types applications and what sections are associated with each application type is determined by a database table.
I have a class with all of the possible properties, there are a several more than listed but you should get the idea. Each the properties have their own set of properties that are basic data types or object pointing to other classes.
class Application
{
[JsonProperty(PropertyName = "accounting")]
public Accounting Accounting { get; set; }
[JsonProperty(PropertyName = "application")]
public Application Application { get; set; }
[JsonProperty(PropertyName = "applicationType")]
public ApplicationType ApplicationType { get; set; }
[JsonProperty(PropertyName = "document")]
public List<Attachment> Document { get; set; }
[JsonProperty(PropertyName = "employment")]
public List<Employment> Employment { get; set; }
[JsonProperty(PropertyName = "enrollment")]
public Enrollment Enrollment { get; set; }
[JsonProperty(PropertyName = "individualAddressContact")]
public IndividualAddressContact IndividualAddressContact { get; set; }
[JsonProperty(PropertyName = "instructors")]
public List<Instructor> Instructors { get; set; }
[JsonProperty(PropertyName = "license")]
public License License { get; set; }
[JsonProperty(PropertyName = "licenseRenewal")]
public LicenseRenewal LicenseRenewal { get; set; }
[JsonProperty(PropertyName = "MilitaryService")]
public List<MilitaryService> MilitaryService { get; set; }
[JsonProperty(PropertyName = "paymentDetail")]
public PaymentDetail PaymentDetail { get; set; }
[JsonProperty(PropertyName = "photo")]
public List<Attachment> Photo { get; set; }
[JsonProperty(PropertyName = "portal")]
public Portal Portal { get; set; }
[JsonProperty(PropertyName = "section")]
public List<Section> Section { get; set; }
[JsonProperty(PropertyName = "testingCalendar")]
public TestingCalendar TestingCalendar { get; set; }
[JsonProperty(PropertyName = "testingScore")]
public List<TestingScore> TestingScore { get; set; }
[JsonProperty(PropertyName = "USCitizen")]
public USCitizen USCitizen { get; set; }
}
So this class is sent/received to an Angular 10 front end using Web API's.
When an application is requested the sections and the different properties are initiated and if the application has be started the progress will be reloaded. So it is possible some of properties will be pulled from the database and sent to the Angular app.
So I have something such as
Load(applicationTypeId, applicationId)
{
Get the sections for the application type
For each section in the sections
switch sectionid
case Documents
Load all of the documents required for the application type and get any documents uploaded
case Accounting
Load the payment details, if no payment made calculate the payment
case IndividualAddressContact
Load the person name/address/contact and set a few defaults if the person hasn't started.
.....
next
}
Save()
{
Save the application
switch current section
case Documents
Save all of the documents for the application
case Accounting
Save the payment details for the application
case IndividualAddressContact
Save the person name/address/contact for the application
.....
get the next section
Update the application current section
}
I have put all of the items in the switch into their own classes but in the end I still have 1 point for serialization/deserialization and still end up with to many dependencies injected. Creating a unit test with over 40 dependencies seems hard to maintain and given I won't know which properties will/won't used until an application is requested and loaded from database. I am unsure how to get around the switch, without at some point and time having to have all of the dependencies injected into 1 class.
I would appreciate some ideas of how to get around this.
"I currently have a class with around 40 dependency injection..." - Oh my gosh!
"It is a hard to maintain and unit test..." - I don't doubt that in the least!
SUGGESTED REFACTORING:
Create a class that manages "Applications" (e.g. "ApplicationManager").
Create an abstract class "Application".
One advantage of "abstract class" over "interface" here that you can put "common code" in the abstract base class.
Create a concrete subclass for each "Application" : public class NewLicense : Application, public class LicenseRenewal : Application, etc. etc.
... AND ...
Use DI primarily for those "services" that each concrete class needs.
I'll bet the constructors for your individual concrete classes will only need to inject three or four services ... instead of 40. Who knows - maybe your base class won't need any DI at all.
This is actually a design we're actually using in one of our production systems. It's simple; it's robust; it's flexible. It's working well for us :)
I would recommend using convention over configuration principle, with the Service Locator.
Declare something like IApplicationHandler interface in your program, e.g.
public interface IApplicationQueryHandler
{
Application Populate(Application application);
}
public interface IApplicationSaveHandler
{
Bool Save(Application application);
}
Then, write pieces of your code, with dependencies and such, e.g.
public class AccountingApplicationQueryHandler : IApplicationQueryHandler
{
public Application Populate(Application application) {
//// Load the payment details, if no payment made calculate the payment
return application;
}
}
public class AccountingApplicationSaveHandler : IApplicationSaveHandler
{
public Bool Save(Application application) {
//// Save the payment details for the application
return true; // this just flags for validation
}
}
// repeat for all other properties
Then in your controller, do something like
public class ApplicationController: Controller
{
public readonly IServiceProvider _serviceProvider;
public ApplicationController(IServiceProvider sp) {
_serviceProvider = sp;
}
public Application Load(string applicationTypeId, string applicationId)
{
var application = new Application(); // or get from db or whatever
var queryHandlers = _serviceProvider.GetServices(typeof(IApplicationQueryHandler));
foreach(var handler in queryHandlers) {
application = handler.Populate(application);
}
return application;
}
[HttpPost]
public bool Save(Application application)
{
var result = true;
var saveHandlers = _serviceProvider.GetServices(typeof(IApplicationSaveHandler));
foreach(var handler in queryHandlers) {
result = handler. Save(application);
}
return result;
}
}
You would need to register your handlers, which you can do e.g. like so:
var queryHandlers = Assembly.GetAssembly(typeof(IApplicationQueryHandler)).GetExportedTypes()
.Where(x => x.GetInterfaces().Any(y => y == typeof(IApplicationQueryHandler)));
foreach(queryHandler in queryHandlers) {
services.AddTransient(typeof(IApplicationQueryHandler), queryHandler);
}
// repeat the same for IApplicationSaveHandler
Now finally, you can write unit tests for part of the code like so
[TestClass]
public class AccountingApplicationQueryHandlerTests
{
[TestMethod]
public void TestPopulate()
{
// arrange
var application = new Application();
var handler = new AccountingApplicationQueryHandler(); // inject mocks here
// act
var result = handler.Populate(application);
// Assert
Assert.AreEqual(result. PaymentDetail, "whatever");
}
}
And you can test that your controller calls the right things by mocking IServiceProvider and injecting that with a couple of dummy handlers to confirm they are called correctly.
Following zaitsman's answer you also could create AggregatedApplicationQueryHandler and AggregatedApplicationSaveHandler and pass collection of concrete implementation of IApplicationQueryHandler and IApplicationSaveHandler to its constructor.
Then you don't need foreach loop inside controller(you loop over handlers inside aggregated handler) and always have only one handler passed to controller. Passing its by constructor parameter shouldn't be so much painful.
You also could create facade over some small services and aggregate theirs functions into one bigger facade service.

How to bind IConfiguration to class having parameters in constructor

I am using standard configuration pattern for ASP.NET Core applications and I can not bind configuration to my class as it has construtor with parameters.
In appsettings.json I included desired config:
"MyServiceConfig": {
"Identity": {
"Version": "1.0",
"ComplicatedUri": {
"Scheme": "http",
"Authority": "localhost",
"Path": "SuperService"
}
}
},
My config class and it's dependencies look like that:
public class MyServiceConfig
{
public MyIdentity Identity { get; set; }
}
public class MyIdentity
{
public string IdentityName { get; set; }
public string Version { get; set; }
public MyComplicatedUri ComplicatedProperty { get; set; }
public MyIdentity(string version, MyComplicatedUri complicatedProperty)
{
Version = version;
ComplicatedProperty = complicatedProperty;
IdentityName = complicatedProperty.Path;
}
}
public class MyComplicatedUri
{
public string Scheme { get; set; }
public string Authority { get; set; }
public string Path { get; set; }
}
I have already tried code like that:
private MyServiceConfig GetMyConfig(IConfiguration configuration)
{
var config = new MyServiceConfig();
configuration.GetSection("MyServiceConfig").Bind(config);
return config;
}
It throws exception:
'Cannot create instance of type 'MyIdentity' because it is missing
a public parameterless constructor.'
That behaviour can make sense in some cases but in that particular one not so much. Mappings could be straightforward - by property names which have public setters or by constructor parameter names.
Another idea would be adding converter in AddJsonOptions in Startup class for my types - IConfiguration.Bind could infer how to construct it but I also tried that with no success.
Have you encoutered similar problems and found some reasonable solution to that?
Edit: Adding parameterless constructor will work of course, but sometimes I need to deal with some classes from external packages I'd like to use as parts of my config class so let's assume we can not modify them. I'd like to avoid adding new types for mapping only as well. Ideally I'd like to force ASP.NET Core engine to use existing constructor with parameters and by parameter name map with json properties - which currently is not working.
You should just add a default constructor in MyIdentity class.
.bind() binds the configuration into the object using the default constructor.
So, add the required default constructor in your MyIdentity class and it will be fine.
public MyIdentity(){}
Also, you can use Options.
In ConfigureServices, add the following:
services.AddOptions();
services.ConfigureOptions<MyServiceConfig>();
and then use dependency injection to initialize it.
In addition, use your own JsonConverter

Creating an HttpContext in MVC/StructureMap project running as a non-web app

How can I create an instance of HttContext and register it in StructureMap config?
I have an MVC3 web project using StructureMap with, I think, a typical setup where the controllers call repository class and the repo classes are responsible for business logic and database manipulation.
StructureMap is used to inject the controllers with the proper repositories.
But recently, I had a requirement for some repos to log certain actions along with the IP address of the user.
To get the IP address, I am using
requestContext.HttpContext.Request.UserHostAddress
Now, I thought it would be smart to pass the HttpContext into the repo classes and then register the HTTContext dependancy in StructureMap like this:
For<RequestContext>().Use(ctx => HttpContext.Current.Request.RequestContext);
That is working so far, but I also have a mini-project that will use the same repo functions but run as a console application (or maybe win service). The problem here is there is no HttpContext without the ASP.Net runtime. I get a runtime error saying that httpContext is null.
How can I get an HttpContext in there?
EDIT Suggested solution by Alexei and Plymouth
Thanks, if I understand Alexei's suggestion, I should make an interface like:
interface ILoggingConext
{
public string IPAddress { get; set; }
}
And then have 2 concrete classes, one of which (A) accepts an HTTPContext and the other (B) can have a default value for IPAddress
Then in StructureMap, configure it so that it will use concrete class a if HttpContext is not null. Otherwise , it will use B.
Am I close?
SOLUTION
Taking Alexei's advice, here is the solution I am currently using:
First declare the Interface and 2 concrete classes
public interface ILoggingContext
{
string IPAddress { get; set; }
string HostAddress { get; set; }
}
public class HttpLoggingContext : ILoggingContext
{
public string IPAddress { get; set; }
public string HostAddress { get; set; }
//This is the concrete class to use if context is available, so provide a constructor to accept a context and set properties appropriately
public HttpLoggingContext(RequestContext rContext)
{
if (rContext != null && rContext.HttpContext != null && rContext.HttpContext.Request != null)
{
this.IPAddress = rContext.HttpContext.Request.UserHostAddress;
this.HostAddress = rContext.HttpContext.Request.UserHostName;
}
}
}
//No http context, so just set the properties to something that signifies this, using "local" here
public class ConsoleLoggingContext : ILoggingContext
{
public string IPAddress { get; set; }
public string HostAddress { get; set; }
public ConsoleLoggingContext()
{
this.IPAddress = "local";
this.HostAddress = "local";
}
}
Then here is the configuration in the StructureMap registry class:
For<ILoggingContext>().ConditionallyUse(o =>
{
o.If(c => HttpContext.Current!=null && HttpContext.Current.Request!=null && HttpContext.Current.Request.RequestContext!=null).ThenIt.Is.ConstructedBy(a=> new HttpLoggingContext(HttpContext.Current.Request.RequestContext));
o.TheDefault.IsThis(new ConsoleLoggingContext());
}
).Named("ConditionalILoggingContext");
If the HttpContext.Current.Request.RequestContext is not null, we use the HttpLoggingContext. Otherwise we use the ConsoleLoggingContext.
I am marking this as the solution. Thanks for the help
To do as you suggest:
For<RequestContext>().Use(ctx =>
{
//TODO: Create unittest.html as required.
SimpleWorkerRequest request = new SimpleWorkerRequest("/unittest", #"c:\inetpub\wwwroot\unittest", "unittest.html", null, new StringWriter());
HttpContext context = new HttpContext(request);
return HttpContext.Current = context;
});
As was recommended though, abstracting the dependency upon the context would be a better long way to go.
The solution I ran with was what Alexei suggested. Use different wrappers to contain the required properties that I needed from the context object and use Structure map to decide which wrapper to use depending on the existence of the HttpContext. See original question for sample code under "Solution".

Categories