Injecting dependency from a Class Library project to Xamarin Forms - xamarin.forms

I have got a brand new Xamarin Form project that requires access to an existing class in a class library project (net standards 2.1).
I would like Xamarin forms to use ClientQueries class from the other project.
ClientQueries has got a HttpClientFactory property using dependency injection and several methods to call an API and it looks something like this:
public class ClientQueries
{
private readonly ClientFactory _ClientFactory;
public TSClientQueries(ClientFactory ClientFactory)
{
_ClientFactory = ClientFactory ?? throw new ArgumentNullException(nameof(ClientFactory));
}
public async Task<Result<Token>> GetToken(CancellationToken cancellationToken, string username, string password)
{
var client = _ClientFactory.Create();
var response = await client.GetToken(cancellationToken, username, password).ConfigureAwait(true);
return response;
}
}
I follow this sample which explains we can make use of Microsoft.Extensions for HttpClientFactory and adding singleton services. This is the link: ASP.NET Core's Dependency Injection into Xamarin Apps with HostBuilder
I tried this StartUp class in Xamarin Forms project which is similar to the asp.net core project which uses the same Class Library with ClientQueries:
public class Startup
{
public static IServiceProvider ServiceProvider { get; set; }
public static void Init()
{
var a = Assembly.GetExecutingAssembly();
using var stream = a.GetManifestResourceStream("App1.appsettings.json");
var host = new HostBuilder()
.ConfigureHostConfiguration(c =>
{
c.AddCommandLine(new string[] { $"ContentRoot={FileSystem.AppDataDirectory}" });
c.AddJsonStream(stream);
})
.ConfigureServices((c, x) => ConfigureServices(c, x))
.ConfigureLogging(l => l.AddConsole(o =>
{
//o.DisableColors = true;
}))
.Build();
ServiceProvider = host.Services;
}
static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
{
#region "api service"
services.AddSingleton<ClientQueries>();
services.AddHttpClient<Client>("HttpClient",
x => { x.BaseAddress = new Uri(ctx.Configuration["APIConfiguration:BaseAddress"]); }
).AddPolicyHandler(GetRetryPolicy());
services.AddSingleton<ClientFactory>();
#endregion
}
Is it possible to inject ClientQueries in ViewModels like the way I used to do it in asp.net core controllers?
public class AccountController : Controller
{
private readonly ClientQueries _ClientQueries;
public AccountController(ClientQueries ClientQueries)
{
_tsClientQueries = tsClientQueries;
}
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
var t = await _ClientQueries.GetToken(CancellationToken.None, model.UserName, model.Password);
[coded abbreviated for simplicity]
Or Has Prism got anything functionality which will allow me to use depedency injection for HttpClientFactory in ClientQueries and Use ClienQueries as a singleton in ViewModels in Xamarin?
I tried DependencyServices and I did not get it right.
Thanks.

Related

Swagger UI and Swagger Doc does not generate query string. .NET 6 Web API with Minimal API, Mediatr, and Swashbuckle

I have build a Web API application using .NET 6, Mediatr, and Swashbuckle ASPNetCore. I am using nTier structure, so there is more than one project for my solutions with my Web API project having reference to a class library project that consist business logic.
The problem is, swagger-ui wont generate query string parameter to be shown on browser while everything else is normal. And another interesting part is, when using Postman, you can pass the query string key and value and it works like a charm.
Here is my request body model from class library project:
using MediatR;
using Microsoft.AspNetCore.Http;
using System.Reflection;
namespace Rest.API.Application
{
public class FindRequest : IRequest<FindResponse>
{
public string firstName { get; init; }
public string lastName { get; set; }
public static ValueTask<FindRequest> BindAsync(HttpContext context, ParameterInfo parameter)
{
FindRequest result = new()
{
firstName = context.Request.Query["firstName"],
lastName = context.Request.Query["lastName"]
};
return ValueTask.FromResult(result);
}
}
}
Here is the Endpoint class from Web API project:
using MediatR;
using Rest.API.Application;
namespace Rest.API.Core
{
public interface IEndpoint
{
void ConfigureApplication(WebApplication app);
}
public class Endpoint : IEndpoint
{
public void ConfigureApplication(WebApplication app)
{
app.MapGet("employee/{id}", async (IMediator mediator, string id) => await mediator.Send(new GetRequest(id)));
app.MapGet("employee", async (IMediator mediator, FindRequest request) => await mediator.Send(request));
}
}
}
My endpoint extension class to wrap all endpoint so I can easily register all endpoint to Program.cs:
using Microsoft.OpenApi.Models;
using System.Reflection;
namespace Rest.API.Core
{
public static class EndpointExtension
{
public static void AddEndpoint(this IServiceCollection service, params Type[] types)
{
var endpoints = new List<IEndpoint>();
foreach (var type in types)
{
endpoints.AddRange(type.Assembly.ExportedTypes
.Where(x => typeof(IEndpoint).IsAssignableFrom(x)
&& !x.IsInterface
&& !x.IsAbstract)
.Select(Activator.CreateInstance)
.Cast<IEndpoint>());
}
service.AddSingleton(endpoints as IReadOnlyCollection<IEndpoint>);
}
public static void UseEndpoint(this WebApplication app)
{
var endpoints = app.Services.GetRequiredService<IReadOnlyCollection<IEndpoint>>();
foreach (var endpoint in endpoints)
{
endpoint.ConfigureApplication(app);
}
}
}
public static class SwaggerExtension
{
public static void ConfigureSwagger(this IServiceCollection services)
{
services.AddEndpointsApiExplorer();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("dev", new OpenApiInfo
{
Title = "Sample Web API Core",
Version = $"DEV-{Environment.Version.Major}.{Environment.Version.Minor}.{DateTime.Now:yyyyMMddHHmmss}",
Description = "Sample Web API"
});
string xmlDocFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
string xmlDocPath = Path.Combine(AppContext.BaseDirectory, xmlDocFile);
c.IncludeXmlComments(xmlDocPath);
});
}
public static void UseSwaggerApp(this WebApplication app)
{
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(x =>
{
x.SwaggerEndpoint("/swagger/dev/swagger.json", "Rest.API.Core");
x.RoutePrefix = "swagger";
x.DocumentTitle = "Sample Web API";
});
}
}
}
public static class CORSExtension
{
public static void ConfigureCORS(this IServiceCollection services)
{
services.AddCors(options =>
{
//NOT FOR PRODUCTION
options.AddPolicy("AllowAnyOrigin", builder =>
{
builder.AllowAnyOrigin();
builder.AllowAnyMethod();
builder.AllowAnyHeader();
});
});
}
}
}
Finally, my Program.cs:
using MediatR;
using Rest.API.Application;
using Rest.API.Core;
using System.Reflection;
var builder = WebApplication.CreateBuilder(args);
#region SERVICES
builder.Services.ConfigureCORS();
builder.Services.AddMediatR(typeof(GetHandler).GetTypeInfo().Assembly);
builder.Services.ConfigureSwagger();
builder.Services.AddEndpoint(typeof(IEndpoint)); //Register all endpoint(controller) that implementing IEndpoint.
#endregion
var app = builder.Build();
#region PIPELINE
app.UseSwaggerApp();
app.UseEndpoint();
app.UseCors("AllowAnyOrigin");
app.UseHttpsRedirection();
#endregion
app.Run();
For the complete sample project you can get from here.
So, any idea how show the query string model on swagger-ui?
Thank You.
There's no way for your model to express how it's being bound from the request. This is a gap being resolved in .NET 7, see https://github.com/dotnet/aspnetcore/issues/40646.
To accomplish this with .NET 6, you can https://www.nuget.org/packages/MinimalApis.Extensions

