ASP.NET Core 运行原理解剖[4]:进入HttpContext的世界

本系列文章从源码分析的角度来探索 ASP.NET Core 的运行原理,分为以下几个章节:

ASP.NET Core 运行原理解剖[1]:Hosting

ASP.NET Core 运行原理解剖[2]:Hosting补充之配置介绍

ASP.NET Core 运行原理解剖[3]:Middleware-请求管道的构成

IHttpContextFactory

在第一章中,我们介绍到,WebHost 在启动 IServer 时,会传入一个 IHttpApplication<TContext> 类型的对象,Server 负责对请求的监听,在接收到请求时,会调用该对象的 ProcessRequestAsync 方法将请求转交给我们的应用程序。IHttpApplication<TContext> 的默认实现为 HostingApplication ,有如下定义:

public class HostingApplication : IHttpApplication<HostingApplication.Context> {  

 private readonly RequestDelegate _application;  

 private readonly IHttpContextFactory _httpContextFactory;  

public Context CreateContext(IFeatureCollection contextFeatures)    {        var context = new Context();      

 var httpContext = _httpContextFactory.Create(contextFeatures);        _diagnostics.BeginRequest(httpContext, ref context);        context.HttpContext = httpContext;    

   return context;    }  

 public Task ProcessRequestAsync(Context context)    {    

   return _application(context.HttpContext);    }

   public void DisposeContext(Context context, Exception exception)    {        var httpContext = context.HttpContext;        _diagnostics.RequestEnd(httpContext, exception, context);        _httpContextFactory.Dispose(httpContext);        _diagnostics.ContextDisposed(context);    } }

首先使用 IHttpContextFactory 来创建 HttpContext 实例,然后在 ProcessRequestAsync 方法中调用上一章介绍的 RequestDelegate,由此进入到我们的应用程序当中。

IHttpContextFactory 负责对 HttpContext 的创建和释放,分别对应着CreateDispose方法,它的默认实现类为HttpContextFactory,定义如下:

public class HttpContextFactory : IHttpContextFactory{  

 private readonly IHttpContextAccessor _httpContextAccessor;  
  private readonly FormOptions _formOptions;  
  
   public HttpContext Create(IFeatureCollection featureCollection)  
   {      
       var httpContext = new DefaultHttpContext(featureCollection);            
       if (_httpContextAccessor != null){_httpContextAccessor.HttpContext = httpContext;}  
     
       var formFeature = new FormFeature(httpContext.Request, _formOptions);featureCollection.Set<IFormFeature>(formFeature);      
         return httpContext;}    
    
    public void Dispose(HttpContext httpContext)    {    
        if (_httpContextAccessor != null){_httpContextAccessor.HttpContext = null;}} }

如上,HttpContextFactory 只是简单的使用 new DefaultHttpContext(featureCollection) 来创建 HttpContext 的实例,而这里涉及到一个 IFeatureCollection 对象,它是由 Server 根据原始请求创建而来的,下面就先介绍一下该对象。

IFeatureCollection

不过,在介绍 IFeatureCollection 之前,我们先需先回顾一下OWIN:

OWIN是 “Open Web Server Interface for .NET” 的首字母缩写,它定义了一套Web Server和Web Application之间的标准接口,主要用于解除 ASP.NET 与 IIS 的紧密耦合。为此,OWIN 定义了四个核心组件:HostServerMiddlewareApplication,并为Server和Middleware的之间的交互提供了一个 Func<IDictionary<string,object>,Task> 类型的标准接口。

每一个OWIN中间件,都会接收到一个 IDictionary<string,object> 类型的变量,用来表示当前请求的相关信息,也称为环境字典。每一个支持OWIN标准的 Web Server 都会根据请求的原始上下文信息,封装成这个环境字典,然后在OWIN中间件之间传递,进而完成整个请求的处理。环境字典定义了一系列预先约定好的Key,比如:用 "owin.RequestBody" 来表示请求体,"owin.RequestHeaders" 来表示请求头,"owin.RequestMethod" 来表示请求方法等。

