.Net 6中WebApplicationBuilder介绍和用法

目录
  • 介绍
  • 正文
    • ConfigureHostBuilder
    • BootstrapHostBuilder
    • WebApplicationBuilder构造函数
    • WebApplicationBuilder.Build()

介绍

.Net 6为我们带来的一种全新的引导程序启动的方式。与之前的拆分成Program.cs和Startup不同,整个引导启动代码都在Program.cs中。

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);在上篇文章中,我简要描述了如何使用 WebApplication和WebApplicationBuilder配置 ASP.NET Core 应用程序。在这篇文章中,我们来深入看下代码.

正文

我们示例程序的第一步是执行WebApplicationBuilder builder = WebApplication.CreateBuilder(args);创建一个WebApplicationBuilder实例。

从命令行中分配Args参数,并将选项对象传递给WebApplicationBuilder构造函数的WebApplicationOptions

  /// <summary>
        /// Initializes a new instance of the <see cref="WebApplicationBuilder"/> class with preconfigured defaults.
        /// </summary>
        /// <param name="args">Command line arguments</param>
        /// <returns>The <see cref="WebApplicationBuilder"/>.</returns>
        public static WebApplicationBuilder CreateBuilder(string[] args) =>
            new(new() { Args = args });

WebApplicationOptions和WebApplicationBuilder后面在讲

    internal WebApplicationBuilder(WebApplicationOptions options, Action<IHostBuilder>? configureDefaults = null)

    /// <summary>
    /// Options for configuing the behavior for <see cref="WebApplication.CreateBuilder(WebApplicationOptions)"/>.
    /// </summary>
    public class WebApplicationOptions
    {
        /// <summary>
        /// The command line arguments.
        /// </summary>
        public string[]? Args { get; init; }

        /// <summary>
        /// The environment name.
        /// </summary>
        public string? EnvironmentName { get; init; }

        /// <summary>
        /// The application name.
        /// </summary>
        public string? ApplicationName { get; init; }

        /// <summary>
        /// The content root path.
        /// </summary>
        public string? ContentRootPath { get; init; }

        /// <summary>
        /// The web root path.
        /// </summary>
        public string? WebRootPath { get; init; }
    }

WebApplicationBuilder由一堆只读属性和一个方法组成Build(),该方法创建了一个WebApplication. 我删除了部分讲解用不到的代码。

如果您熟悉 ASP.NET Core,那么其中许多属性都使用以前版本中的常见类型

  • IWebHostEnvironment: 用于检索环境
  • IServiceCollection: 用于向 DI 容器注册服务。
  • ConfigurationManager: 用于添加新配置和检索配置值。我在之前的文章有讲
  • ILoggingBuilder: 用于注册额外的日志提供程序

在WebHost和Host性质很有趣,因为它们暴露出新的类型,ConfigureWebHostBuilder和ConfigureHostBuilder。这些类型分别实现IWebHostBuilder和IHostBuilder。

