这么多年一直从事桌面开发,一直没有时间好好学学  web 开发。感觉自己就像从石器时代走来的古代类人猿。由于工作的调整,现在终于有时间学习一下 Web 开发。出于对技术和框架的熟悉和继承,决定还是学习微软的 Web 开发框架(虽然我一直认为java 是一种比C# 更优秀的语言,社区的活力远高于 C#,想想 eclipse 还是算了吧)。

  微软的 Web 开发框架从 ASP,ASP.NET,ASP.NET MVC 一直到现在的 ASP.NET Core一路走来,坏消息是没有一个熟悉的,好消息是 ASP.NET Core 是完全开源的,这对学习有很大的帮助。https://github.com/aspnet/AspNetCore  学习技术框架最好的方法是分析源码,但这种方法显然不适合我这种对 Web  开发一窍不通的人,对于我来说,最好的方式是通过项目开发尽快的熟悉 ASP.NET Core 。所以我决定尝试通过开发一个虚拟的项目来熟悉ASP.NET Core,同时因为要从桌面转到 web 开发可以预料到各种问题会接踵而至。我决定重开博客,用一系列文章记录其中曲折的过程以及问题和思考,希望这一系列文章能够对需要重 winform 转型到 web 开发的朋友能够带来一些启发。关于这个虚拟项目的背景我会在下一篇介绍、首先我们要了解一下 ASP.NET Core。

关于 ASP.NET Core 的介绍,网上资料铺天盖地,我就不啰嗦了。在这里主要谈谈从一个桌面 程序员的视角看 ASP.NET Core 的几点感受。

首先用 VS 创建一个 ASP.NET Core 项目,在项目模板选项中因为计算机环境的原因,暂时不选择启用 Docker 支持,Docker 支持在后期可以很方便的添加,当然前提是你搞定了 Docker 的安装和配置,Docker 是个好东西,在你的应用需要跨平台部署时。当然,如果你决定使用 IIS 托管,并且部署环境很固定的话,是不需要 Docker 的。关于 Docker 的安装和配置,网上资料很多,步骤也不是很繁琐,有兴趣的朋友可以百度一下。身份认证选择“个人用户账户”。

  

  

  当然,在真实的项目中,你可能不太会直接用 新建 的方式创建一个项目,并把所有代码包含在一个项目中。更好的方式是创建一个解决方案,然后创建不同的项目对应程序不同的层。更常用的方式是在解决方案根目录下创建文件夹,把项目放在src文件夹,把测试项目放在 test 文件夹。在程序的分层架构方面 winform 或者说桌面程序和 Web 程序没有太大的区别。两者的区别在于表示层,桌面程序你需要自己设计 UI 程序 ,而 Web 程序你不需要自己设计 UI 程序(感谢各种浏览器),你需要在表示层设计UI的内容,在运行时通过各种框架技术,把他们推送到客户的浏览器中。当然早桌面程序中你也可以这么做,先开发一个通过的窗体作为容器,能够运行用某种文件描述的可编辑的内容,用于工业控制的组态软件通常这么做,我以前做的一个生产线控制系统也是这么做的。

  好了,废话少说,我们先看看创创建的项目的文件结构

  

  可以看出,程序的结果简单清晰,应该符合 Rails 约定,模型,视图和控制器的文件夹,到我们真正使用时再讨论,现在我们看看感兴趣的文件 – Program 和 Startup,看得出 ASP.NET Core 已经抛弃了 ASP.NET 把程序编译成 DLL ,运行时由 IIS 托管的方式。ASP.NET core 程序是由 Kestrel  托管的,在部署在 IIS 上时。IIS 仅起到 反向代理的作用,IIS  会把请求转发到 Kestrel ,为此IIS 必须添加 Asp Net core Module 的模块来实现转发功能,以前在做一个用 ASP.Net Core API 宿主的 SIgnalR 程序时,因为对程序启动方式不了解,就碰到这个坑。让我们先看看 Program 的代码

  

public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
} public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}

  启动代码很简练,使用 WebHost 获取 IWebHost 的构建工厂,再构建出 IWebHost 的实例,然后在运行这个实例。让我们感兴趣的构建 IWebHost 时做了哪些事。这是需要打开 ASP.NET Core 的源码一窥究竟。首先打开 WebHostBuilder 文件,在 Hosting 项目中,我们从里面找到了 Builder 方法,代码比较长,这里只截取我们感兴趣的代码,有兴趣的朋友可以自行查看源码

  

/// <summary>
/// Builds the required services and an <see cref="IWebHost"/> which hosts a web application.
/// </summary>
public IWebHost Build()
{
.....
  var hostingServices = BuildCommonServices(out var hostingStartupErrors);
.....
  AddApplicationServices(applicationServices, hostingServiceProvider);

  IServiceProvider GetProviderFromFactory(IServiceCollection collection)
  {
  var provider = collection.BuildServiceProvider();
  var factory = provider.GetService<IServiceProviderFactory<IServiceCollection>>();


  if (factory != null && !(factory is DefaultServiceProviderFactory))
  {
    using (provider)
    {
    return factory.CreateServiceProvider(factory.CreateBuilder(collection));
    }
  }

  return provider;
  }

}