OWIN是随着ASP.NET MVC5进行到我们的视线中,在当时,ASP.NET WebAPI 2.0 也基于OWIN实现了自寄宿模式。再后来,提出了 ASP.NET 5 与 MVC6,完全是基于OWIN的模式来开发的,再到今天的 ASP.NET Core,OWIN的概念已被模糊化了,但是还是随处可以见到OWIN的影子,并且也提供了对 OWIN 的扩展支持。

在 ASP.NET Core 中,提出了 IFeatureCollection 的概念,它本质上也是一个 IDictionary<string,object> 键值对,但是它具有面向对象的特点,相对于 IDictionary<string,object> 更加清晰,容易理解,并且Server构建成这样一个对象也很容易,它有如下定义:

public interface IFeatureCollection : IEnumerable<KeyValuePair<Type, object>>
{   
    bool IsReadOnly { get; }  
   int Revision { get; }  
   object this[Type key] { get; set; }TFeature Get<TFeature>();  
   void Set<TFeature>(TFeature instance); }

它的定义非常简单,由一系列以键值对来表示的标准特性对象(TFeature)组成,可以通过一个索引以及 Get 和 Set 方法来获取或设置这些特性对象。

下面,我们看一下在 ASP.NET Core 中的对它的一个模拟实现:

public class FeatureCollection : IFeatureCollection{   

 private IDictionary<Type, object> _features;  
 
   private readonly IFeatureCollection _defaults;  
   
     private volatile int _containerRevision;  
     
      public virtual int Revision{      
        get { return _containerRevision + (_defaults?.Revision ?? 0); }}  
   
     public object this[Type key]{      
       get{          
        object result;      
             return _features != null && _features.TryGetValue(key, out result) ? result : _defaults?[key];}    
       set{      
            if (value == null){              
              if (_features != null && _features.Remove(key)){_containerRevision++;}          
                   return;}          
          if (_features == null){_features = new Dictionary<Type, object>();}_features[key] = value;_containerRevision++;}}  
          
     public TFeature Get<TFeature>(){      
       return (TFeature)this[typeof(TFeature)];}    
   
    public void Set<TFeature>(TFeature instance){        this[typeof(TFeature)] = instance;}     }

如上,它的内部属性 _features 便是OWIN中的标准环境字典,并且提供了更加方便的泛型 GetSet 方法,以及一个索引器来访问该环境字典。不过,如果只是这样,那使用起来依然不够方便,更为重要的是 ASP.NET Core 还提供了一系列的特性对象,并以这些特性对象的类型做为环境字典中的Key。

通过上面代码,还可以发现,每次对该环境字典的修改,都会使 Revision 属性递增1。

这里为什么说FeatureCollection是一个模拟的实现呢?具我观察,FeatureCollection对象只在ASP.NET Core的测试代码中用到,而每个Server都有它自己的方式来构建IFeatureCollection,并不会使用FeatureCollection,关于Server中是如何创建IFeatureCollection实例的,可以参考KestrelHttpServer中的实现,这里就不再深究。

那特性对象又是什么呢?我们先看一下请求特性的定义:

public interface IHttpRequestFeature{  
 string Protocol { get; set; }  
  string Scheme { get; set; }  
   string Method { get; set; }    
   string PathBase { get; set; }  
    string Path { get; set; }  
      string QueryString { get; set; }  
      
       string RawTarget { get; set; }IHeaderDictionary Headers { get; set; }Stream Body { get; set; } }

再看一下表单特性的定义:

public interface IFormFeature{   
     bool HasFormContentType { get; }IFormCollection Form { get; set; }
    IFormCollection ReadForm();    Task<IFormCollection> ReadFormAsync(CancellationToken cancellationToken); }

