net6中的一些常用组件和使用记录,不断更新…

0. How to use iConfiguration, Environment

Use it directly in the host after Builder.

builder.Configuration;
builder.Environment

How to use swagger

The .NET 6 comes with the template to add swagger to it, you can use it directly.

builder.Services.AddSwaggerGen();

if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

2. How to add EFCORE to .NET 6

Add it according to the EFCORE usual use method, the Entity and DBCONTEXT of the applaud form, add it in the program file

builder.Services.AddDbContext<Service.DataContext>(opt => {
    opt.UseSqlServer(builder.Configuration.GetConnectionString("Default"));
});

You can inject it in other places to use Datacontext

Using the SQLite database, you need to reference Microsoft.EntityFrameworkCore.SQLITE,
and changed when adding services

opt.UseSqlite(builder.Configuration.GetConnectionString("Default"));

Package Management Console Database Structure Generation Method:
Create migration using add-migration
Update data structure using Update-Database

3. How to inject a service

builder.Services.AddScoped<UserIdentyService>();

4. How to define global useing references

In the root directory, create a CS file, such as Globalusing.cs, add your global reference in it, and normal reference is different, add global in front of using

global using Service;
global using Entity;
global using Entity.Dto;

5. How to use Autofac

Add NuGet reference

Autofac.Extensions.DependencyInjection

Program.cs file Add autofac use and injection configuration

builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory());
builder.Host.ConfigureContainer<ContainerBuilder>(builder =>
 {
     Assembly assembly = Assembly.Load("Service.dll");
     builder.RegisterAssemblyTypes(assembly)
            //.AsimplementInterfaces() // no interface injection method
            .InstancePerDependency();
 });

The function can be constructed to be used in this time.

6. How to use Log4Net

Add a reference

Microsoft.Extensions.Logging.Log4Net.AspNetCore

New Profile Log4Net.config;
Add Service Configuration

// Inject log4net
builder.Services.AddLogging(cfg =>
{
         // The default configuration file path is in the root directory, and the file name is log4net.config
    //cfg.AddLog4Net();
         // If the file path or name changes, you need to reset its path or name
         / / For example, create a folder called config in the root of the project, move the log4net.config file into it and renamed log4net.config
         // The following code needs to be configured.
    cfg.AddLog4Net(new Log4NetProviderOptions()
    {
        Log4NetConfigFileName = "config/log4net.config",
        Watch = true
    });
});

You can define it in a required place

_logger = LogManager.GetLogger(typeof(UserController));

7. How to use global abnormal filters

First create a GlobalExceptionFilter global abnormal filter, inherited to exceptionFilter, used to receive an exception thrown

public class GlobalExceptionFilter : IExceptionFilter
{
    readonly IWebHostEnvironment hostEnvironment;
    readonly ILog logger;
    public GlobalExceptionFilter(IWebHostEnvironment _hostEnvironment)
    {
        this.hostEnvironment = _hostEnvironment;
        this.logger = LogManager.GetLogger(typeof(GlobalExceptionFilter));
    }
    public void OnException(ExceptionContext context)
    {
                 if (! context.exceptionhand // If the exception is not processed
        {
            var result = new ApiResult
            {
                Code = 500,
                IsSuccess = false,
                                 Message = "Unreated exception in the server"
            };

            if (hostEnvironment.IsDevelopment())
            {
                result.Message += "," + context.Exception.Message;
                result.Data = context.Exception.StackTrace;
            }

            logger.Error(result);

            context.Result = new JsonResult(result);
                         Context.exceptionHandled = true; // Abnormal processed
        }
    }
}

Then add global abnormal filter in Service

builder.Services.AddControllers(option =>
    {
        option.Filters.Add<GlobalExceptionFilter>();
    }
);

Add a controller method to complete the test

[HttpGet("exception")]
public ApiResult ExceptionAction()
{
    throw new NotImplementedException();
}

8. How to use Redis to cache

Use stackexchange.redis as the cache component (other components similar to usage). Nuget installation stackedxchange.redis.extensions.core
First, create a class REDISCLIENT for managing the connection and operation of REDIS, and then build a RedisClientFactory class to create Redis connection;

public class RedisClient{...}
public class RedisClientFactory{...}

Adding Redis in Appsettings.json

"RedisConfig": {
    "Redis_Default": {
      "Connection": "127.0.0.1:6379",
      "InstanceName": "Redis1:"
    },
    "Redis_6": {
      "Connection": "127.0.0.1:6379",
      "DefaultDatabase": 6,
      "InstanceName": "Redis2:"
    }
  }

Add a REDIS client in Service

// Add Redis's use
builder.Services.AddSingleton<RedisClient>(_=> RedisClientFactory.GetInstance(builder.Configuration));

After a single operation, you can quote the place where you want to use Redis.

RedisClient redisClient
...
this.redisDb = redisClient.GetDatabase("Redis_Default");
redisDb.StringSet("clientId", "clientId", TimeSpan.FromSeconds(10));

To use Redis to make a distributed cache, first reference Microsoft.extensions.Caching.stackexchangeRedis

// Add the Redis distributed cache service to the service
builder.Services.AddStackExchangeRedisCache(options =>
    {
                 // Configure configuration.getConnectionstring ("redisconnectionstring") to connect Redis.
        options.Configuration = "Redis_6";// Configuration.GetConnectionString("RedisConnectionString");
                 // redis instance name RedisDistributedcache
        options.InstanceName = "RedisDistributedCache";
    });

Quoted from "Distributed Redis Cache"

9 How to add a timed task component

Use the Hangfire timing task components, light, sustainable, and panels.
After reference to haangfire, you can add time to update the task.

// Enable Hangfire service.
builder.Services.AddHangfire(x => x.UseStorage(new MemoryStorage()));
builder.Services.AddHangfireServer();

...

