ABP VNext learning diary 28

1.IDS4 discovery document
Resolution: http://localhost:5000/.well-known/openid-configuration

2. Call IDS4 API
Resolution:

var client = new HttpClient();
client.SetBearerToken(tokenResponse.AccessToken);
var response = await client.GetAsync("http://localhost:5001/identity");
if (!response.IsSuccessStatusCode)
{
    Console.WriteLine(response.StatusCode);
}
else
{
    var content = await response.Content.ReadAsStringAsync();
    Console.WriteLine(JArray.Parse(content));
}

The returned results are as follows:

3. Client in ids4
Resolution:

new Client
{
    ClientId = "mvc",
    ClientName = "MVC client",
    AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,
    RequireConsent = false,
    ClientSecrets =
    {
        new Secret("secret".Sha256())
    },
    RedirectUris           = { "http://localhost:5002/signin-oidc" },
    PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
    AllowedScopes =
    {
        IdentityServerConstants.StandardScopes.OpenId,
        IdentityServerConstants.StandardScopes.Profile,
        "api1"
    },
    AllowOfflineAccess = true
}

4.services.AddIdentity()
Resolution:

services.AddIdentity()
.AddEntityFrameworkStores()
.AddDefaultTokenProviders();

5.services.AddIdentityServer()
Resolution:

services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryClients(Config.GetClients())
.AddInMemoryIdentityResources(Config.GetIdentityResources())
.AddAspNetIdentity();

6. Add data migration
Resolution:

dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb
dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb

7.IDS4 initialization database
Analysis: in startup CS to help initialize the database:

private void InitializeDatabase(IApplicationBuilder app)
{
    using (var serviceScope = app.ApplicationServices.GetService().CreateScope())
    {
        serviceScope.ServiceProvider.GetRequiredService().Database.Migrate();
        var context = serviceScope.ServiceProvider.GetRequiredService();
        context.Database.Migrate();
        if (!context.Clients.Any())
        {
            foreach (var client in Config.GetClients())
            {
                context.Clients.Add(client.ToEntity());
            }
            context.SaveChanges();
        }
        if (!context.IdentityResources.Any())
        {
            foreach (var resource in Config.GetIdentityResources())
            {
                context.IdentityResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }
        if (!context.ApiResources.Any())
        {
            foreach (var resource in Config.GetApiResources())
            {
                context.ApiResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }
    }
}

8. Analysis of interaction process between API and IdentityServer
Resolution:

9. Classification of design patterns
Resolution:
[1] Creative design pattern: focus on the creation of objects
[2] Structural design pattern: focus on the relationship between classes
[3] Behavioral design pattern: focus on the separation of object and behavior

10. Creative design pattern
Analysis: there are five creative design patterns, which focus on the creation of objects, that is, how to new an object.
[1]Singleton [single example]
[2] [factory method]
[3]Abstract Factory
[4]Builder [builder]
[5]Prototype [prototype]

11. Structural design mode
Analysis: seven structural design patterns, about the relationship between classes, that is, tossing combination and inheritance, provide better flexibility and expansibility for the program.
[1]Adapter Class/Object
[2]Bridge (bridge)
[3]Composite [composite]
[4]Decorator
[5]Fa ç ade [appearance)
[6]Flyweight
[7]Proxy [proxy]

12. Behavioral design model
Analysis: there are 11 behavioral design patterns, which focus on the separation of object and behavior, that is, whether the behavior [or method] is placed in this class or that class.
[1]Interpreter [interpreter]
[2]Template Method
[3]Chain of Responsibility
[4]Command [command]
[5]Iterator [iterator]
[6]Mediator
[7]Memonto [memo]
[8]Observer [observer]
[9]State [state]
[10]Strategy [strategy]
[11]Visitor [visitor]

13. Domain model and persistence
Analysis: the domain model constructs the object of the problem and solution for the actual scene, and it constructs the object behavior. The data model constructs the data itself and its storage, that is, the storage structure of data.

14. Warehousing
Analysis: warehouse is used for aggregation management. It is between domain model and data model. It is mainly used for aggregation persistence and retrieval. It isolates the domain model from the data model in order to focus on the domain model without considering how to persist.

15. Differences between warehousing and data access layer
Resolution:
[1] The repository limits that domain objects can only be persisted and retrieved through the aggregation root to ensure that all changes and invariance are handled by the aggregation.
[2] Warehouse realizes domain level persistence independence by hiding the underlying technology of aggregation persistence and retrieval.
[3] Warehousing defines a boundary between data model and domain model.

16. Data simulation tools
Resolution:
[1]mock.js
[2]easy-mock.js
[3]mock server worker

17. Pass parameters during Autofac parsing
Parsing: when parsing a service, you need to pass parameters. You can use the Resolve() method to accept variable length parameters.
[1] Available parameter types
NamedParameter - matches the target parameter by name
TypedParameter - match the target parameter by type [need to match specific type]
ResolvedParameter - flexible parameter matching
[2] Parameters of reflection component

var reader = scope.Resolve<ConfigReader>(new NamedParameter("configSectionName", "sectionName"));

[3] Parameters of lambda expression component
[4] Do not explicitly call Resolve to pass parameters

18.Autofac life cycle - temporary
Parsing: each time a request is made to the service container, a new instance will be created, which is equivalent to a new instance every time. Registration method: use the InstancePerDependency() method to label. If not, this is also the default option. The following two registration methods are equivalent:

// If not specified, the default is instantaneous
builder.RegisterType<TransientService>().As<ITransientService>();
// Specifies that its lifecycle domain is transient
builder.RegisterType<TransientService>().As<ITransientService>().InstancePerDependency();

The comparison is the same as the life cycle AddTransient in the default container. It is also a new instance every time. Register with AddTransient():

services.AddTransient<ITransientService, TransientService>()

19.Autofac lifecycle - within scope
Parsing: an instance is created at each Web request, and the life cycle spans the entire request. That is, it is singleton within the scope of each life cycle. Registration method: use InstancePerLifetimeScope() method to identify:

builder.RegisterType<ScopedService>().As<IScopedService>().InstancePerLifetimeScope();

The comparison is the same as the life cycle AddScoped in the default container The container of NETCore framework takes over the creation of request and lifecycle scope, and the same effect can be achieved by using Scoped(). Register with AddScoped():

services.AddScoped<IScopedService, ScopedService>();

20.Autofac lifecycle - match within scope
Resolution: that is, one instance of each matched lifecycle scope. This type is actually one of the above scopes, which can have more precise control over the sharing of instances. By allowing the domain to be labeled, it is singleton as long as it is within this specific label domain.
[1] Registration uses the InstancePerMatchingLifetimeScope(stringtagName) method to register

var builder = new ContainerBuilder();
builder.RegisterType<Worker>().InstancePerMatchingLifetimeScope("myrequest");

When a lifecycle begins, the tag value provided is associated with it.
[2] Examples

// myrequest tag subdomain 1
using(var scope1 = container.BeginLifetimeScope("myrequest"))
{
  for(var i = 0; i < 100; i++)
  {
    var w1 = scope1.Resolve<Worker>();
    using(var scope2 = scope1.BeginLifetimeScope())
    {
      var w2 = scope2.Resolve<Worker>();
      // Parsed twice, but both times are the same instance (w1 and w2 point to the same memory block I)
    }
  }
}

// myrequest tag subdomain 2
using(var scope3 = container.BeginLifetimeScope("myrequest"))
{
  for(var i = 0; i < 100; i++)
  {
   // The label has been successfully resolved in the domain, so it can be registered
    var w3 = scope3.Resolve<Worker>();
    using(var scope4 = scope3.BeginLifetimeScope())
    {
      var w4 = scope4.Resolve<Worker>();
       // Because it is not the same subdomain as the above, the resolved instances w3 and w4 are the same instance, but not the same instance as the previous w1 and w2 
    }
  }
}

// Unlabeled subdomain III
using(var noTagScope = container.BeginLifetimeScope())
{
  // If you try to resolve a component with each matching lifecycle scope from a lifecycle whose name does not match, you will get an exception
  var fail = noTagScope.Resolve<Worker>();
}

If you try to resolve a component from a lifecycle whose name does not match, each component that matches the lifecycle scope will get an exception.

21.Autofac lifecycle - Global singleton
Resolution: that is, there is only one instance globally, that is, each subsequent request uses the same instance. Registration method: use SingleInstance() method to identify:

builder.RegisterType<SingletonService>().As<ISingletonService>().SingleInstance()

The comparison is the same as the life cycle AddSingleton in the default container. Use AddSingleton(); Registration:

services.AddSingleton<ISingletonService, SingletonService>();

There are other life cycle additions:
[1] Each request has an instance [Instance Per Request]: in fact, it is a kind of single instance within the matching scope
[2] One Instance Per Owned at a time
[3] Thread Scope

22. Introduction to automapper
Parsing: AutoMapper is an object to object mapping tool. Body is not a business object, it is designed according to UI requirements. In short, Model is business oriented. We define Model through business. DTO is UI oriented and defined by UI requirements. Through DTO, we realize the decoupling between the presentation layer and the Model layer, and the presentation layer does not refer to the Model. If our Model changes during the development process, but the interface does not change, we only need to change the Model without changing the presentation layer.

23.Profile usage
Resolution:
[1]Profile provides a named mapping class, and all subclasses inherited from profile class are a mapping collection.
[2]CreateMap creates a mapping rule.
[3]BeforeMap: method executed before mapping.
[4]AfterMap: conversely, the method executed after mapping.
[5] Automatic flattening mapping: AutoMapper will split the attributes in the class or match the methods starting with Get.
[6]ForMember: Specifies the mapping field.

24. Create UserProfile and inherit Profile class
Resolution:

public class UserProfile : Profile
{
    //Add entity mapping relationship
    public UserProfile()
    {
        // UserInfoEntity to UserInfoDto
        CreateMap<UserInfo, UserInfoDTO>()
        .BeforeMap((source, dto) =>
        {
            //It can accurately control the output data format
            //dto.CreateTime = Convert.ToDateTime(source.CreateTime).ToString("yyyy-MM-dd");
            if (string.IsNullOrEmpty(source.GetCreateTime))
            {
                source.GetCreateTime = Convert.ToDateTime(source.GetCreateTime).ToString("yyyy-MM-dd");
            }
            //dto.Role = "admin";
        })
            //Specify the mapping field. Set userinfo Getcreatetime maps to userinfodto TestTime
            .ForMember(dto => dto.TestTime, opt => opt.MapFrom(info => info.GetCreateTime))
            .ForMember(dto => dto.Role, opt => opt.Ignore())
            .ForMember(dto => dto.CreateTime, opt => opt.Ignore());
        CreateMap<StudentInfo, UserInfoDTO>();
    }
}

25. Inject impapper into the controller
Resolution:

private readonly IMapper _mapper;
public ValuesController(IMapper mapper)
{
    _mapper = mapper;
}

reference:
[1]oidc-client: https://github.com/IdentityModel/oidc-client-js
[2]IdentityServer4 Chinese document and practice: https://www.cnblogs.com/stulzq/p/8119928.html
[3] What does identityserver4 know: https://www.cnblogs.com/sheng-jie/p/9430920.html
[4]IDS4 third party quick start and examples: https://www.cnblogs.com/stulzq/p/8120570.html
[5]IdentityServer4 Chinese document: https://gitee.com/github_mirrors/identityserver4_doc.zh-cn/tree/master

Keywords: C# abp

Added by wmbetts on Mon, 14 Feb 2022 12:51:40 +0200