公开IWebHostBuilder和IHostBuilder接口对于允许从.NET 6 之前的应用程序迁移到新的最小托管,我们如何将的lambda风格配置IHostBuilder与命令式风格的WebApplicationBuilder协调起来,这就是ConfigureHostBuilder和ConfigureWebHostBuilder与一些内部沿来IHostBuilder实现。

    public sealed class WebApplicationBuilder
    {
        private const string EndpointRouteBuilderKey = "__EndpointRouteBuilder";

        private readonly HostBuilder _hostBuilder = new();
        private readonly BootstrapHostBuilder _bootstrapHostBuilder;
        private readonly WebApplicationServiceCollection _services = new();
        private readonly List<KeyValuePair<string, string>> _hostConfigurationValues;

        private WebApplication? _builtApplication;

        /// <summary>
        /// Provides information about the web hosting environment an application is running.
        /// </summary>
        public IWebHostEnvironment Environment { get; }

        /// <summary>
        /// A collection of services for the application to compose. This is useful for adding user provided or framework provided services.
        /// </summary>
        public IServiceCollection Services { get; }

        /// <summary>
        /// A collection of configuration providers for the application to compose. This is useful for adding new configuration sources and providers.
        /// </summary>
        public ConfigurationManager Configuration { get; }

        /// <summary>
        /// A collection of logging providers for the application to compose. This is useful for adding new logging providers.
        /// </summary>
        public ILoggingBuilder Logging { get; }

        /// <summary>
        /// An <see cref="IWebHostBuilder"/> for configuring server specific properties, but not building.
        /// To build after configuration, call <see cref="Build"/>.
        /// </summary>
        public ConfigureWebHostBuilder WebHost { get; }

        /// <summary>
        /// An <see cref="IHostBuilder"/> for configuring host specific properties, but not building.
        /// To build after configuration, call <see cref="Build"/>.
        /// </summary>
        public ConfigureHostBuilder Host { get; }

        /// <summary>
        /// Builds the <see cref="WebApplication"/>.
        /// </summary>
        /// <returns>A configured <see cref="WebApplication"/>.</returns>
        public WebApplication Build()
        {
            // Wire up the host configuration here. We don't try to preserve the configuration
            // source itself here since we don't support mutating the host values after creating the builder.
            _hostBuilder.ConfigureHostConfiguration(builder =>
            {
                builder.AddInMemoryCollection(_hostConfigurationValues);
            });

            var chainedConfigSource = new TrackingChainedConfigurationSource(Configuration);

            // Wire up the application configuration by copying the already built configuration providers over to final configuration builder.
            // We wrap the existing provider in a configuration source to avoid re-bulding the already added configuration sources.
            _hostBuilder.ConfigureAppConfiguration(builder =>
            {
                builder.Add(chainedConfigSource);

                foreach (var (key, value) in ((IConfigurationBuilder)Configuration).Properties)
                {
                    builder.Properties[key] = value;
                }
            });

            // This needs to go here to avoid adding the IHostedService that boots the server twice (the GenericWebHostService).
            // Copy the services that were added via WebApplicationBuilder.Services into the final IServiceCollection
            _hostBuilder.ConfigureServices((context, services) =>
            {
                // We've only added services configured by the GenericWebHostBuilder and WebHost.ConfigureWebDefaults
                // at this point. HostBuilder news up a new ServiceCollection in HostBuilder.Build() we haven't seen
                // until now, so we cannot clear these services even though some are redundant because
                // we called ConfigureWebHostDefaults on both the _deferredHostBuilder and _hostBuilder.
                foreach (var s in _services)
                {
                    services.Add(s);
                }

                // Add the hosted services that were initially added last
                // this makes sure any hosted services that are added run after the initial set
                // of hosted services. This means hosted services run before the web host starts.
                foreach (var s in _services.HostedServices)
                {
                    services.Add(s);
                }

                // Clear the hosted services list out
                _services.HostedServices.Clear();

                // Add any services to the user visible service collection so that they are observable
                // just in case users capture the Services property. Orchard does this to get a "blueprint"
                // of the service collection

                // Drop the reference to the existing collection and set the inner collection
                // to the new one. This allows code that has references to the service collection to still function.
                _services.InnerCollection = services;

                var hostBuilderProviders = ((IConfigurationRoot)context.Configuration).Providers;

                if (!hostBuilderProviders.Contains(chainedConfigSource.BuiltProvider))
                {
                    // Something removed the _hostBuilder's TrackingChainedConfigurationSource pointing back to the ConfigurationManager.
                    // This is likely a test using WebApplicationFactory. Replicate the effect by clearing the ConfingurationManager sources.
                    ((IConfigurationBuilder)Configuration).Sources.Clear();
                }

                // Make builder.Configuration match the final configuration. To do that, we add the additional
                // providers in the inner _hostBuilders's Configuration to the ConfigurationManager.
                foreach (var provider in hostBuilderProviders)
                {
                    if (!ReferenceEquals(provider, chainedConfigSource.BuiltProvider))
                    {
                        ((IConfigurationBuilder)Configuration).Add(new ConfigurationProviderSource(provider));
                    }
                }
            });

            // Run the other callbacks on the final host builder
            Host.RunDeferredCallbacks(_hostBuilder);

            _builtApplication = new WebApplication(_hostBuilder.Build());

            // Mark the service collection as read-only to prevent future modifications
            _services.IsReadOnly = true;

            // Resolve both the _hostBuilder's Configuration and builder.Configuration to mark both as resolved within the
            // service provider ensuring both will be properly disposed with the provider.
            _ = _builtApplication.Services.GetService<IEnumerable<IConfiguration>>();

            return _builtApplication;
        }

   private void ConfigureApplication(WebHostBuilderContext context, IApplicationBuilder app)
        {
            Debug.Assert(_builtApplication is not null);

            // UseRouting called before WebApplication such as in a StartupFilter
            // lets remove the property and reset it at the end so we don't mess with the routes in the filter
            if (app.Properties.TryGetValue(EndpointRouteBuilderKey, out var priorRouteBuilder))
            {
                app.Properties.Remove(EndpointRouteBuilderKey);
            }

            if (context.HostingEnvironment.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }

            // Wrap the entire destination pipeline in UseRouting() and UseEndpoints(), essentially:
            // destination.UseRouting()
            // destination.Run(source)
            // destination.UseEndpoints()

            // Set the route builder so that UseRouting will use the WebApplication as the IEndpointRouteBuilder for route matching
            app.Properties.Add(WebApplication.GlobalEndpointRouteBuilderKey, _builtApplication);

            // Only call UseRouting() if there are endpoints configured and UseRouting() wasn't called on the global route builder already
            if (_builtApplication.DataSources.Count > 0)
            {
                // If this is set, someone called UseRouting() when a global route builder was already set
                if (!_builtApplication.Properties.TryGetValue(EndpointRouteBuilderKey, out var localRouteBuilder))
                {
                    app.UseRouting();
                }
                else
                {
                    // UseEndpoints will be looking for the RouteBuilder so make sure it's set
                    app.Properties[EndpointRouteBuilderKey] = localRouteBuilder;
                }
            }

            // Wire the source pipeline to run in the destination pipeline
            app.Use(next =>
            {
                _builtApplication.Run(next);
                return _builtApplication.BuildRequestDelegate();
            });

            if (_builtApplication.DataSources.Count > 0)
            {
                // We don't know if user code called UseEndpoints(), so we will call it just in case, UseEndpoints() will ignore duplicate DataSources
                app.UseEndpoints(_ => { });
            }

            // Copy the properties to the destination app builder
            foreach (var item in _builtApplication.Properties)
            {
                app.Properties[item.Key] = item.Value;
            }

            // Remove the route builder to clean up the properties, we're done adding routes to the pipeline
            app.Properties.Remove(WebApplication.GlobalEndpointRouteBuilderKey);

            // reset route builder if it existed, this is needed for StartupFilters
            if (priorRouteBuilder is not null)
            {
                app.Properties[EndpointRouteBuilderKey] = priorRouteBuilder;
            }
        }

        private sealed class LoggingBuilder : ILoggingBuilder
        {
            public LoggingBuilder(IServiceCollection services)
            {
                Services = services;
            }

            public IServiceCollection Services { get; }
        }
    }

