从桌面到 Web - 二十几天学 ASP.NETCore 1

  这么多年一直从事桌面开发,一直没有时间好好学学  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

原文地址:https://www.cnblogs.com/wangxiyou/p/12111334.html

时间: 2024-08-28 08:55:01

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

第三百二十三节,web爬虫,scrapy模块以及相关依赖模块安装

第三百二十三节,web爬虫,scrapy模块以及相关依赖模块安装 当前环境python3.5 ,windows10系统 Linux系统安装 在线安装,会自动安装scrapy模块以及相关依赖模块 pip install Scrapy 手动源码安装,比较麻烦要自己手动安装scrapy模块以及依赖模块 安装以下模块 1.lxml-3.8.0.tar.gz (XML处理库) 2.Twisted-17.5.0.tar.bz2 (用Python编写的异步网络框架) 3.Scrapy-1.4.0.tar.gz

第三百二十四节,web爬虫,scrapy模块介绍与使用

第三百二十四节,web爬虫,scrapy模块介绍与使用 Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架. 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中.其最初是为了页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫.Scrapy用途广泛,可以用于数据挖掘.监测和自动化测试. Scrapy 使用了 Twisted异步网络库来处理网络通讯.

Java Web总结二十二投票系统

投票系统需求: (1)查询所有候选人基本信息 (2)查询某位候选人详细信息 (3)投票人登录和退出 (4)投票人限制1分钟之内重复投票 (5)投票人IP和最后投票时间查询 (6)阻止相同用户名二次在线登录 (7)票数条形显示和候选人头像处理 (8)显示投票人归属地 (9)热门候选人,即投票数最多 (10)后台管理员登录 可选需求: (11)查询.删除.更新.增加候选人详细信息 (12)与一个Listener,创建所有表格式和初始化数据 代码参见:day19/vote(此处不上传) Java We

Java Web总结二十Filter、装饰设计模式

一.Filter的部署--注册Filter <filter> <filter-name>testFitler</filter-name> <filter-class>org.test.TestFiter</filter-class> <init-param> <param-name>word_file</param-name> <param-value>/WEB-INF/word.txt</p

【Java二十周年】十年,二十年

十年 十年前的这个季节,迎着空中烂漫飘落的樱花,我们踌躇满志的走出了大学的殿堂.作为一名管理学院毕业的本科生,信息管理与信息系统这个专业让我与软件开发这个职业有了些许的联系.实际的状况是:在几年的学习生涯中,所学到的编程语言也仅仅只有C语言而已,而且学习的程度也不深,对于指针,结构体这样一些相对复杂的知识点,老师也是一带而过.也就是带着那点可怜的编程知识,我勇敢的到一家美资的企业去应聘程序员.第一关当然是笔试,一位淡定的面试官拿了一份让我很不淡定的考试卷--Java 编程开发相关的试题.Java

微软云计算介绍与实践(实践之二十)

接上面章节,有同学说为什么要搞这么一些东西,刚好我给大家贴一张图,看一下微软私有云解决方案中这几大组件相互关系,看完后大家也就明白我今天为什么还在做各种环境搭建,配置准备工作了. 一.配置System Center 2012虚拟机管理器集成包 上一章节,小张同学可以使用已有的的集成包,但他需要配置一下它们,让其和服务器正确连接.在接下来的步骤中,小张同学是要配置的是他刚刚注册和部署的四个集成包.关于使用集成包的先决条件.可以参考如下TechNet网页:http://technet.microso

Java Web总结十九Filter过滤器

一.Filter简介 Filter也称之为过滤器,它是Servlet技术中最激动人心的技术,Web开发人员通过Filter技术,对Web服务器管理的所有Web资源:例如Jsp,Servlet,静态图片文件或静态HTML文件等进行拦截,从而实现一些特殊的功能.例如实现URL级别的权限访问控制.过滤敏感词汇.自动登录.压缩响应信息等一些高级功能. Servlet API中提供了一个Filter接口,开发Web应用时,如果编写的Java类实现了这个接口,则把这个Java类称之为过滤器Filter.通过

Java Web总结十六之一自定义标签

一.自定义标签简介 1.为什么要使用自定义标签? 自定义标签主要用于移除Jsp页面中的<%java%>代码. 2.开发自定义标签的步骤: 1)开发自定义标签处理类,该类需要实现SimpleTag接口/SimpleTagSupport类,重写doTag()方法. 2)编写标签库描述符(tld)文件,在tld文件中对自定义标签进行描述,并放置在WEB-INF/目录下. 3)完成以上操作,即可在JSP页面中导入和使用自定义标签. 二.自定义标签描述 1.实现SimpleTag接口的标签通常称为简单标

云计算设计模式(二十四)——仆人键模式

云计算设计模式(二十四)——仆人键模式 使用一个令牌或密钥,向客户提供受限制的直接访问特定的资源或服务,以便由应用程序代码卸载数据传输操作.这个模式是在使用云托管的存储系统或队列的应用中特别有用,并且可以最大限度地降低成本,最大限度地提高可扩展性和性能. 背景和问题 客户端程序和网络浏览器经常需要读取和写入文件或数据流,并从一个应用程序的存储空间.通常,应用程序将处理的运动数据,或者通过从存储读取它,并将其传输到客户端,或通过从客户机读取该载流并将其存储在数据存储中.然而,这种方法吸收了宝贵的资