可以看到,这些特性对象与我们熟悉的 HttpContext 中的属性非常相似,这也就大大简化了在 IHttpRequestFeature 和 HttpContext 之间的转换。我们可以通过这些特性接口定义的属性来获取到原始上下文中描述的信息,并通过特性对象提供的方法来操作原始上下文,它就像Web Server与我们的应用程序之间的桥梁,完成抽象和具体之间的转换。

ASP.NET Core 提供了一系列丰富的特性对象,如 Session, Cookies, Query, Form, WebSocket, Request, Response 等等, 更详细的列表可以查看 Microsoft.AspNetCore.Http.Features。

HttpContext

HttpContext 对象我们应该都很熟悉了,它用来表示一个抽象的HTTP上下文,而HttpContext对象的核心又体现在用于描述请求的Request和描述响应的Response属性上。除此之外,它还包含一些与当前请求相关的其他上下文信息,如描述当前HTTP连接的ConnectionInfo对象,控制WebSocket的WebSocketManager,代表当前用户的ClaimsPrincipal对象的Session,等等:

public abstract class HttpContext{   

 public abstract IFeatureCollection Features { get; }  
       public abstract HttpRequest Request { get; }  
       public abstract HttpResponse Response { get; }
       public abstract ConnectionInfo Connection { get; }
       public abstract WebSocketManager WebSockets { get; }  
       public abstract ClaimsPrincipal User { get; set; }  
       public abstract IDictionary<object, object> Items { get; set; }  
       public abstract IServiceProvider RequestServices { get; set; }  
       public abstract CancellationToken RequestAborted { get; set; }    
       public abstract string TraceIdentifier { get; set; }  
       public abstract ISession Session { get; set; }  
       public abstract void Abort(); }

在我们处理请求时,如果希望终止该请求,可以通过 RequestAborted 属性给请求管道发送一个终止信息。当需要对整个管道共享一些与当前上下文相关的数据,可以将它保存在 Items 字典中。而在 ASP.NET Coer 1.x 中还包含一个管理认证的AuthenticationManager对象,但是在 2.0 中,将它移到了 AuthenticationHttpContextExtensions 中,因为用户认证本来就一个相对复杂且独立的模块,把它独立出去会更加符合 ASP.NET Core 的简洁模块化特性。

在上文中,我们了解到 HttpContext 的默认实现使用的是 DefaultHttpContext 类型 ,而 DefaultHttpContext 便是对上面介绍的 IFeatureCollection 对象的封装:

public class DefaultHttpContext : HttpContext{    private FeatureReferences<FeatureInterfaces> _features;    private HttpRequest _request;    private HttpResponse _response;    public DefaultHttpContext(IFeatureCollection features)    {Initialize(features);}    public virtual void Initialize(IFeatureCollection features)    {_features = new FeatureReferences<FeatureInterfaces>(features);_request = InitializeHttpRequest();_response = InitializeHttpResponse();}    protected virtual HttpRequest InitializeHttpRequest() => new DefaultHttpRequest(this);
}

如上,DefaultHttpContext通过 Initialize 来完成从 IFeatureCollection 到 HttpContext 的转换,而各个属性的转换又交给了它们自己。

HttpRequest

HttpRequest 可以用来获取到描述当前请求的各种相关信息,比如请求的协议(HTTP或者HTTPS)、HTTP方法、地址,以及该请求的请求头,请求体等:

public abstract class HttpRequest{   
   public abstract HttpContext HttpContext { get; }
    public abstract string Method { get; set; }  
    public abstract string Scheme { get; set; }  
    public abstract bool IsHttps { get; set; }  
    public abstract HostString Host { get; set; }
    public abstract PathString PathBase { get; set; }  
    public abstract PathString Path { get; set; }
    public abstract QueryString QueryString { get; set; }
    public abstract IQueryCollection Query { get; set; }  
    public abstract string Protocol { get; set; }  
    public abstract IHeaderDictionary Headers { get; }
    public abstract IRequestCookieCollection Cookies { get; set; }
    public abstract long? ContentLength { get; set; }  
    public abstract string ContentType { get; set; }
    public abstract Stream Body { get; set; }
    public abstract bool HasFormContentType { get; }
    public abstract IFormCollection Form { get; set; }  
    public abstract Task<IFormCollection> ReadFormAsync(CancellationToken cancellationToken = new CancellationToken()); }

