How can I force all validation errors to show in an Angular form?
I've got a simple form with a required field
this.form = this.fb.group({
name: [name ?? null, [Validators.required]]
});
But when I click submit, no errors are shown.
submitForm()
{
if(!this.form.valid)
{
// How do I show the errors?
return;
}
// ...
}
If I type something into the field, then delete it, the required validation message shows.
I want to show all validation errors when the user tries to submit an invalid form.
How do I set the default culture and UI culture of my Angular app?
I've configured my FooApiHostModule like so
private void ConfigureLocalization()
{
Configure<AbpLocalizationOptions>(options =>
{
options.Languages.Clear();
options.Languages.Add(new LanguageInfo("en-GB", "en-GB", "English"));
});
}
I've duplicated the en.json localization file and renamed it en-GB, I've changed the Culture
elemein in the top of that file like so
{
"Culture": "en-GB",
"Texts": {
...
}
}
If I put a breakpoint in a controller action, and inspect System.Threading.Thread.CurrentThread.CurrentCulture
and System.Threading.Thread.CurrentThread.CurrentUICulture
they're both "en", not "en-GB".
How do I get my application to run in en-GB
?
I've also cahnged my Startup.Configure()
method like so, but this doesn't fix it either.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
app.InitializeApplication();
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("en-GB"),
SupportedCultures =
{
new CultureInfo("en-GB")
},
SupportedUICultures =
{
new CultureInfo("en-GB")
}
});
}
Hi @liangshiwei. I've added that and it still only generates the update statement for the Customer.
Anything else I can try?
I've got an entity with a backing field navigation property like so.
public class Customer : FullAuditedAggregateRoot<Guid>, IHasTimelineTopic, IHasAttachments
{
private readonly HashSet<Contact> _contacts = new();
public IEnumerable<Contact> Contacts => _contacts?.ToList();
public void AddContacts(IEnumerable<Contact> contacts)
{
Check.NotNull(contacts, nameof(contacts));
foreach (var contact in contacts)
{
_contacts.Add(contact);
}
}
public void RemoveContacts(IEnumerable<Contact> contacts)
{
Check.NotNull(contacts, nameof(contacts));
foreach (var contact in contacts)
{
_contacts.Remove(contact);
}
}
}
it's EF config looks like
builder.Entity<Customer>(b =>
{
b.ToTable(FooConsts.DbTablePrefix + "Customers", FooConsts.DbSchema);
b.ConfigureByConvention();
b.HasMany(x => x.Contacts).WithMany(x => x.Customers)
.UsingEntity(join => join.ToTable("AppCustomerContacts"));
b.Navigation(nameof(Customer.Contacts))
.UsePropertyAccessMode(PropertyAccessMode.Field);
});
In my AppService I can update it like so
[Authorize(FooPermissions.Customers.Edit)]
public virtual async Task<CustomerDto> UpdateAsync(Guid id, CustomerUpdateDto input)
{
var customer = await _customerRepository.GetAsync(id);
ObjectMapper.Map(input, customer);
var contacts = await _contactRepository.FindListAsync(input.ContactIds);
customer.AddContacts(contacts);
var toRemove = customer.Contacts.Where(x => input.ContactIds.Contains(x.Id) == false).ToList();
customer.RemoveContacts(toRemove);
customer = await _customerRepository.UpdateAsync(customer, autoSave: true);
return ObjectMapper.Map<Customer, CustomerDto>(customer);
}
this works fine and generates two SQL statements, one to update the AppCustomerContacts
xref table and one to update the entity itself.
I'm trying to write a console aplication to load some data from an Excel file. I followed the strucure of the included DbMigratior app and I've got :
IHostedService
and takes an IHostApplicationLifetime
as a constructor parameter. It has a StartAsync()
method which does just like the DbMigratior. It creates a DataSeederModule
from the AbpApplicationfactory
, calls UseAutoFac()
and AddLogging()
. Initializes the application, gets a DataSeedingService
from the ServiceProvider
and calls my SeedAsync()
method.DataSeedingService
is an IDomainService
which takes a few repositories, the IGuidGenerator
and IUnitOfWork
as constructor paramerters.The DataSeedingService
adds Contacts to my Customers in the same way as above, using .AddContacts()
but when I call await _customerRepository.UpdateAsync(customer, true);
it only generates a single SQL statement to update the entity and doesn't insert anything into AppCustomerContacts
.
What am I missing?
Here's how SeedAsync()
calls the
contact = await _contactRepository.InsertAsync(contact, true);
customer = await _customerRepository.GetAsync(customerId);
customer.AddContact(contact);
_logger.LogInformation($"\t Adding contact to customer {customer.Name}");
customer = await _customerRepository.UpdateAsync(customer, true);
My DataSeederModule
looks like this
[DependsOn(
typeof(AbpAutofacModule),
typeofFooDomainModule),
typeof(EFooEntityFrameworkCoreModule),
typeof(FooApplicationContractsModule)
)]
public class FooDataSeederModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
Configure<AbpBackgroundJobOptions>(options =>
{
options.IsJobExecutionEnabled = false;
});
}
}
Why isn't my console app generating two SQL statements? What am I missing? Do I need to reference another module or configure something at app startup?
@gterdem @alper do you have any update on this? My project is blocked on this and if I can't resolve the issue soon I'm going to have to look at re-implementing the project without IDS and ABP.
Thanks, Greg
@gterdem I've tried deploying the app to Azure and a Windows VM with the same result.
Nothing else is logged in this time. The application is just hanging on that POST to /account/login .
The application runs fine locally.
I haven't changed any code related to CORS or IdentityServer configuration. Only the URLs stated above at deployment time.
Hi @gterdem.
I don't have Redis. Locally or in the deployed environment.
I've re-deployed the API and now get 200 OK on the login endpoint.
But he login UI still hangs nad eventually gives a 500 Request timed out.
My settings in dev vs on the server are :
In the database:
IdentityServerClientPostLogoutRedirectUris Dev: http://localhost:4200 Server: https://excelerpdevstorage2.z33.web.core.windows.net
IdentityServerClientRedirectUris Dev: http://localhost:4200 Server: https://excelerpdevstorage2.z33.web.core.windows.net
AppSettings.json app.SelfUrl Dev: https://localhost:44390 Server: https://excelerp-dev-appservice.azurewebsites.net
app.ClientUrl Dev: http://localhost:4200 Server: https://excelerpdevstorage2.z33.web.core.windows.net
app.CorsOrigins Dev: https://*.ExcelErp.com,http://localhost:4200,https://localhost:44307 Server: https://excelerpdevstorage2.z33.web.core.windows.net,https://excelerp-dev-appservice.azurewebsites.net
AuthServer.Authority Dev: https://localhost:44390 Server: https://excelerp-dev-appservice.azurewebsites.net
Angular environment.ts baseUrl Dev: http://localhost:4200 Server: https://excelerpdevstorage2.z33.web.core.windows.net
oAuthConfig.issuer Dev: https://localhost:44390 Server: https://excelerp-dev-appservice.azurewebsites.net
apis.default.url Dev: https://localhost:44390 Server: https://excelerp-dev-appservice.azurewebsites.net
Here's an exerpt from my log when I log in via the API
2020-12-24 10:38:32.039 +00:00 [Debug] (Volo.Abp.EntityFrameworkCore.AbpDbContext.) Added 0 entity changes to the current audit log 2020-12-24 10:46:20.396 +00:00 [Warning] (Volo.Abp.Account.Public.Web.Ldap.LdapExternalLoginProvider.) Ldap login feature is not enabled! 2020-12-24 10:46:20.452 +00:00 [Debug] (IdentityServer4.Hosting.IdentityServerAuthenticationService.) Augmenting SignInContext 2020-12-24 10:46:20.452 +00:00 [Debug] (IdentityServer4.Hosting.IdentityServerAuthenticationService.) Adding idp claim with value: "local" 2020-12-24 10:46:20.452 +00:00 [Debug] (IdentityServer4.Hosting.IdentityServerAuthenticationService.) Adding auth_time claim with value: "1608806780" 2020-12-24 10:46:20.567 +00:00 [Debug] (Volo.Abp.EntityFrameworkCore.AbpDbContext.) Added 0 entity changes to the current audit log 2020-12-24 10:46:20.567 +00:00 [Debug] (Volo.Abp.EntityFrameworkCore.AbpDbContext.) Added 0 entity changes to the current audit log 2020-12-24 10:46:20.568 +00:00 [Debug] (Volo.Abp.EntityFrameworkCore.AbpDbContext.) Added 0 entity changes to the current audit log 2020-12-24 10:46:20.593 +00:00 [Debug] (Volo.Abp.EntityFrameworkCore.AbpDbContext.) Added 0 entity changes to the current audit log 2020-12-24 10:46:20.593 +00:00 [Debug] (Volo.Abp.EntityFrameworkCore.AbpDbContext.) Added 0 entity changes to the current audit log
Here's an exerpt from the log when I try to log in via the UI
2020-12-24 11:11:09.199 +00:00 [Debug] (IdentityServer4.Hosting.EndpointRouter.) Request path "/connect/authorize" matched to endpoint type "Authorize" 2020-12-24 11:11:09.211 +00:00 [Debug] (IdentityServer4.Hosting.EndpointRouter.) Endpoint enabled: "Authorize", successfully created handler: "IdentityServer4.Endpoints.AuthorizeEndpoint" 2020-12-24 11:11:09.211 +00:00 [Information] (IdentityServer4.Hosting.IdentityServerMiddleware.) Invoking IdentityServer endpoint: "IdentityServer4.Endpoints.AuthorizeEndpoint" for "/connect/authorize" 2020-12-24 11:11:09.211 +00:00 [Debug] (IdentityServer4.Endpoints.AuthorizeEndpoint.) Start authorize request 2020-12-24 11:11:09.211 +00:00 [Debug] (IdentityServer4.Endpoints.AuthorizeEndpoint.) No user present in authorize request 2020-12-24 11:11:09.211 +00:00 [Debug] (IdentityServer4.Validation.AuthorizeRequestValidator.) Start authorize request protocol validation 2020-12-24 11:11:09.229 +00:00 [Debug] (IdentityServer4.Stores.ValidatingClientStore.) client configuration validation for client "ExcelErp_App" succeeded. 2020-12-24 11:11:09.229 +00:00 [Debug] (IdentityServer4.Validation.AuthorizeRequestValidator.) Checking for PKCE parameters 2020-12-24 11:11:09.249 +00:00 [Debug] (IdentityServer4.Validation.AuthorizeRequestValidator.) Calling into custom validator: "IdentityServer4.Validation.DefaultCustomAuthorizeRequestValidator" 2020-12-24 11:11:09.249 +00:00 [Debug] (IdentityServer4.Endpoints.AuthorizeEndpoint.) ValidatedAuthorizeRequest AuthorizeRequestValidationLog { ClientId: "ExcelErp_App", ClientName: "ExcelErp_App", RedirectUri: "https://excelerpdevstorage2.z33.web.core.windows.net", AllowedRedirectUris: ["https://excelerpdevstorage2.z33.web.core.windows.net"], SubjectId: "anonymous", ResponseType: "code", ResponseMode: "query", GrantType: "authorization_code", RequestedScopes: "openid offline_access ExcelErp", State: "OXh6RE9odlpBMDFDdTJ0SGp1d05sN2dXMFFjZ2xIS0F2RVhxMHpCVmktLnhE", UiLocales: null, Nonce: "OXh6RE9odlpBMDFDdTJ0SGp1d05sN2dXMFFjZ2xIS0F2RVhxMHpCVmktLnhE", AuthenticationContextReferenceClasses: null, DisplayMode: null, PromptMode: null, MaxAge: null, LoginHint: null, SessionId: "", Raw: [("response_type": "code"), ("client_id": "ExcelErp_App"), ("state": "OXh6RE9odlpBMDFDdTJ0SGp1d05sN2dXMFFjZ2xIS0F2RVhxMHpCVmktLnhE"), ("redirect_uri": "https://excelerpdevstorage2.z33.web.core.windows.net"), ("scope": "openid offline_access ExcelErp"), ("code_challenge": "D2uN7NXarCoUwRwmbw_mJFeHO4Kmtk2k6sksENztO7s"), ("code_challenge_method": "S256"), ("nonce": "OXh6RE9odlpBMDFDdTJ0SGp1d05sN2dXMFFjZ2xIS0F2RVhxMHpCVmktLnhE")] } 2020-12-24 11:11:09.250 +00:00 [Information] (IdentityServer4.ResponseHandling.AuthorizeInteractionResponseGenerator.) Showing login: User is not authenticated 2020-12-24 11:11:09.294 +00:00 [Information] (Volo.Abp.AspNetCore.Mvc.AntiForgery.AbpValidateAntiforgeryTokenAuthorizationFilter.) Skipping the execution of current filter as its not the most effective filter implementing the policy Microsoft.AspNetCore.Mvc.ViewFeatures.IAntiforgeryPolicy 2020-12-24 11:11:09.321 +00:00 [Debug] (IdentityServer4.Validation.AuthorizeRequestValidator.) Start authorize request protocol validation 2020-12-24 11:11:09.327 +00:00 [Debug] (IdentityServer4.Stores.ValidatingClientStore.) client configuration validation for client "ExcelErp_App" succeeded. 2020-12-24 11:11:09.327 +00:00 [Debug] (IdentityServer4.Validation.AuthorizeRequestValidator.) Checking for PKCE parameters 2020-12-24 11:11:09.342 +00:00 [Debug] (IdentityServer4.Validation.AuthorizeRequestValidator.) Calling into custom validator: "IdentityServer4.Validation.DefaultCustomAuthorizeRequestValidator" 2020-12-24 11:11:09.347 +00:00 [Debug] (IdentityServer4.Stores.ValidatingClientStore.) client configuration validation for client "ExcelErp_App" succeeded. 2020-12-24 11:11:09.352 +00:00 [Debug] (Volo.Abp.EntityFrameworkCore.AbpDbContext.) Added 0 entity changes to the current audit log 2020-12-24 11:11:09.466 +00:00 [Debug] (Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers.AbpTagHelperResourceService.) Added bundle 'Lepton.Global' to the page in 1.51 ms. 2020-12-24 11:11:09.476 +00:00 [Debug] (Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers.AbpTagHelperResourceService.) Added bundle 'Lepton.Global' to the page in 7.19 ms. 2020-12-24 11:11:09.727 +00:00 [Debug] (Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationAppService.) Executing AbpApplicationConfigurationAppService.GetAsync()... 2020-12-24 11:11:09.752 +00:00 [Debug] (Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.AbpApplicationConfigurationAppService.) Executed AbpApplicationConfigurationAppService.GetAsync(). 2020-12-24 11:15:06.274 +00:00 [Debug] (Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers.AbpTagHelperResourceService.) Added bundle 'Lepton.Global' to the page in 1.01 ms. 2020-12-24 11:15:06.293 +00:00 [Debug] (Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers.AbpTagHelperResourceService.) Added bundle 'Lepton.Global' to the page in 8.75 ms.
As you can see it hangs after the line at 11:11:09 Executed AbpApplicationConfigurationAppService.GetAsync().
before finally timing out at 11:15.
Why is it hanging? How can I get more information?
I can't get login to work reliably after deploying to a server. It works sometimes, at a guess about 3% of the time, but I can't reproduce it reliably to get an accurate number. It only happens once deployed, but I've deployed to two separate environments, a VPS and Azure and ended up with the same situation. This suggests it's something I'm doing (or not doing) but the lack of deployment instructions makes it hard to know.
Here's what I'm doing:
import { Config } from '@abp/ng.core';
/* web URL */
const baseUrl = 'https://example.z33.web.core.windows.net';
export const environment = {
production: true,
application: {
baseUrl,
name: 'MyApp',
},
oAuthConfig: {
issuer: 'https://example-api.azurewebsites.net',
redirectUri: baseUrl,
clientId: 'MyApp_App',
responseType: 'code',
scope: 'offline_access MyApp',
},
apis: {
default: {
url: 'https://example-api.azurewebsites.net',
rootNamespace: 'MyApp',
},
},
} as Config.Environment;
"configurations": {
"production": {
...
},
"azure": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.azure.ts"
}
],
"optimization": true,
...
}
}
yarn build:azure
and upload the output to Static Website in blob storage at https://example.z33.web.core.windows.net.{
"App": {
"SelfUrl": "https://example-api.azurewebsites.net",
"ClientUrl": "https://example.z33.web.core.windows.net",
"CorsOrigins": "https://example.z33.web.core.windows.net,http://example.z33.web.core.windows.net"
},
"ConnectionStrings": {
"Default": "xxxx"
},
"AuthServer": {
"Authority": "https://example-api.azurewebsites.net",
"RequireHttpsMetadata": "true"
},
}
"ExcelErp_App": {
"ClientId": "ExcelErp_App",
"RootUrl": "https://example.z33.web.core.windows.net"
},
(as per https://support.abp.io/QA/Questions/524/UNAUTHORIZEDCLIENT-after-deploying-to-test-server, no trailing slash)
9. I run the DbMigrator and confirm the tables have been created and the seed data added. The Admin user is there and if I check [IdentityServerClientRedirectUris]
I can see a row for
ClientId RedirectUri
CDFEC9FC-51C9-A562-089C-39F953F0ECAB https://example.z33.web.core.windows.net
What's happening? What am I doing wrong?
Hey @bunyamin,
Thanks for that pointer. Any chance you can give me a snippet of how you wire it up?
Cheers, Greg