Thanks @vrajasekaran for your suggestion. We will create a module development tutorial soon, that will be much better.
what is a best practice for this use case in DDD
If you want to truely implement DDD, you can see my presentation: https://www.youtube.com/watch?v=Yx3Y3-GC9EE It also covers your question.
I don't think creating and maintaining multiple user entities is very practical.
Never do that. Just add "Guid UserId" (a reference) instead of "AppUser User" (navigation property). You then need to make join LINQ if you want to access a user related to a ticket.
However, it is still possible to add a navigation property, but you should understand the migration system that we've created. Unfortunately it is not easy to create such a modolar systems with EF Core, so it has some little difficulties to use. See this document as a reference: https://docs.abp.io/en/abp/latest/Entity-Framework-Core-Migrations
I suggest to not define navigation properties to the AppUser (in DDD, this is not a good practice). However, if you really want it, the explanation mentioned by @alper can be implemented.
If AppUser
has ExtraProperties
property and AppUserDto
doesn't have this property, then AutoMapper throws such a validation error. So, this is an expected case. You can ignore it or create ExtraProperties in your DTO, based on your business requirement.
Thanks @AndrewT for your feedback.
See https://blog.abp.io/abp/ABP-v2.8.0-Releases-&-Road-Map
Blazor has a very high priority in our road map among major works.
Great explanation :)
Hi,
This UI is used to manage clients. You can create new clients of edit existing ones.
YourProjectName_Web is a pre-defined client used by the Angular UI. Be careful on editing it, since your application may not properly work if you remove some necessary resources from this client.
You can define new clients here. When you define a new client, then you (or anyone you've shared it) can connect to your application with this new client.
If you are not sure what a client is, please refer to the IdentityServer documentation: https://identityserver4.readthedocs.io/en/latest/ If you are new to IDS, the big picture and the termonilogy documents are good points to start with.
Unfortunately, IDS and OAuth are complex, and you need to understand it to customize. ABP Commercial makes it easy by providing UI and pre-defined configuration for you.
BTW, if you want to remove the IdentityServer module from your system and use another Identity Server (like Azure AD), it is another topic. We use standard Identity and IdentityServer libraries, so you can find documents on the web. Since they are not our products, we don't provide advanced support for them as a part of the standard ABP Commercial support.
If you have a specific question, however, we will try to help you.
Thanks.
Check package.json, it should have using @volo/abp.aspnetcore.mvc.ui.theme.lepton 2.4.0
Run yarn
on the command line (in the folder containing your web project)
Run gulp
This will restore missing files.
Can you try to install the latest .net core SDK (v3.1.102)? https://dotnet.microsoft.com/download/dotnet-core/thank-you/sdk-3.1.102-windows-x64-installer
Hi,
We are using the Identity Server for authentication. There are some different flows, but I think the most convinient way is to use the resource owner password flow for your case.
The downloaded startup template has a .HttpApi.Client.ConsoleTestApp project which authenticates using this flow by default. However, it assumes that username and password is hard-coded in the appsettings.json. I will explain you how to convert this project to dynamically get username & password from user, then authenticate and get access token.
AccessTokenManager
class like that:using System;
using System.Net.Http;
using System.Threading.Tasks;
using IdentityModel.Client;
using Volo.Abp.DependencyInjection;
namespace MyCompanyName.MyProjectName.HttpApi.Client.ConsoleTestApp
{
public class AccessTokenManager : ISingletonDependency
{
public string AccessToken { get; private set; }
private readonly IHttpClientFactory _httpClientFactory;
public AccessTokenManager(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task ObtainAccessToken()
{
Console.Write("Username: ");
var userName = Console.ReadLine();
Console.Write("Password: ");
var password = Console.ReadLine();
var discoveryResponse = await GetDiscoveryResponse();
var tokenResponse = await GetTokenResponse(discoveryResponse, userName, password);
AccessToken = tokenResponse.AccessToken;
}
protected async Task<DiscoveryDocumentResponse> GetDiscoveryResponse()
{
using (var httpClient = _httpClientFactory.CreateClient())
{
return await httpClient.GetDiscoveryDocumentAsync(new DiscoveryDocumentRequest
{
Address = "https://localhost:44301",
Policy = { RequireHttps = true }
});
}
}
protected async Task<TokenResponse> GetTokenResponse(
DiscoveryDocumentResponse discoveryResponse,
string userName,
string password
)
{
using (var httpClient = _httpClientFactory.CreateClient())
{
return await httpClient.RequestPasswordTokenAsync(
await CreatePasswordTokenRequestAsync(discoveryResponse, userName, password)
);
}
}
protected virtual Task<PasswordTokenRequest> CreatePasswordTokenRequestAsync(
DiscoveryDocumentResponse discoveryResponse,
string userName,
string password)
{
var request = new PasswordTokenRequest
{
Address = discoveryResponse.TokenEndpoint,
Scope = "MyProjectName",
ClientId = "MyProjectName_App",
ClientSecret = "1q2w3e*",
UserName = userName,
Password = password
};
return Task.FromResult(request);
}
}
}
ObtainAccessToken()
method gets user & pass from console, authenticates to the identity server (just as described in the IDS4 documentation), then sets it to the AccessToken
property. This class is singleton, so you can access the token from another service later.
I've written the configuration hard-coded, you need to refactor the code :)
IRemoteServiceHttpClientAuthenticator
to get the access token. So, you need to implement it:using System.Threading.Tasks;
using IdentityModel.Client;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Http.Client.Authentication;
namespace MyCompanyName.MyProjectName.HttpApi.Client.ConsoleTestApp
{
public class MyRemoteServiceHttpClientAuthenticator : IRemoteServiceHttpClientAuthenticator, ITransientDependency
{
private readonly AccessTokenManager _accessTokenManager;
public MyRemoteServiceHttpClientAuthenticator(AccessTokenManager accessTokenManager)
{
_accessTokenManager = accessTokenManager;
}
public Task Authenticate(RemoteServiceHttpClientAuthenticateContext context)
{
context.Client.SetBearerToken(_accessTokenManager.AccessToken);
return Task.CompletedTask;
}
}
}
This gets the token from the AccessTokenManager
. It is very simple.
AccessTokenManager.ObtainAccessToken()
on your login screen of the WPF app. In this console app, I called it inside the ConsoleTestAppHostedService
, before the ClientDemoService
usage:await application.ServiceProvider
.GetRequiredService<AccessTokenManager>()
.ObtainAccessToken();
var demo = application.ServiceProvider.GetRequiredService<ClientDemoService>();
await demo.RunAsync();
That's all! Enjoy with the ABP Framework :)