-
Jan 18th, 2024, 08:42 PM
#1
[.NET 8] Dependency Injection on an N-Tier solution
I am creating a solution that has an API (Microsoft.NET.Sdk.Web), domain (Microsoft.NET.Sdk), and MVC projects (Microsoft.NET.Sdk.Web).
In my domain I have two classes that look like this:
Code:
public class ApplicationUserQuery
{
private readonly string _connectionString;
public ApplicationUserQuery(string connectionString)
{
_connectionString = connectionString;
}
// ...
}
public class ApplicationUserService
{
private readonly ApplicationUserQuery _applicationUserQuery;
public ApplicationUserService(ApplicationUserQuery applicationUserQuery)
{
_applicationUserQuery = applicationUserQuery;
}
// ...
}
To use the classes in my API project I am doing the following:
Code:
var applicationDatabaseConnectionString = builder.Configuration.GetConnectionString("ApplicationDatabase");
if (applicationDatabaseConnectionString == null)
{
throw new ArgumentNullException(nameof(applicationDatabaseConnectionString));
}
builder.Services.AddScoped(_ => new ApplicationUserQuery(applicationDatabaseConnectionString));
builder.Services.AddScoped<ApplicationUserService>();
This works, but it seems like a lot of boilerplate just for two classes. Is there anyway to simplify this using the built-in .NET core stuff? I'm wanting to avoid using a 3rd party library like Ninject because of issues we recently started running into at work. This solution I'm building is a personal project.
Last edited by dday9; Jan 22nd, 2024 at 05:28 PM.
-
Jan 19th, 2024, 09:44 AM
#2
Re: [RESOLVED] [.NET 8] Dependency Injection on an N-Tier solution
Question resolved here: https://stackoverflow.com/questions/...ve-boilerplate
First, I created two attributes called QueryAttribute and ServiceAttribute then added them to my respective query/service classes.
Next, I created a new class in my API project called RegisterDependencies that looks like this:
Code:
public class RegisterDependencies
{
private static Assembly AssertDomainAssembly()
{
var domainAssembly = Assembly.GetAssembly(typeof(BaseModel));
if (domainAssembly == null)
{
throw new Exception("Cannot find the domain assembly.");
}
return domainAssembly;
}
public static void RegisterQueries(IServiceCollection services, string connectionString)
{
var domainAssembly = AssertDomainAssembly();
var queryTypes = domainAssembly
.GetTypes()
.Where(t => t.GetCustomAttributes(typeof(QueryAttribute), false).Length > 0);
foreach (var queryType in queryTypes)
{
services.AddScoped(queryType, serviceProvider =>
{
var newInstance = Activator.CreateInstance(queryType, new object[] { connectionString })
?? throw new Exception($"Unable to create a new instance of query: {queryType.Name}");
return newInstance;
});
}
}
public static void RegisterServices(IServiceCollection services)
{
var domainAssembly = AssertDomainAssembly();
var serviceTypes = domainAssembly
.GetTypes()
.Where(t => t.GetCustomAttributes(typeof(ServiceAttribute), false).Length > 0);
foreach (var serviceType in serviceTypes)
{
services.AddScoped(serviceType);
}
}
}
Finally, I am calling the methods in my Program.cs:
Code:
var applicationDatabaseConnectionString = builder.Configuration.GetConnectionString("ApplicationDatabase");
if (applicationDatabaseConnectionString == null)
{
throw new ArgumentNullException(nameof(applicationDatabaseConnectionString));
}
RegisterDependencies.RegisterQueries(builder.Services, applicationDatabaseConnectionString);
RegisterDependencies.RegisterServices(builder.Services);
Now, so long as I have the Query/Service attribute on my class it will automatically get wired up for me without having to do all the boilerplate stuff.
-
Jan 22nd, 2024, 05:34 PM
#3
Re: [.NET 8] Dependency Injection on an N-Tier solution
I'm going to take off the resolved tag (for now).
There has to be a better way to set this up. If I create a BaseQuery class that looks like this:
Code:
public class BaseQuery
{
protected readonly string _connectionString;
public BaseQuery(string connectionString)
{
_connectionString = connectionString;
}
}
Then have my ApplicationUserQuery class inherit from it, why does this fail to wire everything up:
Code:
builder.Services.AddScoped(services.AddScoped(typeof(BaseQuery), () => new BaseQuery(connectionString)));
I don't understand why I would need to explicitly call AddScoped on ApplicationUserService and ApplicationUserQuery since the dependency tree would look like this:
Code:
└── ApplicationUserService
└── ApplicationUserQuery
└── BaseQuery
Since the application knows how to build a BaseQuery it should be able to create an ApplicationUserQuery and because it know how to create an ApplicationUserQuery it should know how to create an ApplicationUserService.
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|