HttpRequest是一个抽象类,它的默认实现是DefaultHttpRequest:

public class DefaultHttpRequest : HttpRequest{    

private readonly static Func<IFeatureCollection, IHttpRequestFeature> _nullRequestFeature = f => null;    

private FeatureReferences<FeatureInterfaces> _features;    
 public DefaultHttpRequest(HttpContext context)    {Initialize(context);}  
 
  public virtual void Initialize(HttpContext context)    {_context = context;_features = new FeatureReferences<FeatureInterfaces>(context.Features);}  
  
   private IHttpRequestFeature HttpRequestFeature => _features.Fetch(ref _features.Cache.Request, _nullRequestFeature);  
   
   public override string Method{      
    get { return HttpRequestFeature.Method; }  
          set { HttpRequestFeature.Method = value; }}

   public override Task<IFormCollection> ReadFormAsync(CancellationToken cancellationToken)    {    
       return FormFeature.ReadFormAsync(cancellationToken);} }

在 DefaultHttpRequest 中,并没有额外的功能,它只是简单的与 IHttpRequestFeature 中的同名属性和方法做了一个映射,而 IHttpRequestFeature 对象的获取又涉及到一个 FeatureReferences<FeatureInterfaces> 类型, 从字面意思来说,就是对Feature对象的一个引用,用来保存对应的Feature实例,并在上文介绍的 Revision 属性发生变化时,清空Feature实例的缓存:

public struct FeatureReferences<TCache>
{    

public IFeatureCollection Collection { get; private set; }  

 public int Revision { get; private set; }  
 
   public TCache Cache;[MethodImpl(MethodImplOptions.AggressiveInlining)]    
   public TFeature Fetch<TFeature, TState>(ref TFeature cached, TState state, Func<TState, TFeature> factory) where TFeature : class{      
       var flush = false;    
       var revision = Collection.Revision;  
       if (Revision != revision){cached = null;flush = true;}      
        return cached ?? UpdateCached(ref cached, state, factory, revision, flush);}  
 
  private TFeature UpdateCached<TFeature, TState>(ref TFeature cached, TState state, Func<TState, TFeature> factory, int revision, bool flush) where TFeature : class{        if (flush){Cache = default(TCache);}cached = Collection.Get<TFeature>();    
     if (cached == null){cached = factory(state);Collection.Set(cached);Revision = Collection.Revision;}      
      else if (flush)    
     
{Revision = revision;}      
       return cached;}  
   
    public TFeature Fetch<TFeature>(ref TFeature cached, Func<IFeatureCollection, TFeature> factory)  
       where TFeature : class => Fetch(ref cached, Collection, factory); }

如上,当 Revision 生成变化时,会将 Cache 设置为 null , 然后重新从 IFeatureCollection 中获取,最后更新 Revision 为最新版本,相当于一个缓存工厂。

Fetch方法使用了[MethodImpl(MethodImplOptions.AggressiveInlining)]特性,表示该方法会尽可能的使用内联方式来执行。而内联是一种很重要的优化方式, 它允许编译器在方法调用开销比方法本身更大的情况下消除对方法调用的开销,即直接将该方法体嵌入到调用者中。

HttpResponse

在了解了表示请求的抽象类 HttpRequest 之后,我们再来认识一下与它对应的,用来描述响应的 HttpResponse 类型:

public abstract class HttpResponse{   

 private static readonly Func<object, Task> _callbackDelegate = callback => ((Func<Task>)callback)();  
 
