.Net Core全面解析_asp.net Core框架全面解析

目录

    1.Asp.Net Core之前后端传值

  1.1 Asp.netCore之控制台启动项目

  2.Asp.Net Core之核心套路组件形式组装整个项目  不再是.netfrom全家桶形式

  3.Asp.Net Core 之Log4Net日志组件扩展,cmd启动程序

  4.Asp.Net Core 之 理解新管道模型

  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实现自定义异常捕获  实现 方法级别 控制器级别 全局级别捕捉异常

  8.Asp.Net Core 之读取配置文件

  9.Asp.Net Core 之自动义过滤操作,

  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;
        }
    }
Program.cs

发送一个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.1 Asp.netCore之控制台启动项目

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

 

 

 

3.Asp.Net Core使用Log4Net日志

第一种方式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>
log4.config

 第四步:访问程序

cmd启动方式:找到程序bin\debug  输入cmd 打开命令模式:输入 dotnet WebApplication1.dll 运行,浏览器输入 https://localhost:5001/ 直接访问

 

 

 

 

 

 

 4.asp.net core 管道模型解析

.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中间件解析
 //终结式-- 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();
        }
    }
View Code

4.Startup.ConfigureServices,添加依赖 两种方式 一种是添加autofac第三方IOC容器 一种是自带的容器

 public void ConfigureServices(IServiceCollection services)
        { 
  //services.AddTransient<ITestServiceA, TestServiceA>();//瞬时 在我们实现的时候 每次构造用到TestServiceA 都会被引用一次
            //services.AddSingleton<ITestServiceB, TestServiceB>();//单例 全局只会被构造一次
            //services.AddScoped<ITestServiceC, TestServiceC>();//作用域单例-- 一次请求一个实例,只在当前作用域生效 
}
Startup.ConfigureServices自带的容器
//第一步先添加nuget引用
第二步在startup.cs添加
  public void ConfigureContainer(ContainerBuilder containerBuilder)
        {
           containerBuilder.RegisterType<TestServiceA>().As<ITestServiceA>().SingleInstance();

            //containerBuilder.RegisterModule<CustomAutofacModule>();
        }
autofac容器

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>
Erroe.cshtml页面 视图做依赖注入

 

 

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);
        }
    }
Attribute异常捕获代码

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();
        }
View Code

 

 /// <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---因为Filter是MVC的,中间件是全部请求都要通过的
//Filter可以针对方法/controller---粒度不同的,合适选择

 

8.asp.netCore之读取配置文件

 public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }
        public IConfiguration Configuration { get; }
}
Startup类
  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();
        }

    }
控制器读取配置文件

 

 

9.asp.netCore,自动义过滤操作,

方法执行前做点啥子,方法执行后做点啥子 视图执行前做点啥子 视图执行后做点啥子

  /// <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>
}
_LoginPartial分部页
<!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">
            &copy; 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>
_Layout模板页

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);
                      
                     
                    });
            });
Startup

 

startp.cs

posted @ 2020-06-24 16:29  12不懂3  阅读(2498)  评论(0编辑  收藏  举报
创作不易,请勿抄袭,欢迎转载!