ConfigureHostBuilder

 public sealed class ConfigureHostBuilder : IHostBuilder, ISupportsConfigureWebHost

    IHostBuilder ISupportsConfigureWebHost.ConfigureWebHost(Action<IWebHostBuilder> configure, Action<WebHostBuilderOptions> configureOptions)
        {
            throw new NotSupportedException("ConfigureWebHost() is not supported by WebApplicationBuilder.Host. Use the WebApplication returned by WebApplicationBuilder.Build() instead.");
        }

ConfigureHostBuilder实现IHostBuilder和ISupportsConfigureWebHost,但 ISupportsConfigureWebHost 的实现是假的什么意思呢?

这意味着虽然以下代码可以编译,但是会在运行时抛出异常。

WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
builder.Host.ConfigureWebHost(webBuilder =>
{
    webBuilder.UseStartup<Startup>();
});

ConfigureServices(),该方法Action<>使用IServiceCollection从WebApplicationBuilder. 所以以下两个调用在功能上是相同的:

后一种方法显然不值得在正常实践中使用,但仍然可以使用依赖于这种方法的现有代码,

 public IHostBuilder ConfigureAppConfiguration(Action<HostBuilderContext, IConfigurationBuilder> configureDelegate)
    {
        // Run these immediately so that they are observable by the imperative code
        configureDelegate(_context, _configuration);
        return this;
    }

    public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate)
    {
        // Run these immediately so that they are observable by the imperative code
        configureDelegate(_context, _services);
        return this;
    }