   private static readonly Func<object, Task> _disposeDelegate = disposable =>{((IDisposable)disposable).Dispose();      
     return Task.CompletedTask;};  
     
     public abstract HttpContext HttpContext { get; }  
     
     public abstract int StatusCode { get; set; }  
     
     public abstract IHeaderDictionary Headers { get; }
     
     public abstract Stream Body { get; set; }  
     
     public abstract long? ContentLength { get; set; }  
     
     public abstract string ContentType { get; set; }  
     
     public abstract IResponseCookies Cookies { get; }  
     
     public abstract bool HasStarted { get; }  
     
     public abstract void OnStarting(Func<object, Task> callback, object state);  
     
     public virtual void OnStarting(Func<Task> callback) => OnStarting(_callbackDelegate, callback);  
     
     public abstract void OnCompleted(Func<object, Task> callback, object state);  
     
     public virtual void RegisterForDispose(IDisposable disposable) => OnCompleted(_disposeDelegate, disposable);  
     
     public virtual void OnCompleted(Func<Task> callback) => OnCompleted(_callbackDelegate, callback);  
     
     public virtual void Redirect(string location) => Redirect(location, permanent: false);  
     
     public abstract void Redirect(string location, bool permanent); }

HttpResponse也是一个抽象类,我们使用它来输出对请求的响应,如设置HTTP状态码,Cookies,HTTP响应报文头,响应主体等,以及提供了一些将响应发送到客户端时的相关事件。

其 HasStarted 属性用来表示响应是否已开始发往客户端,在我们第一次调用 response.Body.WriteAsync 方法时,该属性便会被设置为 True。需要注意的是,一旦 HasStarted 设置为 true 后,便不能再修改响应头,否则将会抛出 InvalidOperationException 异常,也建议我们在HasStarted设置为true后,不要再对 Response 进行写入,因为此时 content-length 的值已经确定,继续写入可能会造成协议冲突。

HttpResponse 的默认实现为 DefaultHttpResponse ,它与 DefaultHttpRequest 类似,只是对 IHttpResponseFeature 的封装,不过 ASP.NET Core 也为我们提供了一些扩展方法,如:我们在写入响应时,通常使用的是 Response 的扩展方法 WriteAsync :

public static class HttpResponseWritingExtensions{  

 public static Task WriteAsync(this HttpResponse response, string text, CancellationToken cancellationToken = default(CancellationToken))    {        return response.WriteAsync(text, Encoding.UTF8, cancellationToken);}  
 
 public static Task WriteAsync(this HttpResponse response, string text, Encoding encoding, CancellationToken cancellationToken = default(CancellationToken))    {      
   byte[] data = encoding.GetBytes(text);    
    return response.Body.WriteAsync(data, 0, data.Length, cancellationToken);} }

ASP.NET Core 还为 Response 提供了用来一个清空响应头和响应体的扩展方法:

public static class ResponseExtensions{    

public static void Clear(this HttpResponse response)    {  
     if (response.HasStarted){          
      throw new InvalidOperationException("The response cannot be cleared, it has already started sending.");}response.StatusCode = 200;response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = null;response.Headers.Clear();    
        if (response.Body.CanSeek){response.Body.SetLength(0);}} }

还有比较常用的发送文件的扩展方法:SendFileAsync ,获取响应头的扩展方法:GetTypedHeaders 等等,就不再细说。

IHttpContextAccessor

在 ASP.NET 4.x 我们经常会通过 HttpContext.Current 来获取当前请求的 HttpContext 对象,而在 ASP.NET Core 中,HttpContext 不再有 Current 属性,并且在 ASP.NET Core 中一切皆注入,更加推荐使用注入的方式来获取实例,而非使用静态变量。因此,ASP.NET Core 提供了一个 IHttpContextAccessor接口,用来统一获取当前请求的 HttpContext 实例的方式:

public interface IHttpContextAccessor{HttpContext HttpContext { get; set; }
}