I'm new to .NET Core 2.1 MVC and I'm having trouble understanding how a few things work

I'm currently following a .Net Core Angular 8 tutorial in Udemy. I'm able do get/post requests in Postman and I can also see what I've posted in a .db file using sqlite as my database and viewing the data through Db Browser. Everything seems to be working great but is all for nothing if I can't comprehend what's going on in some areas of the application. I would really appreciate it if someone could help me answer a few questions.
My entire project is in GitHub: https://github.com/cjtejada/ASP.NetCoreAngular8/tree/master/DatingApp.API
Problem 1: I have the following the following controller:
[Route("api/[controller]")]
[ApiController]
public class AuthController : ControllerBase
{
private readonly IAuthRepository _repo;
private readonly IConfiguration _config;
public AuthController(IAuthRepository repo, IConfiguration config)
{
_repo = repo;
_config = config;
}
[HttpPost("register")]
public async Task<IActionResult> Register(UserForRegisterDto userForRegisterDto)
{
// validate request
userForRegisterDto.Username = userForRegisterDto.Username.ToLower();
if (await _repo.UserExists(userForRegisterDto.Username))
return BadRequest("User already exists");
var userToCreate = new User
{
Username = userForRegisterDto.Username
};
var createdUser = await _repo.Register(userToCreate, userForRegisterDto.Password);
return StatusCode(201);
}
}
I know that when the client makes a request to register, the register() method will be called and the Username that gets passed in will set the Username from DTO userForRegisterDto. After this then we call method UserExists() to check if the user exists in our database.
Question 1:
How is _repo aware of the logic in method UserExists() when it is only using the interface IAuthRepository? I know that IAuthRepository and class AuthRepository are somehow linked but I don't see anywhere in the app where Constructor DI is happening. My suspicion is that it has something to do with this line in startup.cs under the ConfigureServices method :
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(x => x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddCors();
services.AddScoped<IAuthRepository, AuthRepository>(); //<---- This Line
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("AppSettings:Token").Value)),
ValidateIssuer = false,
ValidateAudience = false
};
});
}
After these two are "linked up", then the UserExists() method can be accessed through the AuthRepository class:
public class AuthRepository : IAuthRepository
{
private readonly DataContext _context;
public AuthRepository(DataContext context)
{
_context = context;
}
public async Task<User> Login(string username, string password)
{
}
private bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] passwordSalt)
{
}
public async Task<User> Register(User user, string password)
{
byte[] passwordHash, passwordSalt;
CreatePasswordHash(password, out passwordHash, out passwordSalt);
user.PasswordHash = passwordHash;
user.PasswordSalt = passwordSalt;
await _context.Users.AddAsync(user);
await _context.SaveChangesAsync();
return user;
}
private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] passwordSalt)
{
}
public async Task<bool> UserExists(string username)
{
if (await _context.Users.AnyAsync(x => x.Username == username))
return true;
return false;
}
}
I've been reading about the AddScoped method and what it does but this is not clear to me that this is the case. Any clarification as to how this works would be great.
Problem 2:
This one is more or less the same. If we keep following the path of the request we will hit the register() method in the AuthRepository class.
Question 2:
How does this class have access to the properties of DataContext _context when I also can't spot any instances of constructor DI anywhere?
Here are the rest of my project files if needed:
Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DataContext>(x => x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddCors();
services.AddScoped<IAuthRepository, AuthRepository>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetSection("AppSettings:Token").Value)),
ValidateIssuer = false,
ValidateAudience = false
};
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
//app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
app.UseAuthentication();
app.UseMvc();
}
}
DataContext.cs
public class DataContext : DbContext
{
public DataContext(DbContextOptions<DataContext> options) : base (options){}
public DbSet<Value> Values { get; set; }
public DbSet<User> Users { get; set; }
}
Any clarifications and suggestions are greatly appreciated. Thanks, all.
You are correct. The line services.AddScoped<IAuthRepository, AuthRepository>(); simply instructs the ASP.NET Core service container to substitute an instance of concrete class AuthRepository wherever it sees a reference to IAuthRepository at runtime.
The various Add* methods all do the same thing under the hood regarding registering the mapping of interfaces => classes, the key difference is the scope of the created class, i.e. how long it persists for:
AddScoped classes will be created at the beginning of every request to the server, and destroyed at the end of every request. In other words, every request results in a new instance of that class being created.
AddSingleton classes are created when your ASP.NET Core application starts up, and are destroyed when it shuts down. In other words, only a single instance of that class exists within your application.
AddTransient classes are recreated whenever they are requested. In other words, if a page on your site used the same service transient twice, there would be two instances created. (Contrast this with a scoped service, where only a single instance would be created, as each page is a single request.)
A fuller explanation, including examples: https://stackoverflow.com/a/38139500/70345
In order to fulfill (1) by creating an instance of your class AuthRepository, the service container needs to call that class's constructor. The container inspects your class to find the first public constructor and retrieves any arguments to that constructor, in this case an instance of the DataContext class. The container then searches its internal class mappings for that class and, because you have registered that mapping via services.AddDbContext<DataContext>(...), is able to construct and return the class instance. Thus it's able to pass that instance to AuthRepository, so AuthRepository is constructed successfully.
The AddDbContext method is simply a wrapper around AddScoped, that performs some additional scaffolding to allow Entity Framework DbContexts to work correctly.
For the official explanation, refer to Microsoft's official page on DI and IoC.
Question 1 - You've right this line in Startup.cs provide creating a new object AuthRepository. For this example you must to know that DI container creates an AuthRepository object for you based on the interface and his own implementation and you only need to pass an interface in properly constructor. AddScope() is related with lifetime of created objects. When you register object by method AddScope() then the object will be created for a single request and after the request, the object will be disposed.
Question 2 - Your dbContext is registered in DI container. AddDbContext() is a specific extension method provided to registration of entity framework dbContextes. This line of code registers your dbContext with connection strings got from the appSetting.json file.
services.AddDbContext<DataContext>(x =>
x.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
This DbContext is injected into the constructor of the AuthRepository class and when you use this class DI container created DbContext instance for you.
private readonly DataContext _context;
public AuthRepository(DataContext context)
{
_context = context;
}

An error occurred when trying to create a controller of type 'XXXXController'. Make sure that the controller has a parameterless public constructor

I have created a asp.net web api project and implemented the below HTTP GET method in AccountController and the related service method & repository method in AccountService & AccountRepository respectively.
// WEB API
public class AccountController : ApiController
{
private readonly IAccountService _accountService;
public AccountController(IAccountService accountService)
{
_accountService = accountService;
}
[HttpGet, ActionName("UserProfile")]
public JsonResult<decimal> GetUserSalary(int userID)
{
var account = _accountService.GetUserSalary(userID);
if (account != null)
{
return Json(account.Salary);
}
return Json(0);
}
}
Service / Business Layer
public interface IAccountService
{
decimal GetUserSalary(int userId);
}
public class AccountService : IAccountService
{
readonly IAccountRepository _accountRepository = new AccountRepository();
public decimal GetUserSalary(int userId)
{
return _accountRepository.GetUserSalary(userId);
}
}
Repository / Data Access Layer
public interface IAccountRepository
{
decimal GetUserSalary(int userId);
}
public class AccountRepository : IAccountRepository
{
public decimal GetUserSalary(int userId)
{
using (var db = new AccountEntities())
{
var account = (from b in db.UserAccounts where b.UserID == userId select b).FirstOrDefault();
if (account != null)
{
return account.Salary;
}
}
return 0;
}
}
UnityConfig
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
container.RegisterType<IAccountService, AccountService>();
container.RegisterType<IAccountRepository, AccountRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
But when I invoke the API method GetUserSalary() I get an error saying
An error occurred when trying to create a controller of type 'AccountController'. Make sure that the controller has a parameterless public constructor.
Check that you did not forget to register Unity IoC container itself:
if you use ASP.NET Framework it could be - Global.asax or Startap.cs (Owin) via UnityConfig.RegisterComponents() method.
if you use ASP.NET Core then in the Startup.cs file (I was unable to find official guides for its configuting)
Your current constructor has parameters (or args if you prefer).
see:
public AccountController(IAccountService accountService)
{
_accountService = accountService;
}
All you need to do is add a "Parameter-less Constructor" into the controller as well.
public AccountController()
{
}
Parameter-less constructors are usually above the ones that have params, though as far as I am aware this is only due to standards not any actual effect(s) it may cause.
There is also an already existing issue/question similar to this I will link below that may provide further details.
Make sure that the controller has a parameterless public constructor error

Get transistent/scoped Database access in singletonservice

i updating my app from asp core 1.0 to 2.0. In 1.0 i have a soulution for my longlive import-task, initialated as singleton. The singleton used the DBContext. But in core 2.0 this soulution dosn't work. Can you help me?
My soulution in aps core 1.0 was
services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("LocalConnection")));
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddTransient<IDataStore, DataStore>();
services.AddSingleton<IImportRepository, ImportRepository>();
with
public class ImportRepository : IImportRepository
{
Importer Importer;
private readonly ApplicationDbContext DBContext;
private readonly IDataStore store;
private ImportSet runningSet = null;
public ImportRepository(ApplicationDbContext context, IDataStore store)
{
this.DBContext = context;
this.store = store;
Importer = new Importer(DBContext, store);
}
With this soulutions i get errormessages (in german, but i try to translate). "you cannot use scoped services in singleton"
Last attempt i used this solution
services.AddSingleton<ImportService>(
provider => new ImportService((ApplicationDbContext)provider.GetService(typeof(ApplicationDbContext)))
);
But here i get the errormessage "Cannot resolve scoped service 'Portal.Data.ApplicationDbContext' from root provider."
How can i get access to my database in my Import-Service?
You may resolve dependencies manually using IServiceProvider instance.
public class ImportRepository : IImportRepository
{
private readonly IServiceProvider _provider;
public ImportRepository(IServiceProvider provider)
{
_provider = provider;
...
}
public void DoSomething()
{
var dBContext = (ApplicationDbContext) provider.GetService(typeof(ApplicationDbContext));
...
}
}
By the way, there is an extension method GetService<T>(); defined in Microsoft.Extensions.DependencyInjection namespace:
// using Microsoft.Extensions.DependencyInjection;
var dBContext = provider.GetService<ApplicationDbContext>();
Since your singleton lives longer and is shared, the only option I see is that you take it as a parameter to the functions.
public class ImportRepository : IImportRepository
{
public void DoSomething(ApplicationDbContext context, IDataStore store)
{
}
}
The other option is to make ImportRepository scoped as well.
Ok. I have a soulution, that works, but not perfektly.
Like Juunas example i build a long life funktion
public async Task RunImportAsync(string fileName, DataService data)
{
await Task.Run(() =>
{
if (!System.IO.File.Exists(internalPath + fileName))
{
throw new Exception($"Datei {fileName} nicht gefunden.");
}
[long Operations...]
data.DBContext.Add(new ImportHistory(set));
data.DBContext.SaveChanges();
});
}
the call is simple
[HttpPost]
[Route("runImport")]
public async Task<IActionResult> RunImport([FromBody]dynamic body)
{
string id = "";
try
{
id = body.filename;
_logger.LogInformation($"Import from {id}");
await ImportService.RunImportAsync(id, DB);
return StatusCode(StatusCodes.Success_2xx.OK);
}
catch (Exception e)
{
return SendError(e);
}
}
But postmen get no Response with this solution. Is there a idea, how i can fix it?

Create an User in a Console .NET Core Application

I have a ASP.NET Core 1.0 Solution with 3 projects (Web, Console Application, DataAccessLayer).
I use ASP.NET Core Identity and Entity Framework Core (SQL Server - Code First).
In my Console Application (Used for background tasks), I want to create users, but how I can have access to UserManager object in a Console Application (Or in a .NET Core Class Library) ?
In a controller class, it's easy with Dependency Injection :
public class AccountController : Controller {
private readonly UserManager<ApplicationUser> _userManager;
public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
{
_userManager = userManager;
}
//...
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);
//...
}
How I can do the equivalent in a Console Core Application ?
Thanks to Tseng's answer I ended up with this code. Just in case if someone would need:
public class Program
{
private interface IUserCreationService
{
Task CreateUser();
}
public static void Main(string[] args)
{
var services = new ServiceCollection();
services.AddDbContext<ApplicationDbContext>(
options =>
{
options.UseSqlServer("Server=(localdb)\\mssqllocaldb;Database=my-app-db;Trusted_Connection=True;MultipleActiveResultSets=true");
});
// Authentification
services.AddIdentity<ApplicationUser, IdentityRole>(opt =>
{
// Configure identity options
opt.Password.RequireDigit = false;
opt.Password.RequireLowercase = false;
opt.Password.RequireUppercase = false;
opt.Password.RequireNonAlphanumeric = false;
opt.Password.RequiredLength = 6;
opt.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddScoped<IUserCreationService, UserCreationService>();
// Build the IoC from the service collection
var provider = services.BuildServiceProvider();
var userService = provider.GetService<IUserCreationService>();
userService.CreateUser().GetAwaiter().GetResult();
Console.ReadKey();
}
private class UserCreationService : IUserCreationService
{
private readonly UserManager<ApplicationUser> userManager;
public UserCreationService(UserManager<ApplicationUser> userManager)
{
this.userManager = userManager;
}
public async Task CreateUser()
{
var user = new ApplicationUser { UserName = "TestUser", Email = "test#example.com" };
var result = await this.userManager.CreateAsync(user, "123456");
if (result.Succeeded == false)
{
foreach (var error in result.Errors)
{
Console.WriteLine(error.Description);
}
}
else
{
Console.WriteLine("Done.");
}
}
}
}
In my Console Application (Used for background tasks), I want to create users, but how I can have access to UserManager object in a Console Application (Or in a .NET Core Class Library) ?
Same as you do it in ASP.NET Core. You just need to bootstrap it yourself. Inside your Main (which is the console applications composition root - the earliest point where you can set up your object graph).
Here you create a ServiceCollection instance, register the services and build the container, then resolve your app entry point. From there, anything else goes via DI.
public static int Main(string[] args)
{
var services = new ServiceCollection();
// You can use the same `AddXxx` methods you did in ASP.NET Core
services.AddIdentity();
// Or register manually
services.AddTransient<IMyService,MyService();
services.AddScoped<IUserCreationService,UserCreationService>();
...
// build the IoC from the service collection
var provider = services.BuildServiceProvider();
var userService = provider.GetService<IUserCreationService>();
// we can't await async in Main method, so here this is okay
userService.CreateUser().GetAwaiter().GetResult();
}
public class UserCreationService : IUserCreationService
{
public UserManager<ApplicationUser> userManager;
public UserCreationService(UserManager<ApplicationUser> userManager)
{
this.userManager = userManager;
}
public async Task CreateUser()
{
var user = new ApplicationUser { UserName = "TestUser", Email = "test#example.com" };
var result = await _userManager.CreateAsync(user, model.Password);
}
}
In practice the first class you resolve wouldn't be your UserCreationService but some MainApplication class, which is the core of your application and responsible for keeping the application alive as long as the operation happens, i.e. if its a background worker you run some kind of host (Azure Web Job Host etc.) which keeps the application running so it can receive events from outside (via some message bus) and on each event starts a specific handler or action, which in turn resolves other services etc.
I know this answer is late, but other people might benefit.
You are seriously overcomplicating things using services etc.
You can just do:
var userStore = new UserStore<ApplicationUser>(new ApplicationDbContext());
var manager = new ApplicationUserManager(userStore);
var result = await manager.Create(user, password);
If you still want all the password validation functionality just add it to the constructor of ApplicationUserManager

Resources