@ -1,5 +1,6 @@ |
|||
{ |
|||
"culture": "zh-Hans", |
|||
"texts": { |
|||
"Buy": "购买" |
|||
} |
|||
} |
|||
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 142 KiB |
@ -0,0 +1,82 @@ |
|||
# ABP.IO Platform 7.1 Final Has Been Released! |
|||
|
|||
[ABP Framework](https://abp.io/) and [ABP Commercial](https://commercial.abp.io/) 7.1 versions have been released today. |
|||
|
|||
## What's New With 7.1? |
|||
|
|||
Since all the new features are already explained in detail in the [7.1 RC Announcement Post](https://blog.abp.io/abp/ABP.IO-Platform-7.1-RC-Has-Been-Published), I will not repeat all the details again. See the [RC Blog Post](https://blog.abp.io/abp/ABP.IO-Platform-7.1-RC-Has-Been-Published) for all the features and enhancements. |
|||
|
|||
## Getting Started with 7.1 |
|||
|
|||
### Creating New Solutions |
|||
|
|||
You can create a new solution with the ABP Framework version 7.1 by either using the `abp new` command or generating the CLI command on the [get started page](https://abp.io/get-started). |
|||
|
|||
> See the [getting started document](https://docs.abp.io/en/abp/latest/Getting-Started) for more. |
|||
|
|||
### How to Upgrade an Existing Solution |
|||
|
|||
#### Install/Update the ABP CLI |
|||
|
|||
First of all, install the ABP CLI or upgrade to the latest version. |
|||
|
|||
If you haven't installed it yet: |
|||
|
|||
```bash |
|||
dotnet tool install -g Volo.Abp.Cli |
|||
``` |
|||
|
|||
To update an existing installation: |
|||
|
|||
```bash |
|||
dotnet tool update -g Volo.Abp.Cli |
|||
``` |
|||
|
|||
#### Upgrading Existing Solutions with the ABP Update Command |
|||
|
|||
[ABP CLI](https://docs.abp.io/en/abp/latest/CLI) provides a handy command to update all the ABP related NuGet and NPM packages in your solution with a single command: |
|||
|
|||
```bash |
|||
abp update |
|||
``` |
|||
|
|||
Run this command in the root folder of your solution. |
|||
|
|||
## Migration Guides |
|||
|
|||
This version includes a very minor breaking change and it doesn't affect most of the applications. Check [the migration guide](https://docs.abp.io/en/abp/7.1/Migration-Guides/Abp-7_1) for the details. |
|||
|
|||
## Community News |
|||
|
|||
## ABP Community Talks 2023.2 |
|||
|
|||
The next ABP Community Talks will be done on March 30, at 18:00 (UTC). |
|||
|
|||
 |
|||
|
|||
In this episode, core ABP Framework developers will discuss what are the benefits of using ABP Framework as a .NET developer, instead of creating your own solution from scratch. They will answer most of the common doubts about using ABP and application frameworks in general. You will better understand how ABP makes a developer’s life easier and more enjoyable while cutting production costs. We will also have a question - answer session after the talk, as always. I think this talk will be useful for every .NET developer regardless of whether they use ABP or not. |
|||
|
|||
**[CLICK HERE to register to the event and join us](https://kommunity.com/volosoft/events/abp-community-talks-20232-why-use-abp-framework-as-a-net-developer-e3254183)**. |
|||
|
|||
## Introducing the first ABP .NET Conference! |
|||
|
|||
As the ABP team, we've executed more than 10 [online events](https://community.abp.io/events) and gained a good experience of software talks. In May, we are organizing a full-featured software conference, named **ABP Dotnet Conference 2023**! |
|||
|
|||
 |
|||
|
|||
We are still organizing the speakers, talks and the schedule. There will be 12 sessions about software development and .NET. These will also include a few ABP-related talks. You can **follow https://abp.io/conference website** and buy early bird tickets from now. |
|||
|
|||
### New ABP Community Posts |
|||
|
|||
There are exciting articles contributed by the ABP community as always. I will highlight some of them here: |
|||
|
|||
* [Creating Dockerfile for ABP Applications](https://community.abp.io/posts/creating-dockerfile-for-abp-applications-caj4fkxa) by [Anto Subash](https://community.abp.io/members/antosubash) |
|||
* [IdentityUser Relationship and Extending it](https://community.abp.io/posts/identityuser-relationship-and-extending-it-xtv79mpx) by [Onur Pıçakçı](https://community.abp.io/members/onurpicakci) |
|||
* [Streamline Localization in Your ABP Project](https://community.abp.io/posts/streamline-localization-in-your-abp-project-1t12rmjc) by [Salih Özkara](https://community.abp.io/members/salih) |
|||
* [.Net Microservice template with ABP](https://community.abp.io/posts/.net-microservice-template-with-abp-53r52ryy) by [Anto Subash](https://community.abp.io/members/antosubash) |
|||
|
|||
Thanks to the ABP Community for all the content they have published. You can also [post your ABP related (text or video) content](https://community.abp.io/articles/submit) to the ABP Community. |
|||
|
|||
## About the Next Version |
|||
|
|||
The next feature version will be 7.2. You can follow the [release planning here](https://github.com/abpframework/abp/milestones). Please [submit an issue](https://github.com/abpframework/abp/issues/new) if you have any problems with this version. |
|||
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 329 KiB |
@ -0,0 +1,307 @@ |
|||
## Introduction |
|||
In this article, I will talk about the relationships of IdentityUser in every web application that can be created with the ABP framework. When you read this article, you will learn how to extend the user entity in the applications you develop using the ABP framework with a primitive type, extending the user by associating the user with another entity (User-many-to-one-X). |
|||
|
|||
|
|||
## Creating the Solution |
|||
>For the source code of the application: https://github.com/onurpicakci/Abp-Identity-Relationship |
|||
|
|||
In this article we will use EF Core as the database provider and MVC as the user interface framework. But Angular, Blazor Server and Blazor WebAssembly also work. ABP Framework offers starter templates to get started faster. We can create a new starter template using the ABP CLI: |
|||
|
|||
```bash |
|||
abp new IdentityRelationship |
|||
``` |
|||
|
|||
After the project is created, you can run the `IdentityRelationship.DbMigrator` project to create the database and seed the initial data. You can then run the `IdentityRelationship.Web` project to see our application run. |
|||
|
|||
> The default admin username is **admin** and the password is **1q2w3E\*** |
|||
|
|||
 |
|||
|
|||
## Module Entity Extensions |
|||
|
|||
The module entity extension system is a high level extension system that allows you to define new properties for existing entities of the depended modules. It automatically adds properties to the entity, database, HTTP API and the user interface in a single point. |
|||
|
|||
### Extending the User Entity With a Primitive Type |
|||
|
|||
Open the `IdentityRelationshipModuleExtensionConfigurator` class inside the `Domain.Shared` project of your solution and change the `ConfigureExtraProperties` method as shown below to add an `IdentificationNumber` property to the `IdentityUser` entity of the [Identity Module](https://docs.abp.io/en/abp/latest/Modules/Identity). |
|||
|
|||
```csharp |
|||
public static void ConfigureExtraProperties() |
|||
{ |
|||
OneTimeRunner.Run(() => |
|||
{ |
|||
ObjectExtensionManager.Instance.Modules() |
|||
.ConfigureIdentity(identity => |
|||
{ |
|||
identity.ConfigureUser(user => |
|||
{ |
|||
user.AddOrUpdateProperty<string>( //property type: string |
|||
"IdentificationNumber", //property name |
|||
property => |
|||
{ |
|||
//validation rules |
|||
property.Attributes.Add(string.Empty); |
|||
property.Attributes.Add( |
|||
new StringLengthAttribute(64) { |
|||
MinimumLength = 4 |
|||
} |
|||
); |
|||
|
|||
//...other configurations for this property |
|||
} |
|||
); |
|||
}); |
|||
}); |
|||
}); |
|||
} |
|||
``` |
|||
> This method is called inside the IdentityRelationshipDomainSharedModule at the beginning of the application. OneTimeRunner is a utility class that guarantees to execute this code only one time per application, since multiple calls are unnecessary. |
|||
|
|||
If you want to localize, open the `IdentityRelationship.Domain.Shared` project and create a new localization in your `/Localization/IdentityRelationship/en.json` file. |
|||
|
|||
```json |
|||
"IdentificationNumber": "Identification Number" |
|||
``` |
|||
Once you define a property, it appears in the create and update forms of the related entity: |
|||
|
|||
 |
|||
|
|||
New properties also appear in the data table of the related page: |
|||
|
|||
 |
|||
|
|||
|
|||
## Navigation Properties / Foreign Keys |
|||
|
|||
It is supported to add an extension property to an entity that is the Id of another entity (foreign key). |
|||
|
|||
### Example: Let's associate a department in the database with a user |
|||
|
|||
First, create a `Departments` folder in the `IdentityRelationship.Domain` project and add the `Department` class inside: |
|||
```csharp |
|||
using System; |
|||
using Volo.Abp.Domain.Entities; |
|||
|
|||
namespace IdentityRelationship.Departments; |
|||
|
|||
public class Department : AggregateRoot<Guid> |
|||
{ |
|||
public string Name { get; set; } |
|||
} |
|||
``` |
|||
|
|||
EF Core requires that you relate the entities with your `DbContext`. The easiest way to do so is adding a DbSet property to the `IdentityRelationshipDbContext` class in the `IdentityRelationship.EntityFrameworkCore` project, as shown below: |
|||
|
|||
```csharp |
|||
public DbSet<Department> Departments { get; set; } |
|||
``` |
|||
|
|||
Then in the `IdentityRelationship.EntityFrameworkCore` project of your solution, open the `/EntityFrameworkCore/IdentityRelationshipEfCoreEntityExtensionMappings` class and update your code: |
|||
|
|||
```csharp |
|||
public static class IdentityRelationshipEfCoreEntityExtensionMappings |
|||
{ |
|||
private static readonly OneTimeRunner OneTimeRunner = new OneTimeRunner(); |
|||
|
|||
public static void Configure() |
|||
{ |
|||
IdentityRelationshipGlobalFeatureConfigurator.Configure(); |
|||
IdentityRelationshipModuleExtensionConfigurator.Configure(); |
|||
|
|||
OneTimeRunner.Run(() => |
|||
{ |
|||
ObjectExtensionManager.Instance |
|||
.MapEfCoreProperty<IdentityUser, Guid>( |
|||
"DepartmentId", |
|||
(entityBuilder, propertyBuilder) => { propertyBuilder.HasMaxLength(128); } |
|||
); |
|||
|
|||
}); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
This class can be used to map these extra properties to table fields in the database. Please read [this](https://docs.abp.io/en/abp/latest/Customizing-Application-Modules-Extending-Entities?_ga=2.21022651.140118448.1679289046-1173891759.1672473062) document to improve your understanding of what we are doing. |
|||
|
|||
We need to create a new migration to see the changes in the database. Open your `EntityFrameworkCore` project in the terminal and run the following command (this depends on the IDE you are using). |
|||
|
|||
 |
|||
|
|||
```bash |
|||
dotnet ef migrations add Create_Department_Entity |
|||
``` |
|||
|
|||
Finally, run the `IdentityRelationship.DbMigrator` project to update the database. |
|||
|
|||
When you look at your database, you can see that the `Department` table has been added and `DepartmentId` has been added to your `AbpUsers` table. |
|||
|
|||
 |
|||
|
|||
 |
|||
|
|||
> It's good to have some initial data in the database before running the application. This section introduces the [Data Seeding](https://docs.abp.io/en/abp/latest/Data-Seeding) system of the ABP framework. You can skip this section if you don't want to create the data seeding, but it is suggested to follow along and learn this useful ABP Framework feature. |
|||
|
|||
Create a class deriving from the `IDataSeedContributor` in the `IdentityRelationship.Domain` project by copying the following code: |
|||
|
|||
```csharp |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using IdentityRelationship.Departments; |
|||
using Volo.Abp.Data; |
|||
using Volo.Abp.DependencyInjection; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace IdentityRelationship; |
|||
|
|||
public class IdentityRelationshipDataSeederContributor |
|||
: IDataSeedContributor, ITransientDependency |
|||
{ |
|||
private readonly IRepository<Department, Guid> _departmentRepository; |
|||
|
|||
public IdentityRelationshipDataSeederContributor(IRepository<Department, Guid> departmentRepository) |
|||
{ |
|||
_departmentRepository = departmentRepository; |
|||
} |
|||
|
|||
public async Task SeedAsync(DataSeedContext context) |
|||
{ |
|||
if (await _departmentRepository.GetCountAsync() <= 0) |
|||
{ |
|||
await _departmentRepository.InsertAsync( |
|||
new Department |
|||
{ |
|||
Name = "Human Resources" |
|||
}, |
|||
autoSave: true |
|||
); |
|||
|
|||
await _departmentRepository.InsertAsync( |
|||
new Department |
|||
{ |
|||
Name = "Production" |
|||
}, |
|||
autoSave: true |
|||
); |
|||
} |
|||
} |
|||
} |
|||
``` |
|||
- This code simply uses the `IRepository<Department, Guid>` (the default [repository](https://docs.abp.io/en/abp/latest/Repositories)) to insert two books to the database in case there weren't any books in it. |
|||
|
|||
Run the `IdentityRelationship.DbMigrator` application to update the database: |
|||
|
|||
 |
|||
|
|||
Again, open the `IdentityRelationshipModuleExtensionConfigurator` class in the Domain.Shared project and add the following code: |
|||
|
|||
```csharp |
|||
|
|||
user.AddOrUpdateProperty<Guid>( |
|||
"DepartmentId", |
|||
property => |
|||
{ |
|||
property.UI.Lookup.Url = "/api/app/department"; |
|||
property.UI.Lookup.DisplayPropertyName = "name"; |
|||
} |
|||
); |
|||
``` |
|||
|
|||
The `UI.Lookup.Url` option takes a URL to get the list of departments to select on the edit/create forms. This endpoint can be a typical controller, an auto API controller or any type of endpoint that returns a proper JSON response. |
|||
|
|||
To localize, open the `IdentityRelationship.Domain.Shared` project and add it to your `/Localization/IdentityRelationship/en.json` file: |
|||
|
|||
```json |
|||
"DepartmentId": "Department" |
|||
``` |
|||
|
|||
Create a `Departments` folder in the `IdentityRelationship.Application.Contracts` project of your solution and add the `DepartmentDto` class in it |
|||
|
|||
```csharp |
|||
using System; |
|||
using Volo.Abp.Application.Dtos; |
|||
namespace IdentityRelationship.Departments; |
|||
|
|||
public class DepartmentDto : EntityDto<Guid> |
|||
|
|||
{ |
|||
public string Name { get; set; } |
|||
} |
|||
``` |
|||
Now let's create an `IDepartmentAppService` interface in the `Departments` folder |
|||
|
|||
```csharp |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Application.Services; |
|||
|
|||
namespace IdentityRelationship.Departments; |
|||
|
|||
public interface IDepartmentAppService : IApplicationService |
|||
{ |
|||
public Task<ListResultDto<DepartmentDto>> GetAsync(); |
|||
} |
|||
``` |
|||
|
|||
Time to implement the `IDepartmentAppService` interface. Create a `Departments` folder in your `IdentityRelationship.Application` project and add the `DepartmentAppService` class inside. |
|||
|
|||
```csharp |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
using IdentityRelationship.Departments; |
|||
using Volo.Abp.Application.Dtos; |
|||
using Volo.Abp.Domain.Repositories; |
|||
|
|||
namespace IdentityRelationship.Department; |
|||
|
|||
public class DepartmentAppService : IdentityRelationshipAppService, IDepartmentAppService |
|||
{ |
|||
private readonly IRepository<Departments.Department, Guid> _departmentRepository; |
|||
|
|||
public DepartmentAppService(IRepository<Departments.Department, Guid> departmentRepository) |
|||
{ |
|||
_departmentRepository = departmentRepository; |
|||
} |
|||
|
|||
public async Task<ListResultDto<DepartmentDto>> GetAsync() |
|||
{ |
|||
var departments = await _departmentRepository.GetListAsync(); |
|||
return new ListResultDto<DepartmentDto>( |
|||
ObjectMapper.Map<List<Departments.Department>, List<DepartmentDto>>(departments)); |
|||
} |
|||
} |
|||
``` |
|||
`DepartmentAppService `is using the `ObjectMapper` to convert the `Department` objects to `DepartmentDto` objects. So, we need to define this mapping in the AutoMapper configuration. |
|||
|
|||
Open the `IdentityRelationshipApplicationAutoMapperProfile` class inside the `IdentityRelationship.Application` project and add the following line to the constructor: |
|||
|
|||
```csharp |
|||
using AutoMapper; |
|||
using IdentityRelationship.Departments; |
|||
|
|||
namespace IdentityRelationship; |
|||
|
|||
public class IdentityRelationshipApplicationAutoMapperProfile : Profile |
|||
{ |
|||
public IdentityRelationshipApplicationAutoMapperProfile() |
|||
{ |
|||
CreateMap<Departments.Department, DepartmentDto>(); |
|||
} |
|||
} |
|||
``` |
|||
|
|||
Run your `IdentityRelationship.Web` project and add a department to one of your users. |
|||
|
|||
 |
|||
|
|||
And it shows the department name on the data table: |
|||
|
|||
 |
|||
|
|||
## Conclusion |
|||
In this article I talked about the use of the IdentityUser relationship and how to extend it. Thank you for reading the article, I hope it was useful. See you soon! |
|||
|
|||
## References |
|||
- https://docs.abp.io/en/abp/latest/Module-Entity-Extensions |
|||
- https://learn.microsoft.com/en-us/ef/core/modeling/relationships |
|||
- https://community.abp.io/posts/how-to-add-custom-properties-to-the-user-entity-rixchoha |
|||
|
After Width: | Height: | Size: 217 KiB |
|
After Width: | Height: | Size: 50 KiB |
|
After Width: | Height: | Size: 273 KiB |
|
After Width: | Height: | Size: 92 KiB |
|
After Width: | Height: | Size: 70 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 160 KiB |
|
After Width: | Height: | Size: 65 KiB |
|
After Width: | Height: | Size: 278 KiB |
@ -1,20 +1,20 @@ |
|||
using System.Threading; |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.DistributedLocking; |
|||
|
|||
public class LocalAbpDistributedLockHandle : IAbpDistributedLockHandle |
|||
{ |
|||
private readonly SemaphoreSlim _semaphore; |
|||
private readonly IDisposable _disposable; |
|||
|
|||
public LocalAbpDistributedLockHandle(SemaphoreSlim semaphore) |
|||
public LocalAbpDistributedLockHandle(IDisposable disposable) |
|||
{ |
|||
_semaphore = semaphore; |
|||
_disposable = disposable; |
|||
} |
|||
|
|||
public ValueTask DisposeAsync() |
|||
{ |
|||
_semaphore.Release(); |
|||
_disposable.Dispose(); |
|||
return default; |
|||
} |
|||
} |
|||
|
|||
@ -0,0 +1,26 @@ |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.Json.Newtonsoft; |
|||
using Volo.Abp.Json.SystemTextJson; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.Json; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpAutofacModule), |
|||
typeof(AbpJsonSystemTextJsonModule), |
|||
typeof(AbpTestBaseModule) |
|||
)] |
|||
public class AbpJsonSystemTextJsonTestModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
|
|||
[DependsOn( |
|||
typeof(AbpAutofacModule), |
|||
typeof(AbpJsonNewtonsoftModule), |
|||
typeof(AbpTestBaseModule) |
|||
)] |
|||
public class AbpJsonNewtonsoftTestModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
using Volo.Abp.Testing; |
|||
|
|||
namespace Volo.Abp.Json; |
|||
|
|||
public abstract class AbpJsonSystemTextJsonTestBase : AbpIntegratedTest<AbpJsonSystemTextJsonTestModule> |
|||
{ |
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
} |
|||
|
|||
public abstract class AbpJsonNewtonsoftJsonTestBase : AbpIntegratedTest<AbpJsonNewtonsoftTestModule> |
|||
{ |
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
} |
|||
@ -1,11 +0,0 @@ |
|||
using Volo.Abp.Testing; |
|||
|
|||
namespace Volo.Abp.Json; |
|||
|
|||
public abstract class AbpJsonTestBase : AbpIntegratedTest<AbpJsonTestModule> |
|||
{ |
|||
protected override void SetAbpApplicationCreationOptions(AbpApplicationCreationOptions options) |
|||
{ |
|||
options.UseAutofac(); |
|||
} |
|||
} |
|||
@ -1,14 +0,0 @@ |
|||
using Volo.Abp.Autofac; |
|||
using Volo.Abp.Modularity; |
|||
|
|||
namespace Volo.Abp.Json; |
|||
|
|||
[DependsOn( |
|||
typeof(AbpAutofacModule), |
|||
typeof(AbpJsonModule), |
|||
typeof(AbpTestBaseModule) |
|||
)] |
|||
public class AbpJsonTestModule : AbpModule |
|||
{ |
|||
|
|||
} |
|||
@ -0,0 +1,112 @@ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Shouldly; |
|||
using Volo.Abp.Timing; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.Json; |
|||
|
|||
public class InputAndOutputDateTimeFormatSystemTextJsonTests : AbpJsonSystemTextJsonTestBase |
|||
{ |
|||
private readonly IJsonSerializer _jsonSerializer; |
|||
|
|||
public InputAndOutputDateTimeFormatSystemTextJsonTests() |
|||
{ |
|||
_jsonSerializer = GetRequiredService<IJsonSerializer>(); |
|||
} |
|||
|
|||
protected override void AfterAddApplication(IServiceCollection services) |
|||
{ |
|||
services.Configure<AbpJsonOptions>(options => |
|||
{ |
|||
options.InputDateTimeFormats = new List<string>() |
|||
{ |
|||
"yyyy*MM*dd", |
|||
"yyyy-MM-dd HH:mm:ss" |
|||
}; |
|||
options.OutputDateTimeFormat = "yyyy*MM-dd HH:mm:ss"; |
|||
}); |
|||
services.Configure<AbpClockOptions>(options => |
|||
{ |
|||
options.Kind = DateTimeKind.Utc; |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void InputAndOutputDateTimeFormat_Test() |
|||
{ |
|||
var resultDate = new DateTime(2016, 04, 13, 08, 58, 10, DateTimeKind.Utc); |
|||
var json = _jsonSerializer.Serialize(new DateTimeDto() |
|||
{ |
|||
DateTime1 = resultDate, |
|||
DateTime2 = resultDate |
|||
}); |
|||
json.ShouldContain("\"DateTime1\":\"2016*04-13 08:58:10\""); |
|||
json.ShouldContain("\"DateTime2\":\"2016*04-13 08:58:10\""); |
|||
|
|||
var dto = _jsonSerializer.Deserialize<DateTimeDto>("{\"DateTime1\":\"" + resultDate.ToString("yyyy*MM*dd") + "\",\"DateTime2\":\"" + resultDate.ToString("yyyy-MM-dd HH:mm:ss") + "\"}"); |
|||
dto.DateTime1.ShouldBe(resultDate.Date); |
|||
dto.DateTime1.Kind.ShouldBe(DateTimeKind.Utc); |
|||
dto.DateTime2.ShouldBe(resultDate); |
|||
dto.DateTime2.Value.Kind.ShouldBe(DateTimeKind.Utc); |
|||
} |
|||
|
|||
public class DateTimeDto |
|||
{ |
|||
public DateTime DateTime1 { get; set; } |
|||
public DateTime? DateTime2 { get; set; } |
|||
} |
|||
} |
|||
|
|||
public class InputAndOutputDateTimeFormatNewtonsoftTests : AbpJsonNewtonsoftJsonTestBase |
|||
{ |
|||
private readonly IJsonSerializer _jsonSerializer; |
|||
|
|||
public InputAndOutputDateTimeFormatNewtonsoftTests() |
|||
{ |
|||
_jsonSerializer = GetRequiredService<IJsonSerializer>(); |
|||
} |
|||
|
|||
protected override void AfterAddApplication(IServiceCollection services) |
|||
{ |
|||
services.Configure<AbpJsonOptions>(options => |
|||
{ |
|||
options.InputDateTimeFormats = new List<string>() |
|||
{ |
|||
"yyyy*MM*dd", |
|||
"yyyy-MM-dd HH:mm:ss" |
|||
}; |
|||
options.OutputDateTimeFormat = "yyyy*MM-dd HH:mm:ss"; |
|||
}); |
|||
services.Configure<AbpClockOptions>(options => |
|||
{ |
|||
options.Kind = DateTimeKind.Utc; |
|||
}); |
|||
} |
|||
|
|||
[Fact] |
|||
public void InputAndOutputDateTimeFormat_Test() |
|||
{ |
|||
var resultDate = new DateTime(2016, 04, 13, 08, 58, 10, DateTimeKind.Utc); |
|||
var json = _jsonSerializer.Serialize(new DateTimeDto() |
|||
{ |
|||
DateTime1 = resultDate, |
|||
DateTime2 = resultDate |
|||
}); |
|||
json.ShouldContain("\"DateTime1\":\"2016*04-13 08:58:10\""); |
|||
json.ShouldContain("\"DateTime2\":\"2016*04-13 08:58:10\""); |
|||
|
|||
var dto = _jsonSerializer.Deserialize<DateTimeDto>("{\"DateTime1\":\"" + resultDate.ToString("yyyy*MM*dd") + "\",\"DateTime2\":\"" + resultDate.ToString("yyyy-MM-dd HH:mm:ss") + "\"}"); |
|||
dto.DateTime1.ShouldBe(resultDate.Date); |
|||
dto.DateTime1.Kind.ShouldBe(DateTimeKind.Utc); |
|||
dto.DateTime2.ShouldBe(resultDate); |
|||
dto.DateTime2.Value.Kind.ShouldBe(DateTimeKind.Utc); |
|||
} |
|||
|
|||
public class DateTimeDto |
|||
{ |
|||
public DateTime DateTime1 { get; set; } |
|||
public DateTime? DateTime2 { get; set; } |
|||
} |
|||
} |
|||