builder.Services.AddSingleton<MyImplementation>();

builder.Host.ConfigureServices((ctx, services) => services.AddSingleton<MyImplementation>());

并非所有委托ConfigureHostBuilder都立即传递给运行中的方法。例如UseServiceProviderFactory()保存在列表中,稍后在调用WebApplicationBuilder.Build()

      public IHostBuilder UseServiceProviderFactory<TContainerBuilder>(IServiceProviderFactory<TContainerBuilder> factory) where TContainerBuilder : notnull
        {
            if (factory is null)
            {
                throw new ArgumentNullException(nameof(factory));
            }

            _operations.Add(b => b.UseServiceProviderFactory(factory));
            return this;
        }

BootstrapHostBuilder

回到ConfigureHostBuilder我们看内部的BootstrapHostBuilder,它记录了IHostBuilder收到的所有调用。例如ConfigureHostConfiguration()和ConfigureServices(),
这与ConfigureHostBuilder立即执行提供的委托相比,BootstrapHostBuilder的保存将委托提供给稍后执行的列表。这类似于泛型的HostBuilder工作方式。但请注意,这BootstrapHostBuilder调用Build()会引发异常

 internal class BootstrapHostBuilder : IHostBuilder
    {
        private readonly IServiceCollection _services;
        private readonly List<Action<IConfigurationBuilder>> _configureHostActions = new();
        private readonly List<Action<HostBuilderContext, IConfigurationBuilder>> _configureAppActions = new();
        private readonly List<Action<HostBuilderContext, IServiceCollection>> _configureServicesActions = new();

        public IHost Build()
        {
            // HostingHostBuilderExtensions.ConfigureDefaults should never call this.
            throw new InvalidOperationException();
        }
        public IHostBuilder ConfigureHostConfiguration(Action<IConfigurationBuilder> configureDelegate)
        {
            _configureHostActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)));
            return this;
        }

        public IHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureDelegate)
        {
            // HostingHostBuilderExtensions.ConfigureDefaults calls this via ConfigureLogging
            _configureServicesActions.Add(configureDelegate ?? throw new ArgumentNullException(nameof(configureDelegate)));
            return this;
        }
        // .....
    }

WebApplicationBuilder构造函数

最后我们来看WebApplicationBuilder构造函数,注释都给大家翻译了

internal WebApplicationBuilder(WebApplicationOptions options, Action<IHostBuilder>? configureDefaults = null)
        {
            Services = _services;

            var args = options.Args;

            //尽早运行方法配置通用和web主机默认值,以从appsettings.json填充配置
            //要预填充的环境变量(以DOTNET和ASPNETCORE为前缀)和其他可能的默认源
            //正确的默认值。
            _bootstrapHostBuilder = new BootstrapHostBuilder(Services, _hostBuilder.Properties);

               //不要在这里指定参数,因为我们希望稍后应用它们,以便
            //可以覆盖ConfigureWebHostDefaults指定的默认值
            _bootstrapHostBuilder.ConfigureDefaults(args: null);

            // This is for testing purposes
            configureDefaults?.Invoke(_bootstrapHostBuilder);

            //我们上次在这里指定了命令行,因为我们跳过了对ConfigureDefaults的调用中的命令行。
            //args可以包含主机和应用程序设置,因此我们要确保
            //我们适当地订购这些配置提供程序,而不复制它们
            if (args is { Length: > 0 })
            {
                _bootstrapHostBuilder.ConfigureAppConfiguration(config =>
                {
                    config.AddCommandLine(args);
                });
            }

            // ....
        }