它的定义非常简单,就只有一个 HttpContext 属性,它在ASP.NET Core 中还有一个内置的实现类:HttpContextAccessor

public class HttpContextAccessor : IHttpContextAccessor{    

private static AsyncLocal<HttpContext> _httpContextCurrent = new AsyncLocal<HttpContext>();  

 public HttpContext HttpContext{      
       get{        
     return _httpContextCurrent.Value;}      
      set{_httpContextCurrent.Value = value;}} }

这里使用了一个 AsyncLocal<T> 类型来保存 HttpContext 对象,可能很多人对 AsyncLocal 不太了解,这里就来介绍一下:

在.NET 4.5 中引用了 async await 等关键字,使我们可以像编写同步方法一样方便的来执行异步操作,因此我们的大部分代码都会使用异步。以往我们所使用的 ThreadLocal 在同步方法中没有问题,但是在 await 后有可能会创建新实的例(await 之后可能还交给之前的线程执行,也有可能是一个新的线程来执行),而不再适合用来保存线程内的唯一实例,因此在 .NET 4.6 中引用了 AsyncLocal<T> 类型,它类似于 ThreadLocal,但是在 await 之后就算切换线程也仍然可以保持同一实例。我们知道在 ASP.NET 4.x 中,HttpContext的 Current 实例是通过 CallContext 对象来保存的,但是 ASP.NET Core 中不再支持CallContext,故使用 AsyncLocal<T> 来保证线程内的唯一实例。

不过,ASP.NET Core 默认并没有注入 IHttpContextAccessor 对象,如果我们想在应用程序中使用它,则需要手动来注册:

public void ConfigureServices(IServiceCollection services){ervices.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
}

在上面介绍的HttpContextFactory类的构造函数中会注入IHttpContextAccessor实例,并为其HttpContext属性赋值,并在Dispose方法中将其设置为null。

总结

在ASP.NET 4.x 中,我们就对 HttpContext 非常熟悉了,而在 ASP.NET Core 中,它的变化并不大,只是做了一些简化,因此本文较为简单,主要描述了一下 HttpContext 是如何创建的,以及它的构成,最后则介绍了一下在每个请求中获取 HttpContext 唯一实例的方式,而在 ASP.NET Core 2.0 中 HttpContext 的 AuthenticationManager 对象已标记为过时,添加了一些扩展方法来实现AuthenticationManager中的功能,下一章就来介绍一下 ASP.NET Core 中的认证系统。

相关文章: 

  • .NET Core 2.0 正式发布信息汇总

  • .NET Standard 2.0 特性介绍和使用指南

  • .NET Core 2.0 的dll实时更新、https、依赖包变更问题及解决

  • .NET Core 2.0 特性介绍和使用指南

  • Entity Framework Core 2.0 新特性

  • 体验 PHP under .NET Core

  • .NET Core 2.0使用NLog

  • 升级项目到.NET Core 2.0,在Linux上安装Docker,并成功部署

  • 解决Visual Studio For Mac Restore失败的问题

  • ASP.NET Core 2.0 特性介绍和使用指南

  • .Net Core下通过Proxy 模式 使用 WCF

  • .NET Core 2.0 开源Office组件 NPOI

  • ASP.NET Core Razor页面 vs MVC

  • Razor Page–Asp.Net Core 2.0新功能  Razor Page介绍

  • MySql 使用 EF Core 2.0 CodeFirst、DbFirst、数据库迁移(Migration)介绍及示例

  • .NET Core 2.0迁移技巧之web.config配置文件

  • asp.net core MVC 过滤器之ExceptionFilter过滤器(一)

  • ASP.NET Core 使用Cookie验证身份

  • ASP.NET Core MVC – Tag Helpers 介绍

  • ASP.NET Core MVC – Caching Tag Helpers

  • ASP.NET Core MVC – Form Tag Helpers

  • ASP.NET Core MVC – 自定义 Tag Helpers

  • ASP.NET Core MVC – Tag Helper 组件

  • ASP.NET Core 运行原理解剖[1]:Hosting

  • ASP.NET Core 运行原理解剖[2]:Hosting补充之配置介绍

  • ASP.NET Core 运行原理解剖[3]:Middleware-请求管道的构成