private IServiceCollection BuildCommonServices(out AggregateException hostingStartupErrors)
{
...

  var services = new ServiceCollection();
  services.AddSingleton(_options);
  services.AddSingleton<IWebHostEnvironment>(_hostingEnvironment);
  services.AddSingleton<IHostEnvironment>(_hostingEnvironment);
  #pragma warning disable CS0618 // Type or member is obsolete
  services.AddSingleton<AspNetCore.Hosting.IHostingEnvironment>(_hostingEnvironment);
  services.AddSingleton<Extensions.Hosting.IHostingEnvironment>(_hostingEnvironment);
  #pragma warning restore CS0618 // Type or member is obsolete
  services.AddSingleton(_context);


  var builder = new ConfigurationBuilder()
  .SetBasePath(_hostingEnvironment.ContentRootPath)
  .AddConfiguration(_config, shouldDisposeConfiguration: true);


  _configureAppConfigurationBuilder?.Invoke(_context, builder);


  var configuration = builder.Build();
  // register configuration as factory to make it dispose with the service provider
  services.AddSingleton<IConfiguration>(_ => configuration);
  _context.Configuration = configuration;


  var listener = new DiagnosticListener("Microsoft.AspNetCore");
  services.AddSingleton<DiagnosticListener>(listener);
  services.AddSingleton<DiagnosticSource>(listener);


  services.AddTransient<IApplicationBuilderFactory, ApplicationBuilderFactory>();
  services.AddTransient<IHttpContextFactory, DefaultHttpContextFactory>();
  services.AddScoped<IMiddlewareFactory, MiddlewareFactory>();
  services.AddOptions();
  services.AddLogging();


  services.AddTransient<IServiceProviderFactory<IServiceCollection>, DefaultServiceProviderFactory>();

  return services;
}

  在 Builder 方法中调用 BuildCommonServices 创建并返回一个 IServiceCollection 的实例, ASp.NET Core 使用这个容器实现依赖注入,并把基础服务通过 AddXXX<T>方法注入到容器。使用不同的方法签名可以控制注入的对象声明周期。以前做桌面程序时,也需要很多基础的服务,一般情况下也会用到容器,然后把它基础在程序的运行时单例中,在 Program 中,在启动主窗体前先把服务注入到运行时,这样就可以在程序任意地方通过接口获取这些服务,类似于 GetService<T>();这是一种手动的依赖注入方式,类似 Addin 方式,在使用服务时需要手动通过接口获取,功能远没有 ASP.NET core  的依赖注入强大.不过应付一般的桌面程序也就够了,毕竟咱也编不了多大的程序。

  让我再回到 Program 中看第二句 UseStartup<Startup>() ,UseStartUp 是一个扩展方法,定义在 WebHostBuilderExtensions 文件中 ,通过代码我们可以知道这个方法就是把 StartUp 的实例注入到 IOC 容器中,只不过代码里做了些判断,注入的对象是否实现了 IStartup 接口。StartUp 代码如下

  

public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
} public IConfiguration Configuration { get; } // This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
}); services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
} app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy(); app.UseAuthentication(); app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}

  ASP.NET Core 使用了中间件实现对请求管道的配置,在 StarUp 中你可以添加自己的中间件实现特殊的功能,这点类似 WCF 的上下文拦截技术(在我原来的博客里写过.NET基于上下文的拦截,不过后来博客密码忘了,只好重新创建一个),可以在请求管道中增加自己需要的垂直功能(如日志记录,身份验证 - 这两项 ASP.NETCore 都有,而且做的不错)- 就是所谓的面向切面的编程 AOP,在 StartUp 中还可以在 IOC 容器中注入依赖。修改甚至加载自己的配置项。必须入,下面这段代码实现了用户数据存储的配置和依赖注入。

  

services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();

  现在我们通过几段简单的源码,简单了解了 ASP.NET Core 的启动过程,虽然很简单,单让我们窥视到了 ASP.NET Core 的基础-依赖注入,这应该是微软和以前不一样的地方。ASP.NET  Core  的其他技术在虚拟项目开始用到的地方在继续写。

  下一篇计划暂时离开 ASP.NETCore 介绍一下项目的背景和这个项目的领域模型.,虚拟项目已经托管在 GitHub ,准备持续开发,敢兴趣的朋友可以 Fork me  https://github.com/wangxiyou/ProductionLBS

PS:一直为这个系列博客起名而发愁,突然想到以前的经典书名 21 天 学会 XXX ,借来一用,窃书为雅,窃书名更雅,感觉 21 天学会太难,于是改成 从桌面到 Web - 二十几天学 ASP.NETCore