// 自ConfigureWebHostDefaults覆盖特定于主机的设置(应用程序名称)以来,上次将参数应用于主机配置。
            _bootstrapHostBuilder.ConfigureHostConfiguration(config =>
            {
                if (args is { Length: > 0 })
                {
                    config.AddCommandLine(args);
                }

                // Apply the options after the args
                options.ApplyHostConfiguration(config);
            });

到此你可能都非常疑惑这玩意到底在干嘛。只要能看明白下面代码就好了,调用BootstrapHostBuilder.RunDefaultCallbacks(),
它以正确的顺序运行我们迄今为止积累的所有存储的回调,以构建HostBuilderContext. 该HostBuilderContext则是用来最终设定的剩余性能WebApplicationBuilder。

完成特定于应用程序的配置后,在由我们手动调用Build()创建一个WebApplication实例。

            Configuration = new();

            // Collect the hosted services separately since we want those to run after the user's hosted services
            _services.TrackHostedServices = true;

            // This is the application configuration
            var (hostContext, hostConfiguration) = _bootstrapHostBuilder.RunDefaultCallbacks(Configuration, _hostBuilder);

            // Stop tracking here
            _services.TrackHostedServices = false;

            // Capture the host configuration values here. We capture the values so that
            // changes to the host configuration have no effect on the final application. The
            // host configuration is immutable at this point.
            _hostConfigurationValues = new(hostConfiguration.AsEnumerable());

            // Grab the WebHostBuilderContext from the property bag to use in the ConfigureWebHostBuilder
            var webHostContext = (WebHostBuilderContext)hostContext.Properties[typeof(WebHostBuilderContext)];

            // Grab the IWebHostEnvironment from the webHostContext. This also matches the instance in the IServiceCollection.
            Environment = webHostContext.HostingEnvironment;
            Logging = new LoggingBuilder(Services);
            Host = new ConfigureHostBuilder(hostContext, Configuration, Services);
            WebHost = new ConfigureWebHostBuilder(webHostContext, Configuration, Services);

WebApplicationBuilder.Build()

该Build()方法不是非常复杂,首先是将配置的配置源复制到_hostBuilder的ConfigurationBuilder实现中。调用此方法时,builder它最初为空,因此这将填充由默认构建器扩展方法添加的所有源,以及您随后配置的额外源。

 // source itself here since we don't support mutating the host values after creating the builder.
            _hostBuilder.ConfigureHostConfiguration(builder =>
            {
                builder.AddInMemoryCollection(_hostConfigurationValues);
            });

             _hostBuilder.ConfigureAppConfiguration(builder =>
            {
                builder.Add(chainedConfigSource);

                foreach (var (key, value) in ((IConfigurationBuilder)Configuration).Properties)
                {
                    builder.Properties[key] = value;
                }
            });

接下来,是一样的事情IServiceCollection,将它们从_services实例复制到_hostBuilder的集合中。

