net core 记录
class Program { static void Main(string[] args) { //1 nuget 包Microsoft.Extensions.DependencyInjection //2 建立 ServiceColl ection //3 BuildServiceProvider ServiceCollection services = new ServiceCollection(); // services.AddSingleton<IService, ConcreteService>();
services.AddSingleton(typeof(IService), new ConcreteService());//这种可以实现带参数的构造函数 using (var serviceBuild = services.BuildServiceProvider()) { var conCreteService = serviceBuild.GetService<IService>();//找不到 null
var conCreteService = serviceBuild.GetRequiredService<IService>();// 抛异常 conCreteService.Show(); } Console.WriteLine("Hello World!"); } } public interface IService { void Show(); } public class ConcreteService : IService { public void Show() { Console.WriteLine( "你哈"); } }
using Microsoft.Extensions.DependencyInjection;
在扩展包内的
----------------------------------------------------------------------------------------------------------------------
多线程:
异步不代表多线程。
闭包:
static async Task Main(string[] args) { List tasks = new List(); for (int i = 0; i < 5; i++) { tasks.Add( Task.Run(() => { Output(i); }) ); } //等待所有线程结束 Task.WaitAll(tasks.ToArray()); } //结果都是5
static async Task Main(string[] args) { List tasks = new List(); for (int i = 0; i < 5; i++) { int temp = i; tasks.Add( Task.Run(() => { Output(temp); }) ); } Task.WaitAll(tasks.ToArray()); } //这样结果是0.1.2.3.4
----------------------------------------------------------------------------------------------------------------------
生命周期,
transient每次都不一样
Singleton单列,以最后面的为准,最后面谁修改了属性,前面的实例也会是这个属性值。
scoped:范围,一个using是一个范围。
如何选择:
如果类无状态,没有属性,建议是singleTon;
如果类有状态,且有scope控制,建议是scope.因为通常这个scope控制下的代码都是运行在一个线程内的没有发生修改的问题。
在使用transient的要谨慎。
----------------------------------------------------------------------------------------------------------------------
三:配置选项:
class Program { static void Main(string[] args) { Console.WriteLine("Hello World!"); //1 添加包 Microsoft.Extensions.Configuration // Microsoft.Extensions.Configuration.Binder // Microsoft.Extensions.Configuration.Json //2 构建ConfigurationBuilder //3 使用IConfigurationRoot读取文件内容 ConfigurationBuilder builder = new ConfigurationBuilder(); builder.AddJsonFile("Appsetting.json", optional: false, reloadOnChange: true); IConfigurationRoot root = builder.Build(); Console.WriteLine(root["name"]); Console.WriteLine(root.GetSection("Info:Phone").Value); Console.ReadLine(); } }
--options
//关于option 安装包Microsoft.Extensions.options IServiceCollection serviceCollection = new ServiceCollection(); serviceCollection.AddScoped<HomeController>(); ConfigurationBuilder build = new ConfigurationBuilder(); build.AddJsonFile("Appsetting.json", optional: false, reloadOnChange: true); var root = build.Build(); var config = root.Get<Config>();// .Bind<Config>(); /// 注意这里 这里是把json全部文件都取出来了。也可以取部分内容,绑定到自己映射的类中。 serviceCollection.AddOptions().Configure<Config>(c => root.Bind(c)); using (var sp = serviceCollection.BuildServiceProvider()) { var home = sp.GetRequiredService<HomeController>(); home.Test(); }
--衍射类
public class Config { public string name { get; set; } public Info Info { get; set; } } public class Info { public String Address { get; set; } public String Phone { get; set; } }
--json文件:
{ "name": "YDB", "Info": {"Address": "上海","Phone": "12324435"} }
--具体实现类:
class HomeController { private readonly IOptionsSnapshot<Config> _config; //这里表示在同一个scope内读取的内容不会随着json文件内容改变而改变。 public HomeController(IOptionsSnapshot<Config> config) { this._config = config;//这样注入不会读取文件内容。、 } public void Test() { Console.WriteLine(_config.Value.name); Console.WriteLine("---------------"); Console.WriteLine(_config.Value.name); } }
--自定义一个读取webcofig的sourceprovider
1 YDFileConfigProvider
class YDFileConfigProvider : FileConfigurationProvider { /// <summary> /// Initializes a new instance with the specified source. /// </summary> /// <param name="source">The source settings.</param> public YDFileConfigProvider(YDConfigurationSource source) :base(source) { } private Dictionary<string, string> Data = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); public override void Load(Stream stream) { XmlDocument xmldoc = new XmlDocument(); xmldoc.Load(stream); var nodes = xmldoc.SelectNodes("/configuration/connectionStrings/add"); foreach (var nodeConnStr in nodes.Cast<XmlNode>()) { string name = nodeConnStr.Attributes["name"].Value; string connectionString = nodeConnStr.Attributes["connectionString"].Value; Data[$"{name}:connectionString"] = connectionString; var provideNameProp = nodeConnStr.Attributes["provideName"]; if (provideNameProp != null) { string providerName = provideNameProp.Value; Data[$"{name}:provideName"] = providerName; } } base.Data = Data; } }
2.YDConfigurationSource和扩展方法
public class YDConfigurationSource : FileConfigurationSource { public override IConfigurationProvider Build(IConfigurationBuilder builder) { EnsureDefaults(builder);// 处理path默认值问题 return new YDFileConfigProvider(this); } } public static class YDConfigurationSourceExtensions { public static void AddConfig(this ConfigurationBuilder configurationBuilder, string path) { configurationBuilder.Add(new YDConfigurationSource() { Path = path }); } }
3具体使用
ConfigurationBuilder builder = new ConfigurationBuilder(); //builder.Add(new YDConfigurationSource() { Path = "Web.config" }); builder.AddConfig( "Web.config" ); IConfigurationRoot root = builder.Build(); Console.WriteLine(root["ss:connectionString"]);
--其他机密文件,不会上传到github上
1.添加:Microsoft.Extensions.Configuration.UserSecrets,或者项目右击添加机密文件。
具体使用:数据如下
//机密数据 ConfigurationBuilder builder = new ConfigurationBuilder(); builder.AddUserSecrets<Program>(); IConfigurationRoot root = builder.Build(); Console.WriteLine(root["name"]);
-------------------------------------------------------------------------------------------------------------------------
日志:
1.写到控制台:
//----------------------- // 1按照日期区分 // 2限制日志总个数 // 3日志太大 //日志 // 1.安装 Microsoft.Extensions.Logging,Microsoft.Extensions.Logging.Console // 2.依赖注入 // 3.具体使用 ServiceCollection service = new ServiceCollection(); service.AddLogging(config => config.AddConsole().SetMinimumLevel(LogLevel.Trace) ) ; service.AddScoped<TestContoller>(); using (var sp = service.BuildServiceProvider()) { var test = sp.GetService<TestContoller>(); test.Test(); } //-------------------------
2.nlog:
//-----------------------------nlog---- // 1安装包:Install-Package NLog -Version 5.0.0-rc2 // Install-Package NLog.Extensions.Logging -Version 5.0.0-rc2 ServiceCollection service = new ServiceCollection(); service.AddLogging(configure => { configure.AddConsole(); configure.AddNLog(); configure.SetMinimumLevel(LogLevel.Trace); }); service.AddScoped<TestContoller>(); using (var sp = service.BuildServiceProvider()) { var test = sp.GetService<TestContoller>(); test.Test(); } //-------------------------------------
配置文件:nlog.config
<?xml version="1.0" encoding="utf-8" ?> <nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <targets> <target name="logfile" xsi:type="File" fileName="file.txt" /> <target name="logconsole" xsi:type="Console" /> </targets> <rules> <logger name="*" minlevel="Trace" writeTo="logconsole" /> <logger name="*" minlevel="Trace" writeTo="logfile" /> </rules> </nlog>
SeriLog:结构化输出
ServiceCollection service = new ServiceCollection(); service.AddLogging(configure => { configure.AddSerilog(); Log.Logger = new LoggerConfiguration() .WriteTo.Console(new JsonFormatter()) .WriteTo.File("log-.txt",rollingInterval: RollingInterval.Day) .CreateLogger(); });
--这里有案例:https://www.cnblogs.com/zcqiand/p/14257598.html
----------------------------------------------------------------------------------------------------------------------
EF Core:
class MyDbContext : DbContext { // 使用EF Core // 1.安装Microsoft.EntityFrameworkCore,Microsoft.EntityFrameworkCore.Tools, // Microsoft.EntityFrameworkCore.SqlServer // 2 public DbSet<Book> Books {get;set;} public DbSet<User> Users {get;set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { base.OnConfiguring(optionsBuilder); optionsBuilder.UseSqlServer(connectionString: "Server=.;DataBase=YbdProject;User ID=sa;Pwd=sa"); } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); } }
关于guid不要设置成聚集索引,聚集索引:按照顺序排列,很容易找到周围的值。
------------------------------------------------ 表达式树----------------------------------------------------------------------
表达式树:Expression Tree,树形数据结构表示代码。以便可以在运行时访问逻辑运算的机构
2.Expression<TDelegate>类型
3.从lambda表达式来生成表达式树
Expression<Func<Book,bool>> el = b=>b.Price>5;
4.表达式不能带方法体
// 构建表达式树 ParameterExpression paramExpB = Expression.Parameter(typeof(Book), "b"); ConstantExpression consExpr5 = Expression.Constant(5.0, typeof(double)); MemberExpression memExprPrice = Expression.MakeMemberAccess(paramExpB, typeof(Book).GetProperty("Price")); BinaryExpression binaryThan = Expression.GreaterThan(memExprPrice, consExpr5); Expression<Func<Book, bool>> exprRoot = Expression.Lambda<Func<Book, bool>>(binaryThan, paramExpB); Console.WriteLine(books.Where(exprRoot.Compile()).First().Title);
或者:
var b = Parameter( typeof(Book), "b" ); var const5 = Expression.Constant(5.0, typeof(double)); var exprPrice = MakeMemberAccess( b, typeof(Book).GetProperty("Price") ); var exprCompare = Expression.GreaterThan(exprPrice, const5); //主要这里要把参数放进去。。。 var expressRoot = Lambda<Func<Book,bool>>( body: exprCompare, parameters: b ); Console.WriteLine(books.Where(expressRoot.Compile()).First().Title);
------------------------------------------------ 表达式树结束------------------------------------------------------------------
------------------------------------------------ WebApi-----------------------------------------------------------------
改变代码不暂停
1.启动不调试
2. Hotr Reload
Rest:
1.面向资源
2.使用动词
3.幂等,执行对此和一次是一样的
4.get的响应可以被缓存
5.服务端要通过状态码来返回结果
------------------------------------------------ WebApi结束-----------------------------------------------------------------
------------------------------------------------ 登录认证-----------------------------------------------------------------
Cookie 的授权认证是一种兼容性较高的一种方式,并且前端请求中无需额外配置,也会在 Header 中自动带上程序生成针对用户唯一标识的加密Cookie
下面是基于 .Net Core 的实现方式
第一步,在 Startup.cs 添加中间件
ConfigureServices 中
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme). AddCookie(option => { option.LoginPath = new PathString("/api/login");//未登录时,进行跳转的url option.AccessDeniedPath = new PathString("/api/login");//身份认证不通过时,进行跳转的url option.ExpireTimeSpan = TimeSpan.FromDays(1);//指定Cookie的过期时间 option.SlidingExpiration = true;//当Cookie过期时间已达一半时,是否重置为ExpireTimeSpan option.Cookie.Name = "AuthCookie";//Cookie的名称 } );
Configure 中
app.UseAuthentication();//必须在 app.UseMvc(); 前面 app.UseMvc();
第二步,登陆
[HttpGet("Login")] public async Task Login(string userName,string pwd) { //Todo //校验账号密码是否正确 //用户身份 var identity = new ClaimsIdentity(CookieAuthenticationDefaults.AuthenticationScheme); identity.AddClaim(new Claim(ClaimTypes.Name, userName)); //取值 User.Identity.Name identity.AddClaim(new Claim(ClaimTypes.UserData, "用户账号其他数据")); // User.Claims.Select(t => new { t.Type, t.Value }).ToList(); identity.AddClaim(new Claim(ClaimTypes.Role, "admin"));// 用于区分账号权限,如[Authorize(Roles = "admin")] //用户登录成功后颁发一个证书(加密的用户凭证),用来标识用户的身份,该凭证(cookie)将会写入到客户端浏览器 await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(identity), new AuthenticationProperties { IsPersistent = true, //true:保持登陆不过期 false:关闭浏览器就过期 ExpiresUtc = DateTime.UtcNow.AddDays(1),//过期时间 AllowRefresh = true }); return "succeed"; }
第三步,API的授权控制
如果此时未登录,访问该 api 的话会跳转到 LoginPath 指定的url
如果此时已登录,但 Roles 不为 “admin” 的情况下,访问该 api 的话会跳转到 AccessDeniedPath 指定的url
如果是通过异步请求,则会返回 http 401 Unauthorized 的错误
需要注意的是,跨域的异步请求是直接返回 http 302 重定向的,这个与 CookieAuthenticationEvents 类的处理方式有关,代码中有关于是否是 Ajax 请求的判断,如果请求的 QueryString 或者 Header 中包含 X-Requested-With 并且值为 XMLHttpRequest 的话, 则会被判断为 AjaxRequest , 将不会返回重定向结果
所以,解决办法有两种
一种是在请求的头部 headers 加上 ‘X-Requested-With’:”XMLHttpRequest” 即可
[HttpGet("AdminWelcome")] [Authorize(Roles = "admin")] public string AdminWelcome() { var user = HttpContext.User.Identity.Name; return $"welcome "{user}; }
另外一种是在 AddAuthentication 中针对这种会自动跳转的情况进行事件重写,直接返回 401
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme). AddCookie(option => { option.LoginPath = new PathString("/home/admin");//登陆地址 option.AccessDeniedPath = new PathString("/home/admin");//授权不通过跳转地址 option.ExpireTimeSpan = TimeSpan.FromDays(1);//指定Cookie的过期时间 option.SlidingExpiration = true;//当Cookie过期时间已达一半时,是否重置为ExpireTimeSpan option.Cookie.Name = "AuthCookie";//cookie名称 option.Events.OnRedirectToAccessDenied = option.Events.OnRedirectToLogin = c => { c.Response.StatusCode = StatusCodes.Status401Unauthorized; return Task.FromResult<object>(null); }; });
------------------------------------------------ 登录认证结束------------------------------------------------------------
--------------------------------------------------中间件---------------------------------------------------------------------
--------------------------------------------------中间件结束-----------------------------------------------------------------
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报