 // Enable Hangfire Panel
app.UseHangfireDashboard();
 / / Open a timing task
RecurringJob.AddOrUpdate("test",() => Console.WriteLine("Recurring!"), Cron.Minutely());

Visithttps://localhost:7219/hangfire You can see the task panel

10. How to use the business lock lock or pay the operation

First of all, do this, you need to build a lock, this lock has a lock identifier Key, you can determine if the key corresponding to the key is exist according to this key.
When a user pays or subtracts the stock, you can follow this key to first lock, and then there is a user to take the same operation when it takes other channels. It can be determined whether the operation can be continued according to whether it is locked.

For example, a payment order, you can operate on your phone, or you can do it on your computer. This time you can lock the payment interface, as long as one payment process exists, and there is no timeout, then you cannot operate in other channels.
We have used Redis, and use Redis to simulate this operation, specifically see the code:

/// <summary>
         /// Test business lock
    /// </summary>
    /// <returns></returns>
    [HttpGet("lockhandle")]
    public async Task<ApiResult> LockHandle(int userId)
    {
        var key = "user";
        var token = $"ID:{userId}";
        try
        {
            if (redisDb.LockTake(key, token, TimeSpan.FromSeconds(50)))
            {
                await Task.Delay(30 * 1000);
                                 Return AWAIT TASK.FROMROMROMROMRESULT ($ "ID: {UserID} Getting to lock, operate normally, connect.httpContext.connection.id}");
            }
            else
            {
                                 Return Await Task.FromResult (ApireSult.Fail ($ "is a lock, connect: {Request.httpContext.connection.id});
            }
        }
        catch (Exception)
        {
            throw;
        }
        finally
        {
            redisDb.LockRelease(key, token);
        }
    }

11. How to configure cross-domain

The global cross-domain is mainly recorded here, which does not include the specified API cross-domain. First add a configuration "CORS": "HTTP: 127.0.0.1: 5001", configure the URL across the domain, or you can use the default cross-domain configuration.
Host Configure the following services, on demand:

builder.Services.AddCors(delegate (CorsOptions options)
{
    options.AddPolicy("CorsPolicy", delegate (CorsPolicyBuilder corsBuilder)
    {
                 / / Specify URL cross-domain
        corsBuilder.WithOrigins(builder.Configuration.GetValue<string>("Cors").Split(','));
                 // Default cross-domain
        corsBuilder.SetIsOriginAllowed((string _) => true).AllowAnyMethod().AllowAnyHeader()
            .AllowCredentials();
    });
});

12. How to use newtonsoftjson

.NET6 default series of train is built-in System.Text.json, if there are many unfamiliar places, it must be replaced back to NewtonSoftjson, need NuGet to reference Microsoft.aspnetCore.MVC.NEWTONSOFTJSON to configure usage,
Common configuration includes date format, case regular, loop reference configuration. . . Wait, below is a configuration

builder.Services.AddControllers(option =>
    {
        option.Filters.Add<GlobalExceptionFilter>();
    }
).AddNewtonsoftJson(options =>
{
         options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver (); key is // hump style for serializing
    options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
    options.SerializerSettings.DateFormatString = "yyyy-MM-dd HH:mm:ss";
         Options.serializersettings.referenceLoopHandling = ReferenceLoopHandling.Ignore; / / ignore the loop reference
});  


 
 

13. 使用kafka

Code instance (point-to-point mode)

copy code
   public interface IKafkaService
    {
        /// <summary>
        ///  A message to the designated topic
        /// </summary>
        /// <typeparam name="TMessage"></typeparam>
        /// <param name="topicName"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        Task PublishAsync<TMessage>(string host,string topicName, TMessage message) where TMessage : class;


        /// <summary>
        ///  Subscribe from the specified topic
        /// </summary>
        /// <typeparam name="TMessage"></typeparam>
        /// <param name="topics"></param>
        /// <param name="messageFunc"></param>
        /// <param name="cancellationToken"></param>
        /// <returns></returns>
        Task SubscribeAsync<TMessage>(IEnumerable<string> topics,Action<TMessage> messageFunc,CancellationToken cancellationToken) where TMessage : class;
    }
copy code

// Package

copy code
public class KafkaService : IKafkaService
    {
        public readonly string host = "120.79.77.91:9092";
        public async Task PublishAsync<TMessage>(string host, string topicName, TMessage message) where TMessage : class
        {
            var config = new ProducerConfig
            {
                BootstrapServers = host
            };
            using var producer = new ProducerBuilder<string, string>(config).Build();
            var data = new Message<string, string> { Key = Guid.NewGuid().ToString(), Value = Newtonsoft.Json.JsonConvert.SerializeObject(message) };
            await producer.ProduceAsync(topicName, data);
        }

        public async Task SubscribeAsync<TMessage>(IEnumerable<string> topics, Action<TMessage> messageFunc, CancellationToken cancellationToken) where TMessage : class
        {
            var config = new ConsumerConfig
            {
                BootstrapServers = host,
                GroupId = "consumer",
                EnableAutoCommit = false,
                StatisticsIntervalMs = 5000,
                SessionTimeoutMs = 6000,
                AutoOffsetReset = AutoOffsetReset.Earliest,
                EnablePartitionEof = true
            };
            //const int commitPeriod = 5;
            using var consumer = new ConsumerBuilder<Ignore, string>(config)
             .SetErrorHandler((_, e) =>
             {
                 Console.WriteLine($"Error: {e.Reason}");
             })
             .SetStatisticsHandler((_, json) =>
             {
                 Console.WriteLine($"  - {datetime.now:yyyy-mm-dd hh: mm: ss}> message listening..");
             })
             .SetPartitionsAssignedHandler((c, partitions) =>
             {
                 string partitionsStr = string.Join(", ", partitions);
                 Console.WriteLine($"  - Allocated Kafka partition: {PartitionsStr}");
             })
             .SetPartitionsRevokedHandler((c, partitions) =>
             {
                 string partitionsStr = string.Join(", ", partitions);
                 Console.WriteLine($"  - Recycling Kafka partition: {partitionsstr}");
             })
             .Build();
            consumer.Subscribe(topics);
            try
            {
                while (true)
                {
                    try
                    {
                        var consumeResult = consumer.Consume(cancellationToken);
                        Console.WriteLine($"Consumed message '{consumeResult.Message?.Value}' at: '{consumeResult?.TopicPartitionOffset}'.");
                        if (consumeResult.IsPartitionEOF)
                        {
                            Console.WriteLine($"  - {datetime.now:yyyy-mm-dd hh: mm: ss} has been in the end: {consumeResult.topic}, partition {consumeResult.partition}, offset {consumeresult.offset}.");
                            continue;
                        }
                        TMessage messageResult = null;
                        try
                        {
                            messageResult = JsonConvert.DeserializeObject<TMessage>(consumeResult.Message.Value);
                        }
                        catch (Exception ex)
                        {
                            var errorMessage = $"  - {datetime.now:Yyyy-mm-dd hh: mm: ss} [Exception message reverse sequence failed, value: {consumeResult.Message.Value}]: {EX.STACKTRACE? .Tostring ()}";
                            Console.WriteLine(errorMessage);
                            messageResult = null;
                        }
                        if (messageResult != null/* && consumeResult.Offset % commitPeriod == 0*/)
                        {
                            messageFunc(messageResult);
                            try
                            {
                                consumer.Commit(consumeResult);
                            }
                            catch (KafkaException e)
                            {
                                Console.WriteLine(e.Message);
                            }
                        }
                    }
                    catch (ConsumeException e)
                    {
                        Console.WriteLine($"Consume error: {e.Error.Reason}");
                    }
                }
            }
            catch (OperationCanceledException)
            {
                Console.WriteLine("Closing consumer.");
                consumer.Close();
            }
            await Task.CompletedTask;
        }
    }
copy code

// producers

copy code
string[] configList = { "xxx.xx.xx.xx:9092", "sun" };

//Call the interface definition method
KafkaService kafkaService = new KafkaService();
while (true)
{
    var data = Console.ReadLine();
    await kafkaService.PublishAsync<string>(configList.First(), configList.Last(), data);
}
copy code

//consumer

copy code
KafkaService kafkaService = new KafkaService();
await kafkaService.SubscribeAsync<string>(new string[] { "sun" }, like, new CancellationToken());

static void like(string like)
{
    Console.WriteLine($"This is acceptable: {like}");
}
copy code

Code instance (Publish / subscription mode)

posted @ 2022-01-28 10:08  清风拂人  阅读(297)  评论(0编辑  收藏  举报