// This needs to go here to avoid adding the IHostedService that boots the server twice (the GenericWebHostService).
            // Copy the services that were added via WebApplicationBuilder.Services into the final IServiceCollection
            _hostBuilder.ConfigureServices((context, services) =>
            {
                // We've only added services configured by the GenericWebHostBuilder and WebHost.ConfigureWebDefaults
                // at this point. HostBuilder news up a new ServiceCollection in HostBuilder.Build() we haven't seen
                // until now, so we cannot clear these services even though some are redundant because
                // we called ConfigureWebHostDefaults on both the _deferredHostBuilder and _hostBuilder.
                foreach (var s in _services)
                {
                    services.Add(s);
                }

                // Add the hosted services that were initially added last
                // this makes sure any hosted services that are added run after the initial set
                // of hosted services. This means hosted services run before the web host starts.
                foreach (var s in _services.HostedServices)
                {
                    services.Add(s);
                }

                // Clear the hosted services list out
                _services.HostedServices.Clear();

                // Add any services to the user visible service collection so that they are observable
                // just in case users capture the Services property. Orchard does this to get a "blueprint"
                // of the service collection

                // Drop the reference to the existing collection and set the inner collection
                // to the new one. This allows code that has references to the service collection to still function.
                _services.InnerCollection = services;

                var hostBuilderProviders = ((IConfigurationRoot)context.Configuration).Providers;

                if (!hostBuilderProviders.Contains(chainedConfigSource.BuiltProvider))
                {
                    // Something removed the _hostBuilder's TrackingChainedConfigurationSource pointing back to the ConfigurationManager.
                    // This is likely a test using WebApplicationFactory. Replicate the effect by clearing the ConfingurationManager sources.
                    ((IConfigurationBuilder)Configuration).Sources.Clear();
                }

                // Make builder.Configuration match the final configuration. To do that, we add the additional
                // providers in the inner _hostBuilders's Configuration to the ConfigurationManager.
                foreach (var provider in hostBuilderProviders)
                {
                    if (!ReferenceEquals(provider, chainedConfigSource.BuiltProvider))
                    {
                        ((IConfigurationBuilder)Configuration).Add(new ConfigurationProviderSource(provider));
                    }
                }
            });

接下来运行我们在ConfigureHostBuilder属性中收集的任何回调

// Run the other callbacks on the final host builder
Host.RunDeferredCallbacks(_hostBuilder);

最后我们调用_hostBuilder.Build()构建Host实例,并将其传递给 的新实例WebApplication。调用_hostBuilder.Build()是调用所有注册回调的地方。

_builtApplication = new WebApplication(_hostBuilder.Build());

最后,为了保持一切一致ConfigurationManager实例被清除,并链接到存储在WebApplication. 此外IServiceCollectiononWebApplicationBuilder被标记为只读,因此在调用后尝试添加服务WebApplicationBuilder将抛出一个InvalidOperationException. 最后WebApplication返回。

 // Mark the service collection as read-only to prevent future modifications
            _services.IsReadOnly = true;

            // Resolve both the _hostBuilder's Configuration and builder.Configuration to mark both as resolved within the
            // service provider ensuring both will be properly disposed with the provider.
            _ = _builtApplication.Services.GetService<IEnumerable<IConfiguration>>();

            return _builtApplication;

差不多就是这样.

