.Net Core全面解析_asp.net Core框架全面解析
目录
1.1 Asp.netCore之控制台启动项目
2.Asp.Net Core之核心套路组件形式组装整个项目 不再是.netfrom全家桶形式
3.Asp.Net Core 之Log4Net日志组件扩展,cmd启动程序
5.Asp.Net Core 之Startup.Configure Use(组件化解析)
6.Asp.Net Core 之依赖注入+asp.net core IOC容器与autofac容器解析 IOC容器的生命周期 以及Ui层实现依赖注入
7.Asp.Net Core 之AOP思想_通过MVC自带的Filter+Attribute实现自定义异常捕获 实现 方法级别 控制器级别 全局级别捕捉异常
10.Asp.Net Core 之用户登录退出,使用UseAuthentication自带过滤器进行鉴权
11.Asp.Net Core 之网站访问前给http头部添加信息
.netcore能跨平台的原因:
asp.netcore(内置Kestrel=主机,) 只要安装core sdk环境就有Kestrel sdk环境在哪里 就有Kestrel 就可以执行core程序 这也是能够跨平台的原因
.Net core .Net 5 源码解读 执行的源码解读
//1.程序启动的时候,得到一个最小的IHostBuilder(主机),包含的是最基本的配置,专门用来生成最基础的Host; //2.通过【 webBuilder.UseStartup<Startup>()】里面的不同的扩展,扩展IHostBuilder,每一层扩展都是在之前的基础上,进一步封装相关配置(套娃模式); //3. 就可以通过扩展把我们自己的写的配置给替换到默认配置上去;包括指定请求来了以后的处理过程; //4.Build方法执行后,所部分配置都给执行,得到一个WebHost;把WebHost所需要的 包含基础的服务,IOC容器; //5.用WebHost.Run();启动起来,把Kestrel启动起来,绑定端口,把服务启动起来;应装配了所有的环节! //Http请求进来—Kestrel监听---启动一个线程--包装context上下文—调用application /// <summary> /// 其实我们所谓的aspnetcore是一个控制台; /// </summary> public class Program { /// <summary> /// 程序的入口 /// </summary> /// <param name="args"></param> public static void Main(string[] args) { //1.程序启动--CreateHostBuilder(创建一个主机Kestral) //2.调用build 方法的到一个主机 //3.主机开始运行 var builder = CreateHostBuilder(args); //1.创建默认主机的建造者 IHost host = builder.Build(); //2.build一下 host.Run();//3.主机开始运行 //什么是主机:例如:IIS //主机运行是为了执行我们自己定义的代码;代码在哪儿?其实集成到主机中去了; } /// <summary> /// 这个类其实就是相当于程序运行前需要的一些基础的初始化配置,或者自己在里面增加一些配置 /// /// </summary> /// <param name="args"></param> /// <returns></returns> public static IHostBuilder CreateHostBuilder(string[] args) { //var host = Host.CreateDefaultBuilder(args); //Microsoft.Extensions.Hosting.HostBuilder IHostBuilder build = Host.CreateDefaultBuilder(args); //创建默认主机的建造者; var builder2 = build.ConfigureLogging(loggbuild => { loggbuild = loggbuild.AddLog4Net("CfgFile/log4net.Config"); }); ///配置logging(指定使用Log4net) var builder3 = builder2.ConfigureWebHostDefaults(webBuilder => //配置一个默认的Web主机 { webBuilder.UseStartup<Startup>(); //如何配置? 配置全交给Startup来完成; }).UseServiceProviderFactory(new AutofacServiceProviderFactory()); //build.ConfigureServices() return build; } }
发送一个http请求请求到asp.net Core的经历
1.浏览器发送http请求
2.DNS服务器解析域名确定IP+Port(端口号-确定是那个程序) IP+port确定具体服务器和具体程序程序
3.IIS下 core怎么运行的:
1.http请求到IIS (主机,core就是寄宿在上面运行)
2.IIS拿到请求转发给asp.net core module
3.请求再给 Kestrel
4.kestrel的请求最终到代码里面
4.Core程序代码已经得到了http的请求了 响应的过程就是一个http请求处理的管道
5.Core开始响应 (就是一个控制台应用程序)http请求走 Program.cs Main方法,创建一个web主机,执行 Startup.cs(配置管道环节)
7.startp.cs里面的配置先走完,然后http请求根据Configure里面配置的管道环节 最终走到也是Configure里面配置的MVC路由
8.页面请求走完!
startp.cs里面的方法都是在运行时调用的,和静态构造函数一样执行且执行一次
startp.cs>Configure(配置管道环节)>定义的IApplicationBuilder参数类 里面的Build方法就是得到一个Http请求的委托
.use就是把 【按需增加的相关服务】放到一个集合中。 在Build的时候 循环集合把委托遍历出来,层层包装成一个多层嵌套委托:俄罗斯套娃一样
然后HTTP请求开始走这个俄罗斯套娃
这就是 Core的管道模型,和以前的.net fromwork管道模型区别在于
net Core管道模型:一个是根据程序按需增加相关环节,
net fromwork管道模型:一个http请求必须走完固定的19个环节
1.创建Asp.Net Core网站项目是如何从后端传值到前端
base.ViewBag.User1 = "值1"; base.ViewData["User2"] = "值2"; base.TempData["User3"] = "值3"; object name = "值4"; return View(name);
@model System.String @{ ViewData["Title"] = "Index"; } <h1>Index</h1> <h2>@base.ViewBag.User1</h2> <h2>@base.ViewData["User2"]</h2> <h2>@base.TempData["User3"]</h2> <h2>@Model</h2>
1.E:\微服务代码库\click\click\bin\Debug\netcoreapp3.1 在此路径下面启动cmd
2.cmd输入:dotnet Clicent.dll --urls="http://*:801" --ip="127.0.0.1" --port=8012
3.把wwwroot文件夹复制到 bin\Debug\netcoreapp3.1 里面去
2.Asp.Net Core以组件形式组装整个项目 不再是.netfrom全家桶形式
实现套路,1.控制器使用,2.startup.ConfigureServices添加
1.控制器使用
2.startup.ConfigureServices添加 需要在ConfigureServices添加session
第一种方式nuget添加log4net,Microsoft.Extensions.Logging.Log4Net.AspNetCore
Program.cs添加
第二种方式:Starup.cs添加
后台控制器使用
第三步添加配置文件,设置始终复制,
<?xml version="1.0" encoding="utf-8"?> <log4net> <!-- Define some output appenders --> <appender name="rollingAppender" type="log4net.Appender.RollingFileAppender"> <file value="log\log.txt" /> <!--追加日志内容--> <appendToFile value="true" /> <!--防止多线程时不能写Log,官方说线程非安全--> <lockingModel type="log4net.Appender.FileAppender+MinimalLock" /> <!--可以为:Once|Size|Date|Composite--> <!--Composite为Size和Date的组合--> <rollingStyle value="Composite" /> <!--当备份文件时,为文件名加的后缀--> <datePattern value="yyyyMMdd.TXT" /> <!--日志最大个数,都是最新的--> <!--rollingStyle节点为Size时,只能有value个日志--> <!--rollingStyle节点为Composite时,每天有value个日志--> <maxSizeRollBackups value="20" /> <!--可用的单位:KB|MB|GB--> <maximumFileSize value="3MB" /> <!--置为true,当前最新日志文件名永远为file节中的名字--> <staticLogFileName value="true" /> <!--输出级别在INFO和ERROR之间的日志--> <filter type="log4net.Filter.LevelRangeFilter"> <param name="LevelMin" value="ALL" /> <param name="LevelMax" value="FATAL" /> </filter> <layout type="log4net.Layout.PatternLayout"> <conversionPattern value="%date [%thread] %-5level %logger - %message%newline"/> </layout> </appender> <root> <priority value="ALL"/> <level value="ALL"/> <appender-ref ref="rollingAppender" /> </root> </log4net>
第四步:访问程序
cmd启动方式:找到程序bin\debug 输入cmd 打开命令模式:输入 dotnet WebApplication1.dll 运行,浏览器输入 https://localhost:5001/ 直接访问
.netcore和.net5 实际是一个控制台应用程序 。请求管道模型
执行顺序就是:发送http请求>请求被Kestrel解析得到HttpContext->然后被后台代码处理Request>返回Response->经由Kestrel回发到客户端
所谓管道,就是拿着HttpContext,经过多个步骤的加工,生成Response,而这其实就是管道模型请求
所以Startup.Configure就是指定我们的代码如何去处理请求
这个Startup.Configure方法,叫请求级(所有请求生效,且只执行一次其实也就是初始化)----而页面级就是 请求一个页面Home/Index
Startup.cs里面的几个方法都是在运行时调用的和静态构造函数一样,执行且执行一次
5.Startup.Configure方法 Use中间件 源码解析 通过中间件把请求交给MVC
Configure的核心其实就是IApplicationBuilder app这个参数
而里面需要实现的就是build方法:它的注释:构建此应用程序用来处理HTTP请求的委托。
而实现Build方法 就是Use调用RequestDelegate(是一个委托) 接收一个HttpContext,执行相应的操作 所以就让我们在一个http请求进入MVC前随意扩展定义
上面就是build源码解读
下面的user使用之后的执行顺延为什么会这样 由上面这个Build源码解读就可以得知
//终结式-- app.Use(_ => handler);---意味着没有下个步骤 //终结式-- app.Run(c => c.Response.WriteAsync("Hello World!"));
//另外个use 可以不是request delegate app.Use(async (context, next) =>//没有调用 next() 那就是终结点 跟Run一样 { await context.Response.WriteAsync("Hello World Use3 Again Again <br/>"); //await next(); });
//UseWhen可以对HttpContext检测后,增加处理环节;原来的流程还是正常执行的 app.UseWhen(context => { return context.Request.Query.ContainsKey("Name"); }, appBuilder => { appBuilder.Use(async (context, next) => { await context.Response.WriteAsync("Hello World Use3 Again Again Again <br/>"); //await next(); }); });
//根据条件指定中间件 指向终结点,没有Next app.Map("/Test", MapTest); app.Map("/Eleven", a => a.Run(async context => { await context.Response.WriteAsync($"This is Advanced Eleven Site"); })); app.MapWhen(context => { return context.Request.Query.ContainsKey("Name"); //拒绝非chorme浏览器的请求 //多语言 //把ajax统一处理 }, MapTest); //以上均为Use的封装,其实是为了熟悉的人方便,或者增加面试的复杂度
6.asp.net core 依赖注入+asp.net core 自带IOC容器与autofac容器解析
实现套路,1.接口层 2.实现层,3.控制器层使用依赖注入,4.Startup.ConfigureServices,添加依赖
1.接口层
public interface ITestServiceA { void Show(); } public interface ITestServiceB { void Show(); } public interface ITestServiceC { void Show(); } public interface ITestServiceD { void Show(); } public interface ITestServiceE { void Show(); }
2.实现层
public class TestServiceA : ITestServiceA { public TestServiceA() { Console.WriteLine($"{this.GetType().Name}被构造。。。"); } public void Show() { Console.WriteLine("A123456"); } } public class TestServiceB : ITestServiceB { public TestServiceB(ITestServiceA iTestServiceA) { Console.WriteLine($"{this.GetType().Name}被构造。。。"); } public void Show() { Console.WriteLine($"This is TestServiceB B123456"); } } public class TestServiceC : ITestServiceC { public TestServiceC(ITestServiceB iTestServiceB) { Console.WriteLine($"{this.GetType().Name}被构造。。。"); } public void Show() { Console.WriteLine("C123456"); } } public class TestServiceD : ITestServiceD { public TestServiceD() { Console.WriteLine($"{this.GetType().Name}被构造。。。"); } public void Show() { Console.WriteLine("D123456"); } } public class TestServiceE : ITestServiceE { public TestServiceE(ITestServiceC serviceC) { Console.WriteLine($"{this.GetType().Name}被构造。。。"); } public void Show() { Console.WriteLine("E123456"); } } public class TestServiceUpdate : ITestServiceA { public TestServiceUpdate() { Console.WriteLine($"{this.GetType().Name} --V2被构造。。。"); } public void Show() { Console.WriteLine("A123456 V2"); } }
3.控制器实现依赖注入
public class SecondController : Controller { private readonly ITestServiceA _iTestServiceA; /// <summary> /// 构造函数注入 /// </summary> public SecondController( ITestServiceA testServiceA) { this._iTestServiceA = testServiceA; } public IActionResult Index() { //实现 this._iTestServiceA.Show(); return View(); } }
4.Startup.ConfigureServices,添加依赖 两种方式 一种是添加autofac第三方IOC容器 一种是自带的容器
public void ConfigureServices(IServiceCollection services) { //services.AddTransient<ITestServiceA, TestServiceA>();//瞬时 在我们实现的时候 每次构造用到TestServiceA 都会被引用一次 //services.AddSingleton<ITestServiceB, TestServiceB>();//单例 全局只会被构造一次 //services.AddScoped<ITestServiceC, TestServiceC>();//作用域单例-- 一次请求一个实例,只在当前作用域生效 }
//第一步先添加nuget引用 第二步在startup.cs添加 public void ConfigureContainer(ContainerBuilder containerBuilder) { containerBuilder.RegisterType<TestServiceA>().As<ITestServiceA>().SingleInstance(); //containerBuilder.RegisterModule<CustomAutofacModule>(); }
ConfigureServices和autofac互不影响
这样就实现了通过依赖注入
自带的IOC容器有几种不同的状态
services.AddTransient<ITestServiceA, TestServiceA>();//瞬时 在我们实现的时候 每次构造用到TestServiceA 都会被引用一次
如下图 如果使用 AddTransint 那么在实现 TestServiceA的时候 A的构造函数会构造一次 TestServiceB实现的时候 B会构造一次 A还会构造以一次
services.AddSingleton<ITestServiceB, TestServiceB>();//单例 全局只会被构造一次
如下图,如果使用AddSingletion 实现TestserviceA的时候 A的构造函数会实现一次 B实现的时候B的构造函数会实现一次 哪怕b引用了A A也不会实现构造函数
services.AddScoped<ITestServiceC, TestServiceC>();//作用域单例-- 一次请求一个实例,只在当前作用域生效
如果使用了AddScoped 那么我们实现 This.TestService.show的时候 他只会在当前的控制器生效 如果别的地方用到了 那么就会报错
视图实现依赖注入,使用类.方法
@*@model ErrorViewModel*@ @*如果ErrorViewModel为空 那么会报错*@ @inject Zhaoxi.AspNetCore3_1.Interface.ITestServiceA _iTestServiceA; @*视图里面做依赖注入*@ @{ ViewData["Title"] = "Error"; Exception exception = base.ViewData["Exception"] as Exception; _iTestServiceA.Show(); } <h1 class="text-danger">Error.</h1> <h2 class="text-danger">An error occurred while processing your request.</h2> <h2>@exception.Message</h2> @*@if (Model.ShowRequestId) { <p> <strong>Request ID:</strong> <code>@Model.RequestId</code> </p> }*@ <h3>Development Mode</h3> <p> Swapping to <strong>Development</strong> environment will display more detailed information about the error that occurred. </p> <p> <strong>The Development environment shouldn't be enabled for deployed applications.</strong> It can result in displaying sensitive information from exceptions to end users. For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong> and restarting the app. </p>
7.Asp.netCore之AOP_通过MVC自带的Filter+Attribute实现自定义异常捕获
实现套路:1.新增FilterAttribute类,2.Startup.ConfigureServices 添加依赖 3.控制器,方法,全局使用,
一般的异常处理我们都是通过try catch 来实现异常捕获每个页面方法都需要加
1.新增FilterAttribute类,
public class CustomExceptionFilterAttribute : ExceptionFilterAttribute { #region Identity 依赖注入 private readonly ILogger<CustomExceptionFilterAttribute> _logger; private readonly IModelMetadataProvider _modelMetadataProvider; public CustomExceptionFilterAttribute(ILogger<CustomExceptionFilterAttribute> logger , IModelMetadataProvider modelMetadataProvider) { this._modelMetadataProvider = modelMetadataProvider; this._logger = logger; } #endregion /// <summary> /// 异常发生,但是没有处理时 /// 异常之后得写日志 /// </summary> /// <param name="context"></param> public override void OnException(ExceptionContext context) { if (!context.ExceptionHandled) { this._logger.LogError($"{context.HttpContext.Request.RouteValues["controller"]} is Error"); if (this.IsAjaxRequest(context.HttpContext.Request))//header看看是不是XMLHttpRequest { context.Result = new JsonResult(new { Result = false, Msg = context.Exception.Message });//中断式---请求到这里结束了,不再继续Action } else { var result = new ViewResult { ViewName = "~/Views/Shared/Error.cshtml" }; result.ViewData = new ViewDataDictionary(_modelMetadataProvider, context.ModelState); result.ViewData.Add("Exception", context.Exception); context.Result = result; } context.ExceptionHandled = true; } } /// <summary> /// 判断http请求是否为ajax /// </summary> /// <param name="request"></param> /// <returns></returns> private bool IsAjaxRequest(HttpRequest request) { string header = request.Headers["X-Requested-With"]; return "XMLHttpRequest".Equals(header); } }
2.Startup.ConfigureServices 添加依赖
public void ConfigureServices(IServiceCollection services) { services.AddScoped(typeof(CustomExceptionFilterAttribute));//不是直接new 而是容器生成 就可以自动注入了 }
3.控制器,方法,全局使用
全局使用特性生效
public void ConfigureServices(IServiceCollection services) { services.AddSession(); services.AddControllersWithViews( options => { options.Filters.Add<CustomExceptionFilterAttribute>();//全局注册 全局都会生效 自动实现依赖注入 }); }
控制器使用特性
[ServiceFilter(typeof(CustomExceptionFilterAttribute))]//控制器生效 public class ThirdController : Controller { }
方法使用特性
/// <summary> /// 不是Action增加try catch 而是Filter /// 特性是编译时确定, this._logger是运行时才生成的,特性的构造函数只能是常量,不能是变量 /// </summary> /// <returns></returns> [ServiceFilter(typeof(CustomExceptionFilterAttribute))] [TypeFilter(typeof(CustomExceptionFilterAttribute))] [CustomIOCFilterFactoryAttribute(typeof(CustomExceptionFilterAttribute))]// public IActionResult Index() { return View(); }
/// <summary> /// 基于完成Filter的依赖注入 /// </summary> public class CustomIOCFilterFactoryAttribute : Attribute, IFilterFactory { private readonly Type _FilterType = null; public CustomIOCFilterFactoryAttribute(Type type) { this._FilterType = type; } public bool IsReusable => true; public IFilterMetadata CreateInstance(IServiceProvider serviceProvider) { //return (IFilterMetadata)serviceProvider.GetService(typeof(CustomExceptionFilterAttribute)); return (IFilterMetadata)serviceProvider.GetService(this._FilterType); } }
//那什么时候用中间件 什么时候用Filter---因为Filter是MVC的,中间件是全部请求都要通过的
//Filter可以针对方法/controller---粒度不同的,合适选择
public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } }
public class ThirdController : Controller { #region Identity private readonly IConfiguration _iConfiguration;//获取配置文件 appsettings.json public ThirdController(IConfiguration configuration) { this._iConfiguration = configuration; } #endregion public IActionResult Index() { string AllowedHosts = this._iConfiguration["AllowedHosts"]; string writeConn = this._iConfiguration["ConnectionStrings:Write"]; string readConn = this._iConfiguration["ConnectionStrings:Read:0"];//获取里面的第1个 //获取配置文件数组 string[] _SqlConnectionStringRead = this._iConfiguration.GetSection("ConnectionStrings").GetSection("Read").GetChildren().Select(s => s.Value).ToArray(); string allowedHost = this._iConfiguration["AllowedHost"].ToString(); return View(); } }
方法执行前做点啥子,方法执行后做点啥子 视图执行前做点啥子 视图执行后做点啥子
/// <summary> /// 自定义操作 /// </summary> public class CustomActionCacheFilterAttribute : ActionFilterAttribute { //方法执行前 public override void OnActionExecuted(ActionExecutedContext context) { Console.WriteLine($"This {nameof(CustomActionCacheFilterAttribute)} OnActionExecuted{this.Order}"); } //方法执行后 public override void OnActionExecuting(ActionExecutingContext context) { Console.WriteLine($"This {nameof(CustomActionCacheFilterAttribute)} OnActionExecuting{this.Order}"); } //视图执行前 public override void OnResultExecuting(ResultExecutingContext context) { Console.WriteLine($"This {nameof(CustomActionCacheFilterAttribute)} OnResultExecuting{this.Order}"); } //视图执行后 public override void OnResultExecuted(ResultExecutedContext context) { Console.WriteLine($"This {nameof(CustomActionCacheFilterAttribute)} OnResultExecuted{this.Order}"); } }
现在有一个问题如果全局,控制器,方法都实现了自定义操作那么执行顺序是
全局注册
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews( options => { options.Filters.Add<CustomActionFilterAttribute>();//全局注册 }); }
控制器,方法注册
[CustomActionFilterAttribute]//控制器注册 public class ThirdController : Controller { //方法注册 [CustomActionFilterAttribute] public IActionResult Info() {} }
10.Asp.Net Core 之用户登录退出,使用UseAuthentication自带过滤器进行鉴权
实现套路:1.Startup,添加中间件和使用,
2.登录控制器增加登录 登出,验证码方法
3.模板页获取信息,
4.其他控制器增鉴权加过滤器
1.Startup,添加中间件和使用,
2.登录控制器增加登录 登出,验证码方法
using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using Client.Models; using Client.Utility; using Interface; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; using Model; namespace Client.Controllers { public class FourthController : Controller { #region Identity private readonly ILogger<FourthController> _logger; private readonly ILoggerFactory _loggerFactory; private readonly IServiceProvider _iServiceProvider; private readonly IConfiguration _iConfiguration; public FourthController(ILogger<FourthController> logger, ILoggerFactory loggerFactory , IServiceProvider serviceProvider , IConfiguration configuration ) //, DbContext dbContext) { this._logger = logger; this._loggerFactory = loggerFactory; this._iServiceProvider = serviceProvider; this._iConfiguration = configuration; //this._dbContext = dbContext; } #endregion [HttpGet]//响应get请求 public ViewResult Login() { return View(); } [HttpPost] public ActionResult Login(string name, string password, string verify) { string verifyCode = base.HttpContext.Session.GetString("CheckCode"); if (verifyCode != null && verifyCode.Equals(verify, StringComparison.CurrentCultureIgnoreCase)) { if ("admin".Equals(name) && "123456".Equals(password)) { CurrentUser currentUser = new CurrentUser() { Id = 123, Name = "admin", Account = "1", Email = "1", Password = "1", LoginTime = DateTime.Now }; #region Cookie/Session 自己写 //base.HttpContext.SetCookies("CurrentUser", Newtonsoft.Json.JsonConvert.SerializeObject(currentUser), 30); //base.HttpContext.Session.SetString("CurrentUser", Newtonsoft.Json.JsonConvert.SerializeObject(currentUser)); #endregion //过期时间全局设置 #region 使用Authentication的形式进行鉴权 var claims = new List<Claim>() { new Claim(ClaimTypes.Name,name), new Claim("password",password),//可以写入任意数据 new Claim("Account","Administrator") }; var userPrincipal = new ClaimsPrincipal(new ClaimsIdentity(claims, "Customer")); HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, userPrincipal, new AuthenticationProperties { ExpiresUtc = DateTime.UtcNow.AddMinutes(30),//有效期 }).Wait();//没用await 因为方法没写async //cookie策略--用户信息---过期时间 #endregion return base.Redirect("/Home/Index"); } else { base.ViewBag.Msg = "账号密码错误"; } } else { base.ViewBag.Msg = "验证码错误"; } return View(); } public ActionResult VerifyCode() { string code = ""; Bitmap bitmap = VerifyCodeHelper.CreateVerifyCode(out code); base.HttpContext.Session.SetString("CheckCode", code); MemoryStream stream = new MemoryStream(); bitmap.Save(stream, ImageFormat.Gif); return File(stream.ToArray(), "image/gif"); } //注销 [HttpPost] //[CustomAllowAnonymous] public ActionResult Logout() { #region Cookie base.HttpContext.Response.Cookies.Delete("CurrentUser"); #endregion Cookie #region Session CurrentUser sessionUser = base.HttpContext.GetCurrentUserBySession(); if (sessionUser != null) { this._logger.LogDebug(string.Format("用户id={0} Name={1}退出系统", sessionUser.Id, sessionUser.Name)); } base.HttpContext.Session.Remove("CurrentUser"); base.HttpContext.Session.Clear(); #endregion Session #region MyRegion //HttpContext.User.Claims//其他信息 HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme).Wait(); #endregion return RedirectToAction("Index", "Home"); ; } } }
@model Zhaoxi.AspNetCore31.Demo.Models.CurrentUser @{ ViewBag.Title = "登录"; } <h2>@ViewBag.Title。</h2> <div class="row"> <div class="col-md-8"> <section id="loginForm"> @using (Html.BeginForm("Login", "Fourth", new { sid = "123", Account = "Eleven" }, FormMethod.Post, true, new { @class = "form-horizontal", role = "form" })) { @Html.AntiForgeryToken() <h4>使用本地帐户登录。</h4> <hr /> @Html.ValidationSummary(true) <div class="form-group"> @Html.LabelFor(m => m.Name, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBoxFor(m => m.Name, new { @class = "form-control" }) </div> </div> <div class="form-group"> @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.PasswordFor(m => m.Password, new { @class = "form-control" }) </div> </div> <div class="form-group"> @Html.Label("VerifyCode", "VerifyCode", new { @class = "col-md-2 control-label" }) <div class="col-md-10"> @Html.TextBox("verify", "", new { @class = "form-control" }) </div> </div> <div class="form-group"> <div class="col-md-10"> <img alt="验证码图片" class="img" onclick="refresh(this)" src="/Fourth/VerifyCode" title="点击刷新"> </div> </div> <div class="form-group"> <div class="col-md-offset-2 col-md-10"> <input type="submit" value="登录" class="btn btn-default" /> @base.ViewBag.Msg </div> </div> } </section> </div> </div> <script> function refresh(obj) { $(obj).attr("src", "/Fifth/Verify?random=" + Math.random()); } </script>
3,.模板页获取信息,
@using Client.Models; @using Client.Utility; @{ //CurrentUser currentUser = base.Context.GetCurrentUserBySession(); //使用Authentication的形式进行鉴权 CurrentUser currentUser = base.Context.User.Identity.Name == null ? null : new CurrentUser() { Name = base.Context.User.Identity.Name }; } @if (currentUser != null) { using (Html.BeginForm("Logout", "Fourth", FormMethod.Post, new { id = "logoutForm", @class = "navbar-right" })) { @Html.AntiForgeryToken() <ul class="nav navbar-nav navbar-right"> <li> @Html.ActionLink("你好 " + currentUser.Name + "!", "Index", "Home", routeValues: null, htmlAttributes: new { title = currentUser.Name }) </li> <li><a href="javascript:document.getElementById('logoutForm').submit()">注销</a></li> </ul> } } else { <ul class="nav navbar-nav navbar-right"> <li>@Html.ActionLink("登录", "Login", "Fourth", routeValues: null, htmlAttributes: new { id = "loginLink" })</li> </ul> }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>@ViewData["Title"] - Client</title> <link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" /> <link rel="stylesheet" href="~/css/site.css" /> </head> <body> <header> <nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3"> <div class="container"> <a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">Client</a> <button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> <span class="navbar-toggler-icon"></span> </button> <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse"> <ul class="navbar-nav flex-grow-1"> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a> </li> <li class="nav-item"> <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a> </li> </ul> @Html.Partial("_LoginPartial") </div> </div> </nav> </header> <div class="container"> <main role="main" class="pb-3"> @RenderBody() </main> </div> <footer class="border-top footer text-muted"> <div class="container"> © 2020 - Client - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a> </div> </footer> <script src="~/lib/jquery/dist/jquery.min.js"></script> <script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script> <script src="~/js/site.js" asp-append-version="true"></script> @RenderSection("Scripts", required: false) </body> </html>
4.其他控制器鉴权加过滤器
11.Asp.Net Core 之网站访问前给http头部添加信息
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory) { app.Use(next => { Console.WriteLine("This is middleware 1"); return new RequestDelegate( async context => { //不能与MVC同时使用因为Response中间件在用了,MVC就不能去修改删除 //await context.Response.WriteAsync("This is Hello World 1 start"); //这样就可以使用 await Task.Run(() => Console.WriteLine("12345678797989")); context.Response.OnStarting(state => { var httpContext = (HttpContext)state; httpContext.Response.Headers.Add("middleware", "12345");//给http头部添加信息 return Task.CompletedTask; }, context); await next.Invoke(context); }); });
startp.cs
本文来自博客园,作者:12不懂3,转载请注明原文链接:https://www.cnblogs.com/LZXX/p/13188218.html