从桌面到 Web - 二十几天学 ASP.NETCore 1的更多相关文章

  1. 二十、Hadoop学记笔记————Hive On Hbase

    Hive架构图: 一般用户接口采用命令行操作, hive与hbase整合之后架构图: 使用场景 场景一:通过insert语句,将文件或者table中的内容加入到hive中,由于hive和hbase已经 ...

  2. Web 开发人员和设计师必读文章推荐【系列二十九】

    <Web 前端开发精华文章推荐>2014年第8期(总第29期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  3. Web 前端开发人员和设计师必读文章推荐【系列二十八】

    <Web 前端开发精华文章推荐>2014年第7期(总第28期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  4. VMware vSphere 服务器虚拟化之二十八 桌面虚拟化之安装View传输服务器

    VMware vSphere 服务器虚拟化之二十八 桌面虚拟化之安装View传输服务器 View 传输服务器用于管理和简化数据中心与在最终用户本地系统上检出使用的 View 桌面之间的数据传输.必须安 ...

  5. Web 前端开发人员和设计师必读精华文章【系列二十六】

    <Web 前端开发精华文章推荐>2014年第5期(总第26期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML5 ...

  6. Web 前端开发精华文章推荐(HTML5、CSS3、jQuery)【系列二十二】

    <Web 前端开发精华文章推荐>2014年第一期(总第二十二期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML ...

  7. Web 前端开发精华文章集锦(jQuery、HTML5、CSS3)【系列二十】

    <Web 前端开发精华文章推荐>2013年第八期(总第二十期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各种增强网站用户体验的 jQuery 插件,展示前沿的 HTML5 和 C ...

  8. VMware vSphere 服务器虚拟化之二十五 桌面虚拟化之终端服务池

    VMware vSphere 服务器虚拟化之二十五 桌面虚拟化之终端服务池 终端服务池是指由一台或多台微软终端服务器提供服务的桌面源组成的池.终端服务器桌面源可交付多个桌面.它具有以下特征: 1.终端 ...

  9. VMware vSphere 服务器虚拟化之二十二桌面虚拟化之创建View Composer链接克隆的虚拟桌面池

    VMware vSphere 服务器虚拟化之二十二桌面虚拟化之创建View Composer链接克隆的虚拟桌面池 在上一节我们创建了完整克隆的自动专有桌面池,在创建过程比较缓慢,这次我们将学习创建Vi ...

随机推荐

  1. Python基础:22__slots__类属性

    1:工厂函数 由于类型和类的统一,因而可以子类化Python数据类型.但是所有的Python 内建的转换函数现在都是工厂函数.当这些函数被调用时,你实际上是对相应的类型进行实例化.比如下面的函数都已经 ...

  2. HTTP协议详解以及URL具体访问过程(转载)

    https://blog.csdn.net/f45056231p/article/details/82533490

  3. 2019-3-8-win10-uwp-渲染原理-DirectComposition-渲染

    title author date CreateTime categories win10 uwp 渲染原理 DirectComposition 渲染 lindexi 2019-03-08 09:18 ...

  4. 漏洞: RHSA-2017:3075: wget security update

    该网址有解决方案 http://www.stumblingblock.cn/3102.html

  5. Linux下的实用工具——计算器bc

    Linux下的实用工具——计算器   1. bc指令算加法,如图: 4. bc指令算除法(进阶),如图示,10/3之所以为3,是因为我们没有指定小数点后取几位,默认取到整数部分:而10/100之所以为 ...

  6. 关于Ping和Tracert命令原理详解

    本文只是总结了两个常用的网络命令的实现原理和一点使用经验说明.这些东西通常都分布在各种书籍或者文章中的,我勤快那么一点点,总结一下,再加上我的一点理解和使用经验,方便大家了解.这些也是很基础的东西,没 ...

  7. 【js】React-Native 初始化时报错

    一.按照官网的步骤一步一步的操作,到最后  react-native init AwesomeProject  时就是报错 报错信息如下图 然后我下载了这个模块  npm install prompt ...

  8. 2019-4-10-win10-uwp-自定义标记扩展

    title author date CreateTime categories win10 uwp 自定义标记扩展 lindexi 2019-04-10 09:46:13 +0800 2019-04- ...

  9. navicat for mysql (10038)如何解决

    1.授权(youpassword修改为你的密码) #本机登陆mysql: $:mysql -u root -p #改变数据库: mysql>use mysql; #从所有主机: mysql> ...

  10. linux 内核定时器的实现

    为了使用它们, 尽管你不会需要知道内核定时器如何实现, 这个实现是有趣的, 并且值得 看一下它们的内部. 定时器的实现被设计来符合下列要求和假设: 定时器管理必须尽可能简化. 设计应当随着激活的定时器 ...