到此这篇关于.Net 6中WebApplicationBuilder介绍和用法的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • .Net 6中WebApplicationBuilder介绍和用法

    目录 介绍 正文 ConfigureHostBuilder BootstrapHostBuilder WebApplicationBuilder构造函数 WebApplicationBuilder.Build() 介绍 .Net 6为我们带来的一种全新的引导程序启动的方式.与之前的拆分成Program.cs和Startup不同,整个引导启动代码都在Program.cs中. WebApplicationBuilder builder = WebApplication.CreateBuilder(a

  • 基于Python2、Python3中reload()的不同用法介绍

    reload() 简介 作用:用于重新载入之前载入的模块 语法格式:reload(module) 参数:module为模块对象,必须已经被加载 返回值:返回模块对象 注意事项: 多次重复使用import语句时,不会重新加载被指定的模块,只是把对该模块的内存地址给引用到本地变量环境. reload()会重新加载已加载的模块,重新编译模块,重新执行模块级代码,但是__init__函数不再重复执行,原来已经使用的实例还是会使用旧的模块,而新生产的实例会使用新的模块:reload后还是用原来的内存地址:

  • python 的numpy库中的mean()函数用法介绍

    1. mean() 函数定义: numpy.mean(a, axis=None, dtype=None, out=None, keepdims=<class numpy._globals._NoValue at 0x40b6a26c>)[source] Compute the arithmetic mean along the specified axis. Returns the average of the array elements. The average is taken over

  • 简单介绍java中equals以及==的用法

    简单介绍 equals方法是java.lang.Object类的方法有两种用法说明: 一.对于字符串变量来说,使用"=="和"equals()"方法比较字符串时,其比较方法不同. 1."=="比较两个变量本身的值,即两个对象在内存中的首地址.(java中,对象的首地址是它在内存中存放的起始地址,它后面的地址是用来存放它所包含的各个属性的地址,所以内存中会用多个内存块来存放对象的各个参数,而通过这个首地址就可以找到该对象,进而可以找到该对象的各个属

  • C#中File和FileStream的简单介绍和用法

    前言 在近期的工作过程中发现自己的基础比较薄弱,所以最近在恶补基础知识.下面就对我所学习的File类和FileStream进行简单的总结. 1.首先先介绍File类和FileStream文件流 1.1  File类,是一个静态类,支持对文件的基本操作,包括创建,拷贝,移动,删除和打开一个文件.File类方法的参量很多时候都是路径path.主要提供有关文件的各种操作,在使用时需要引用System.IO命名空间. 1.2  FileStream文件流 只能处理原始字节(raw byte).FileS

  • SQLServer中exists和except用法介绍

    目录 一.exists 1.1 说明 1.2 示例 1.3 intersect/2017-07-21 二.except 2.1 说明 2.2 示例 三.测试数据 一.exists 1.1 说明 EXISTS(包括 NOT EXISTS)子句的返回值是一个 BOOL 值.EXISTS 内部有一个子查询语句(SELECT ... FROM...),我将其称为 EXIST 的内查询语句.其内查询语句返回一个结果集. EXISTS 子句根据其内查询语句的结果集空或者非空,返回一个布尔值. exists:

  • C#委托方法Func()中GetInvocationList()方法的用法介绍

    在日常使用委托时,有以下常用方法 方法名称 说明  Clone   创建委托的浅表副本.  GetInvocationList   按照调用顺序返回此多路广播委托的调用列表.  GetMethodImpl   返回由当前的 MulticastDelegate 表示的静态方法.  GetObjectData   用序列化该实例所需的所有数据填充 SerializationInfo 对象.  MemberwiseClone   创建当前 Object 的浅表副本.  RemoveImpl   调用列

  • WPF中的数据模板用法介绍

    数据模板常用在3种类型的控件, 下图形式: 1.Grid这种列表表格中修改Cell的数据格式, CellTemplate可以修改单元格的展示数据的方式. 2.针对列表类型的控件, 例如树形控件,下拉列表,列表控件, 可以修改其中的ItemTemplate. 3.修改ContentTemplate, 例UserControl控件的数据展现形式. CellTemplate 模板 下面用一个例子, 来演示CellTemplate使用.例子实现一个DataGrid 展示一个普通的数据标, 同时新增一列C

  • ASP.NET Core MVC中Form Tag Helpers用法介绍

    简介 我们已经介绍过Tag Helpers以及一些最常用的Tag Helpers,也谈到了缓存Tag Helpers.在这篇文章中,我们将讨论表单Tag Helpers. HTML或Web表单通过使用各种HTML元素用于收集来自用户的输入,如输入框.复选框.单选按钮.下拉列表等.使用 <form> 元素时,我们通常使用POST请求.虽然也可以使用GET请求,不过GET请求建议提交于少量.非敏感的数据来获取数据. ASP.NET Core MVC提供了一些Form Tag Helpers,让我们

  • javascript中内置对象Math的介绍及用法案例

    目录 前言 Math概述 Math中常用函数的用法 1.绝对值方法 2.三个取整方法 3.求最大值/最小值 4.随机数 结语 前言 今天总结一下javascript 内置对象Math中的函数用法,顺带写一下常见的案例. Math概述 Math 对象不是构造函数,它具有数学常数和函数的属性和方法.跟数学相关的运算(求绝对值,取整.最大值等)可以使用 Math 中的成员. Math中常用函数的用法 Math.PI //圆周率Math.floor () //向下取整Math.ceil () //向上取

随机推荐