原文地址:http://www.cnblogs.com/RainingNight/p/httpcontext-in-asp-net-core.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/323720.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

都忘了自己还有一套房子了。。。

​自20年始来&#xff0c;一直租着我的房子。当时疫情刚刚有所好转&#xff0c;我把房子挂在58上&#xff0c;陆陆续续的有好多人问&#xff0c;不过都没有租&#xff0c;一来离我住的地方有点远&#xff0c;过去一次得个把小时的&#xff0c;人家要看房子不能及时过去。二来问…

Visual Studio2017 远程调试 Remote Debugger

前言 大家在使用vs打包后的文件部署到服务器后&#xff0c;有时候我们需要对线网的后台进行调试。但是它不像在VS中。这个时候我们该怎么调试呢&#xff1f; 微软想到了这一点&#xff0c;他们在 VS 中给我们提供了一个功能: Remote Debugger&#xff0c;要远程调试我们就需要…

对于这款APP,我充了个终身VIP!!!

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂。”现在是&#xff1a;2022年3月15日00:02:07昨天&#xff0c;无意间知道了一款特牛的APP&#xff0c;看了看&#xff0c;决定充了个终身会员&#xff01;今天&#xff0c;我就简单的对这…

Ubuntu amp;amp; GitLab CI amp;amp; Docker amp;amp; ASP.NETnbs

上一篇&#xff1a;Ubuntu & GitLab CI & Docker & ASP.NET Core 2.0 自动化发布和部署&#xff08;1&#xff09; 服务器版本 Ubuntu 16.04 LTS。 本篇博文目的&#xff1a;项目中添加Dockerfile文件&#xff0c;使用 CI 脚本构建自定义镜像&#xff0c;推送到 …

新版《Windows Sysinternals实战指南》,读书积赞活动

新书《Windows Sysinternals实战指南》即将上市。该本由Sysinternals创始人、Windwos内核技术专家Mark Russinovich 与 Windows专家Aaron Margosis联手编著&#xff0c;详细介绍了Sysinternals每款工具的独到功能&#xff0c;并用较多篇幅深入介绍了如何通过几款重量级工具优化…

Bladex生成Swagger的方法

一、在启动类中添加如下代码&#xff1a;&#xff08;目的是为了打印输出swagger的地址等&#xff09; 注解&#xff1a;Slf4j 实现接口&#xff1a;CommandLineRunner 依赖注入&#xff1a; Autowiredprivate Environment environment;Overridepublic void run(String... str…

了解spark计算模型

简介 在集群背后&#xff0c;有一个非常重要的分布式数据架构&#xff0c;即弹性分布式数据集&#xff08;resilient distributed dataset&#xff0c;RDD&#xff09;&#xff0c;它是逻辑集中的实体&#xff0c;在集群中的多台机器上进行了数据分区。通过对多台机器上不同RDD…

如何理解事件溯源

在近期举行的PHPDublin见面会上&#xff0c;来自DynamicRes的架构师Barry Sullivan被问到“什么是事件溯源”&#xff0c;作为对这个问题的回答&#xff0c;他在博客上写下了这篇文章&#xff0c;详细解释了什么是事件溯源以及事件溯源有哪些好处。以下内容翻译自Barry的博客&a…

java中日期处理的一些工具方法

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年4月16日15:35:14&#xff01;忙里偷闲&#xff0c;直接来看方法吧&#xff0c;写完文章继续去改Bug: 1.计算两个日期之间相差的天数 /*** param stratTime 开始时间* p…

ASP.NET Core 运行原理解剖[5]:Authentication

在现代应用程序中&#xff0c;认证已不再是简单的将用户凭证保存在浏览器中&#xff0c;而要适应多种场景&#xff0c;如App&#xff0c;WebAPI&#xff0c;第三方登录等等。在 ASP.NET 4.x 时代的Windows认证和Forms认证已无法满足现代化的需求&#xff0c;因此在ASP.NET Core…

bladex自定义分页

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是2022年4月16日21:44:05&#xff01;今天分享一个代码段&#xff0c;个人觉得还是比较有参考性的。 后端使用框架&#xff1a;bladex前端使用技术&#xff1a;AVue功能:自定义分…

bladex中自定义分页的写法~

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是2022年4月16日21:44:05&#xff01;今天分享一个代码段&#xff0c;个人觉得还是比较有参考性的。后端使用框架&#xff1a;bladex前端使用技术&#xff1a;AVue功能:自定义分…

OpenID Connect:OAuth 2.0协议之上的简单身份层

OpenID Connect是什么&#xff1f;OpenID Connect(目前版本是1.0)是OAuth 2.0协议(可参考本人此篇&#xff1a;OAuth 2.0 / RCF6749 协议解读)之上的简单身份层&#xff0c;用 API 进行身份交互的框架&#xff0c;允许客户端根据授权服务器的认证结果最终确认用户的身份&#x…

一文看懂web服务器、应用服务器、web容器、反向代理服务器区别与联系

我们知道&#xff0c;不同肤色的人外貌差别很大&#xff0c;而双胞胎的辨识很难。有意思的是Web服务器/Web容器/Web应用程序服务器/反向代理有点像四胞胎&#xff0c;在网络上经常一起出现。本文将带读者对这四个相似概念如何区分。 1.1. Web服务器概念与基本原理 1.1.1. Web服…

bladex实现单点登录

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年4月17日16:19:51 在实际开发中&#xff0c;有时候我们有这样的需求&#xff0c;即&#xff0c;一个体系中的用户是共通的&#xff0c;比如统一体系下&#…

若依实现单点登录(解析请求链接中的参数做鉴权认证)

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年4月19日19:56:56 昨天写了个bladex的单点登录&#xff0c;回想起来还是比较复杂的&#xff0c;今天又收到了个在若依里面实现单点登录。具体是这样的:别的系…

Docker打包 Asp.Net Core应用,在CentOS上运行

本文主要介绍下运用docker虚拟技术打包Asp.net core应用。 Docker作为一个开源的应用容器引擎&#xff0c;近几年得到广泛的应用&#xff0c;使用Docker我们可以轻松实现应用的持续集成部署&#xff0c;一次打包&#xff0c;到处运行。 开篇借用百科上对docker的介绍。 Docker …

若依实现系统单点登录(可绕过验证码)

“大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂”前言现在是&#xff1a;2022年4月19日19:56:56昨天写了个bladex的单点登录&#xff0c;回想起来还是比较复杂的&#xff0c;今天又收到了个在若依里面实现单点登录。具体是这样的:别的系…

springboot解析txt文件顺便加到数据库中(nohup文件)

大家好&#xff0c;我是雄雄&#xff0c;欢迎关注微信公众号&#xff1a;雄雄的小课堂 前言 现在是&#xff1a;2022年4月20日13:33:23 以前是怎么都没想到&#xff0c;我需要在服务器的nohup文件中找记录&#xff0c;然后往数据库里面更新。具体因为啥不提了&#xff0c;说多…

ASP.Net Core 2.0中的Razor Page不是WebForm

随着.net core2.0的发布&#xff0c;我们可以创建2.0的web应用了。2.0中新东西的出现&#xff0c;会让我们忘记老的东西&#xff0c;他就是Razor Page。下面的这篇博客将会介绍ASP.Net Core 2.0中的Razor Page。 在ASP.Net Core 2.0新特点之一就是支持Razor Page。今天的Razor…