当前位置: 首页 > news >正文

莒县网站建设广告制作公司如何经营

莒县网站建设,广告制作公司如何经营,刚刚邯郸发生大事了,免费 wordpress企业主题Minimal API仅仅是在基于IHost/IHostBuilder的服务承载系统上作了小小的封装而已#xff0c;它利用WebApplication和WebApplicationBuilder这两个类型提供了更加简洁的API#xff0c;同时提供了与现有API的兼容。[本文节选《ASP.NET Core 6框架揭秘》第17章]一、基础模型二、…Minimal API仅仅是在基于IHost/IHostBuilder的服务承载系统上作了小小的封装而已它利用WebApplication和WebApplicationBuilder这两个类型提供了更加简洁的API同时提供了与现有API的兼容。[本文节选《ASP.NET Core 6框架揭秘》第17章]一、基础模型二、WebApplication三、WebApplication的构建     1. BootstrapHostBuilder     2. ConfigureHostBuilder     3. ConfigureWebHostBuilder     4. WebApplicationBuilder四、 工厂方法一、基础模型对于由WebApplication和WebApplicationBuilder构建的承载模型我们没有必要了解其实现的每一个细节知道其大致的设计和实现原理就可以了所以本节会采用最简洁的代码模拟这两个类型的实现。如图1所示代表承载应用的WebApplication对象是对一个IHost对象的封装而且该类型自身也实现了IHost接口 WebApplication对象其实还是作为一个IHost对象被启动的。作为构建这的WebApplicationBuilder则是对一个IHostBuilder对象的封装它对WebApplication对象的构建体现在利用封装的IHostBuilder对象构建一个对应的IHost对象最终利用后者将WebApplication对象创建出来。图17-8 完整的请求处理管道二、WebApplicationWebApplication类型不仅仅实现了IHost接口还同时实现IApplicationBuilder接口所以中间件可以直接注册到这个对象上的。该类型还实现了IEndpointRouteBuilder接口所以我们还能利用它进行路由注册我们在20章才会涉及到路由所以我们现在先忽略针对该接口的实现。下面的代码模拟WebApplication类型的实现。如代码片段所示WebApplication的构造函数定义了一个IHost类型的参数它利用这个对象完成了对IHost接口所有成员的实现针对IApplicationBuilder接口成员的实现则利用创建的ApplicationBuilder对象来完成。WebApplication还提供了一个BuildRequestDelegate方法利用这个ApplicationBuilder对象完成了对中间件管道的构建。public class WebApplication : IApplicationBuilder, IHost {private readonly IHost _host;private readonly ApplicationBuilder _app;public WebApplication(IHost host){_host  host;_app  new ApplicationBuilder(host.Services);}IServiceProvider IHost.Services  _host.Services;Task IHost.StartAsync(CancellationToken cancellationToken)  _host.StartAsync(cancellationToken);Task IHost.StopAsync(CancellationToken cancellationToken)  _host.StopAsync(cancellationToken);IServiceProvider IApplicationBuilder.ApplicationServices { get  _app.ApplicationServices; set  _app.ApplicationServices  value; }IFeatureCollection IApplicationBuilder.ServerFeatures  _app.ServerFeatures;IDictionarystring, object? IApplicationBuilder.Properties  _app.Properties;RequestDelegate IApplicationBuilder.Build()  _app.Build();IApplicationBuilder IApplicationBuilder.New()  _app.New();IApplicationBuilder IApplicationBuilder.Use(FuncRequestDelegate, RequestDelegate middleware)  _app.Use(middleware);void IDisposable.Dispose()  _host.Dispose();public IServiceProvider Services  _host.Services;internal RequestDelegate BuildRequestDelegate()  _app.Build();... }WebApplication额外定义了如下的RunAsync和Run方法它们分别以异步和同步方式启动承载的应用。调用这两个方法的时候可以指定监听地址指定的地址被添加到IServerAddressesFeature特性中而服务器正式利用这个特性来提供监听地址的。public class WebApplication : IApplicationBuilder, IHost {private readonly IHost _host;public ICollectionstring Urls  _host.Services.GetRequiredServiceIServer().Features.GetIServerAddressesFeature()?.Addresses ?? throw new InvalidOperationException(IServerAddressesFeature is not found.);public Task RunAsync(string? url  null){Listen(url);return HostingAbstractionsHostExtensions.RunAsync(this);}public void Run(string? url  null){Listen(url);HostingAbstractionsHostExtensions.Run(this);}private void Listen(string? url){if (url is not null){var addresses  _host.Services.GetRequiredServiceIServer().Features.GetIServerAddressesFeature()?.Addresses ?? throw new InvalidOperationException(IServerAddressesFeature is not found.);addresses.Clear();addresses.Add(url);}}... }三、WebApplication的构建要创建一个WebApplication对象只需要提供一个对应的IHost对象即可。IHost对象是通过IHostBuilder对象构建的所以WebApplicationBuilder需要一个IHostBuilder对象具体来说是一个HostBuilder对象。我们针对WebApplicationBuilder对象所作的一切设置最终都需要转移到这个HostBuilder对象上才能生效。为了提供更加简洁的APIWebApplicationBuilder类型提供了一系列的属性。比如它利用Serrvices属性提供了可以直接进行服务注册的IServiceCollection集合利用Environment属性提供了表示当前承载环境的IWebHostEnvironment对象利用Configuration属性提供的ConfigurationManager对象不仅可以作为IConfigurationBuilder对象帮助我们完成对配置系统的一切设置它自身也可以作为IConfiguration对象为我们提供配置。WebApplicationBuilder还定义了Host和WebHost属性对应类型为ConfigureHostBuilder和ConfigureWebHostBuilder它们分别实现了IHostBuilder和IWebHostBuilder接口其目的是为了复用IHostBuilder和IWebHostBuilder接口承载的API主要是扩展方法。为了会尽可能使用现有方法对IHostBuilder对象进行初始化设置它还使用了一个实现了IHostBuilder接口的BootstrapHostBuilder类型。有这些对象组成了WebApplicationBuilder针对HostBuilder的构建模型。如图2所示WebApplicationBuilder的所有工作都是为了构建它封装的HostBuilder对象。当WebApplicationBuilder初始化的时候它除了会创建这个HostBuilder对象还会创建存储服务注册的IServiceCollection对象以及用来对配置进行设置的ConfigurationManager对象。接下来它会创建一个BootstrapHostBuilder对象并将它参数调用相应的方法比如ConfigureWebHostDefaults方法将初始化设置收集起来收集的服务注册和针对配置系统的设置分别转移到创建的IServiceCollection和ConfigurationManager对象中其他设置直接应用到封装的HostBuilder对象上。图2 HostBuilder构建模型WebApplicationBuilder在此之后会创建出代表承载环境的IWebHostEnvironment对象并对Environment属性进行初始化。在得到表示承载上下文的WebHostBuilderContext对象之后上述的ConfigureHostBuilder和ConfigureWebHostBuilder对象被创建出来并赋值给Host和WebHost属性。与BootstrapHostBuilder作用类似我们利用这两个对象所作的设置最终都会转移到上述的三个对象中。当WebApplicationBuilder进行WebApplication对象构建的时候IServiceCollection对象存储的服务注册和ConfigurationManager对象承载配置最终转移到HostBuilder对象上。此时再利用后者构建出对应的IHost对象代表承载应用的WebApplication对象最终由该对象构建出来。1. BootstrapHostBuilder如下所示的是我们模拟的BootstrapHostBuilder类型的定义。正如上面所说这个它的作用是收集初始化IHostBuilder对象提供的设置并将它们分别应用到指定的IServiceCollection、ConfigurationManager和IHostBuilder对象上。这一使命体现在BootstrapHostBuilder的Apply方法上该方法还通过一个输出参数返回创建的HostBuilderContext上下文。public class BootstrapHostBuilder : IHostBuilder {private readonly ListActionIConfigurationBuilder _configureHostConfigurations  new();private readonly ListActionHostBuilderContext, IConfigurationBuilder _configureAppConfigurations  new();private readonly ListActionHostBuilderContext, IServiceCollection _configureServices  new();private readonly ListActionIHostBuilder _others  new();public IDictionaryobject, object Properties { get; }  new Dictionaryobject, object();public IHost Build()  throw new NotImplementedException();public IHostBuilder ConfigureHostConfiguration(ActionIConfigurationBuilder configureDelegate){_configureHostConfigurations.Add(configureDelegate);return this;}public IHostBuilder ConfigureAppConfiguration(ActionHostBuilderContext, IConfigurationBuilder configureDelegate){_configureAppConfigurations.Add(configureDelegate);return this;}public IHostBuilder ConfigureServices(ActionHostBuilderContext, IServiceCollection configureDelegate){_configureServices.Add(configureDelegate);return this;}public IHostBuilder UseServiceProviderFactoryTContainerBuilder(IServiceProviderFactoryTContainerBuilder factory){_others.Add(builder  builder.UseServiceProviderFactory(factory));return this;}public IHostBuilder UseServiceProviderFactoryTContainerBuilder(FuncHostBuilderContext, IServiceProviderFactoryTContainerBuilder factory){_others.Add(builder  builder.UseServiceProviderFactory(factory));return this;}public IHostBuilder ConfigureContainerTContainerBuilder(ActionHostBuilderContext, TContainerBuilder configureDelegate){_others.Add(builder  builder.ConfigureContainer(configureDelegate));return this;}internal void Apply(IHostBuilder hostBuilder, ConfigurationManager configuration,IServiceCollection services, out HostBuilderContext builderContext){// 初始化针对宿主的配置var hostConfiguration  new ConfigurationManager();_configureHostConfigurations.ForEach( it  it(hostConfiguration));// 创建承载环境var environment  new HostingEnvironment(){ApplicationName  hostConfiguration[HostDefaults.ApplicationKey],EnvironmentName  hostConfiguration[HostDefaults.EnvironmentKey] ?? Environments.Production,ContentRootPath  HostingPathResolver.ResolvePath(hostConfiguration[HostDefaults.ContentRootKey])};environment.ContentRootFileProvider  new PhysicalFileProvider(environment.ContentRootPath);// 创建HostBuilderContext上下文var hostContext  new HostBuilderContext(Properties){Configuration  hostConfiguration,HostingEnvironment  environment,};// 将针对宿主的配置添加到ConfigurationManager中configuration.AddConfiguration(hostConfiguration, true);// 初始化针对应用的配置_configureAppConfigurations.ForEach( it  it(hostContext, configuration));// 收集服务注册_configureServices.ForEach( it  it(hostContext, services));// 将针对依赖注入容器的设置应用到指定的IHostBuilder对象上_others.ForEach(it  it(hostBuilder));// 将自定义属性转移到指定的IHostBuilder对象上foreach (var kv in Properties){hostBuilder.Properties[kv.Key]  kv.Value;}builderContext  hostContext;} }除了Build方法IHostBuilder接口中定义的所有方法的参数都是委托所以实现的这些方法将提供的委托收集起来。在Apply方法中我们通过执行这些委托对象将初始化设置应用到指定的IServiceCollection、ConfigurationManager和IHostBuilder对象上并根据初始化宿主配置构建出代表承载环境的HostingEnvironment对象。该方法最后根据承载环境结合配置将HostBuilderContext上下文创建出来并以输出参数的形式返回。internal static class HostingPathResolver {public static string ResolvePath(string? contentRootPath)  ResolvePath(contentRootPath, .BaseDirectory);public static string ResolvePath(string? contentRootPath, string basePath)  string.IsNullOrEmpty(contentRootPath)? Path.GetFullPath(basePath): Path.IsPathRooted(contentRootPath)? Path.GetFullPath(contentRootPath): Path.GetFullPath(Path.Combine(Path.GetFullPath(basePath), contentRootPath)); }2. ConfigureHostBuilderConfigureHostBuilder是在应用了BootstrapHostBuilder收集的初始化设置之后创建的在创建该对象时提供了HostBuilderContext上下文 ConfigurationManager和IServiceCollection对象。提供的服务注册直接添加到IServiceCollection对象中针对配置的设置已经应用到ConfigurationManager对象直接针对IHostBuilder对象的设置则利用_configureActions字段暂存起来。public class ConfigureHostBuilder : IHostBuilder {private readonly ConfigurationManager _configuration;private readonly IServiceCollection _services;private readonly HostBuilderContext _context;private readonly ListActionIHostBuilder _configureActions  new();internal ConfigureHostBuilder(HostBuilderContext context, ConfigurationManager configuration, IServiceCollection services){_configuration  configuration;_services  services;_context  context;}public IDictionaryobject, object Properties  _context.Properties;public IHost Build()  throw new NotImplementedException();public IHostBuilder ConfigureAppConfiguration(ActionHostBuilderContext, IConfigurationBuilder configureDelegate) Configure(()  configureDelegate(_context, _configuration));public IHostBuilder ConfigureHostConfiguration(ActionIConfigurationBuilder configureDelegate){var applicationName  _configuration[HostDefaults.ApplicationKey];var contentRoot  _context.HostingEnvironment.ContentRootPath;var environment  _configuration[HostDefaults.EnvironmentKey];configureDelegate(_configuration);// 与环境相关的三个配置不允许改变Validate(applicationName, HostDefaults.ApplicationKey, Application name cannot be changed.);Validate(contentRoot, HostDefaults.ContentRootKey, Content root cannot be changed.);Validate(environment, HostDefaults.EnvironmentKey, Environment name cannot be changed.);return this;void Validate(string previousValue, string key, string message){if (!string.Equals(previousValue, _configuration[key], StringComparison.OrdinalIgnoreCase)){throw new NotSupportedException(message);}}}public IHostBuilder ConfigureServices(ActionHostBuilderContext, IServiceCollection configureDelegate) Configure(()  configureDelegate(_context, _services));public IHostBuilder UseServiceProviderFactoryTContainerBuilder(IServiceProviderFactoryTContainerBuilder factory) Configure(()  _configureActions.Add(b  b.UseServiceProviderFactory(factory)));public IHostBuilder UseServiceProviderFactoryTContainerBuilder(FuncHostBuilderContext, IServiceProviderFactoryTContainerBuilder factory) Configure(()  _configureActions.Add(b  b.UseServiceProviderFactory(factory)));public IHostBuilder ConfigureContainerTContainerBuilder(ActionHostBuilderContext, TContainerBuilder configureDelegate) Configure(()  _configureActions.Add(b  b.ConfigureContainer(configureDelegate)));private IHostBuilder Configure(Action configure){configure();return this;}internal void Apply(IHostBuilder hostBuilder)  _configureActions.ForEach(op  op(hostBuilder)); }WebApplicationBuilder对象一旦被创建出来后针对承载环境的配置是不能改变的所以ConfigureHostBuilder的ConfigureHostConfiguration方法针对此添加了相应的验证。两个UseServiceProviderFactory方法和ConfigureContainer方法针对依赖注入容器的设置最终需要应用到IHostBuilder对象上所以我们将方法中提供的委托对象利用configureActions字段存起来并最终利用Apply方法应用到指定的IHostBuilder对象上。3. ConfigureWebHostBuilderConfigureWebHostBuilder同样是在应用了BootstrapHostBuilder提供的初始化设置后创建的创建该对象时能够提供WebHostBuilderContext上下文和承载配置和服务注册的ConfigurationManager和IServiceCollection对象。由于IWebHostBuilder接口定义的方法只涉及服务注册和针对配置的设置所以方法提供的委托对象可以直接应用到这两个对象上。public class ConfigureWebHostBuilder : IWebHostBuilder, ISupportsStartup {private readonly WebHostBuilderContext _builderContext;private readonly IServiceCollection _services;private readonly ConfigurationManager _configuration;public ConfigureWebHostBuilder(WebHostBuilderContext builderContext, ConfigurationManager configuration, IServiceCollection services){_builderContext  builderContext;_services  services;_configuration  configuration;}public IWebHost Build()  throw new NotImplementedException();public IWebHostBuilder ConfigureAppConfiguration(ActionWebHostBuilderContext, IConfigurationBuilder configureDelegate)  Configure(()  configureDelegate(_builderContext, _configuration));public IWebHostBuilder ConfigureServices(ActionIServiceCollection configureServices)  Configure(()  configureServices(_services));public IWebHostBuilder ConfigureServices(ActionWebHostBuilderContext, IServiceCollection configureServices)  Configure(()  configureServices(_builderContext, _services));public string? GetSetting(string key)  _configuration[key];public IWebHostBuilder UseSetting(string key, string? value)  Configure(()  _configuration[key]  value);IWebHostBuilder ISupportsStartup.UseStartup(Type startupType)  throw new NotImplementedException();IWebHostBuilder ISupportsStartup.UseStartupTStartup(FuncWebHostBuilderContext, TStartup startupFactory)  throw new NotImplementedException();IWebHostBuilder ISupportsStartup.Configure(ActionIApplicationBuilder configure)  throw new NotImplementedException();IWebHostBuilder ISupportsStartup.Configure(ActionWebHostBuilderContext, IApplicationBuilder configure)  throw new NotImplementedException();private IWebHostBuilder Configure(Action configure){configure();return this;} }我们在前面说过传统承载方式将初始化操作定义在注册的Startup类型的编程方式在Minima API中已经不再被支持了所以WebApplicationBuilder本不该实现ISupportsStartup接口但是我们希望用户在采用这种编程方式时得到显式的提醒所以依然让它实现该接口并在实现的方法中抛出NotImplementedException类型的异常。4. WebApplicationBuilder如下的代码片段模拟了WebApplicationBuilder针对WebApplication的构建。它的构造函数会创建一个BootstrapHostBuilder对象调用它的ConfigureDefaults和ConfigureWebHostDefaults扩展方法将初始化设置收集起来。ConfigureWebHostDefaults方法会利用提供的ActionIWebHostBuilder委托进行中间件的注册由于中间件的注册被转移到WebApplication对象上并且它提供了一个BuildRequestDelegate方法返回由注册中间件组成的管道所以在这里只需调用构建的WebApplication对象通过_application字段表示虽然此时尚未创建但是中间件真正被注册时会被创建出来的这个方法并将返回的RequestDelegate对象作为参数调用IApplicationBuilder接口的Run方法将中间件管道注册为请求处理器。public class WebApplicationBuilder {private readonly HostBuilder _hostBuilder  new HostBuilder();private WebApplication _application;public ConfigurationManager Configuration { get; }   new ConfigurationManager();public IServiceCollection Services { get; }   new ServiceCollection();public IWebHostEnvironment Environment { get; }public ConfigureHostBuilder Host { get; }public ConfigureWebHostBuilder WebHost { get; }public ILoggingBuilder Logging { get; }public WebApplicationBuilder(WebApplicationOptions options){//创建BootstrapHostBuilder并利用它收集初始化过程中设置的配置、服务和针对依赖注入容器的设置var args  options.Args;var bootstrap  new BootstrapHostBuilder();bootstrap.ConfigureDefaults(null).ConfigureWebHostDefaults(webHostBuilder  webHostBuilder .Configure(app  app.Run(_application.BuildRequestDelegate()))).ConfigureHostConfiguration(config  {// 添加命令行配置源if (args?.Any()  true){config.AddCommandLine(args);}// 将WebApplicationOptions配置选项转移到配置中Dictionarystring, string? settings  null;if (options.EnvironmentName is not null)  (settings ?? new())[HostDefaults.EnvironmentKey]    options.EnvironmentName;if (options.ApplicationName is not null)   (settings ?? new())[HostDefaults.ApplicationKey]    options.ApplicationName;if (options.ContentRootPath is not null)   (settings ?? new())[HostDefaults.ContentRootKey]    options.ContentRootPath;if (options.WebRootPath is not null)   (settings ?? new())[WebHostDefaults.WebRootKey]    options.EnvironmentName;if (settings ! null){config.AddInMemoryCollection(settings);}});// 将BootstrapHostBuilder收集到配置和服务转移到Configuration和Services上// 将应用到BootstrapHostBuilder上针对依赖注入溶质的设置转移到_hostBuilder上// 得到BuilderContext上下文bootstrap.Apply(_hostBuilder, Configuration,  Services, out var builderContext);// 如果提供了命令行参数在Configuration上添加对应配置源if (options.Args?.Any()  true){Configuration.AddCommandLine(options.Args);}// 构建WebHostBuilderContext上下文// 初始化Host、WebHost和Logging属性var webHostContext  (WebHostBuilderContext)builderContext  .Properties[typeof(WebHostBuilderContext)];Environment  webHostContext.HostingEnvironment;Host  new ConfigureHostBuilder( builderContext, Configuration, Services);WebHost  new ConfigureWebHostBuilder( webHostContext, Configuration, Services);Logging  new LogginigBuilder(Services);}public WebApplication Build(){// 将ConfigurationManager的配置转移到_hostBuilder_hostBuilder.ConfigureAppConfiguration(builder {builder.AddConfiguration(Configuration);foreach (var kv in  ((IConfigurationBuilder)Configuration).Properties){builder.Properties[kv.Key]  kv.Value;}});// 将添加的服务注册转移到_hostBuilder_hostBuilder.ConfigureServices((_, services) {foreach (var service in Services){services.Add(service);}});// 将应用到Host属性上的设置转移到_hostBuilderHost.Apply(_hostBuilder);// 利用_hostBuilder构建的IHost对象创建WebApplicationreturn _application  new WebApplication(_hostBuilder.Build());} }接下来BootstrapHostBuilder的ConfigureHostConfiguration方法被调用我们利用它将提供的WebApplicationOptions配置选项转移到BootstrapHostBuilder针对宿主的配置上。针对IHostBuilder初始化设置应用到BootstrapHostBuilder对象上之后我们调用其Apply方法将这些设置分别转移到承载服务注册和配置的IServiceCollection和ConfigurationManager对象以及封装的HostBuilder对象上。Apply方法利用输出参数提供了HostBuilderContext上下文我们进一步从中提取出WebHostBuilderContext上下文GenericWebHostBuilder会将构建的WebHostBuilderContext上下文置于HostBuilderContext对象的属性字典中。我们利用这个上下文将ConfigureHostBuilder和ConfigureWebHostBuilder对象创建出来并作为Host和WebHost属性。用于对日志做进一步设置的Logging属性也在这里被初始化返回的LoggingBuilder对象仅仅是对IServiceCollection对象的简单封装而已。构建WebApplication对象的Build方法分别调用ConfigureAppConfiguration和ConfigureServices方法将ConfigurationManager和IServiceCollection对象承载的配置和服务注册转移到HostBuilder对象上。它接下来提取出Host属性返回的ConfigureHostBuilder对象并调用其Apply方法将应用在该对象上针对依赖注入容器的设置转移到HostBuilder对象上。至此所有的设置全部转移到了HostBuilder对象上我们调用其Build方法构建出对应的IHost对象后最后利用后者将代码承载应用的WebApplication对象构建出来。我们将这个对象赋值到_application字段上前面调用ConfigureWebHostDefaults扩展方法提供的委托会将它的BuildRequestDelegate方法构建的中间件管道作为请求处理器。四、 工厂方法代表承载应用的WebApplication对象由WebApplicationBuilder构建的但是我们一般不会通过调用构造函数的方式来创建WebApplicationBuilder对象这有违“面向接口”编程的原则所以我们都会使用WebApplication类型提供的静态工厂方法来创建它。WebApplication除了提供了三个用于创建WebApplicationBuilder的CreateBuilder方法重载还提供了一个直接创建WebApplication对象的Create方法。public sealed class WebApplication {public static WebApplicationBuilder CreateBuilder()  new WebApplicationBuilder(new WebApplicationOptions());public static WebApplicationBuilder CreateBuilder(string[] args){var options  new WebApplicationOptions();options.Args  args;return new WebApplicationBuilder(options);}public static WebApplicationBuilder CreateBuilder(WebApplicationOptions options)  new WebApplicationBuilder(options, null);public static WebApplication Create(string[]? args  null){var options  new WebApplicationOptions();options.Args  args;return new WebApplicationBuilder(options).Build();} }本节内容通过针对WebApplication和WebApplicationBuilder这两个类型的实现模拟来讲解Minimal API的实现原理。一方面为了让讲解更加清晰另一方面也出于篇幅的限制不得不省去很多细枝末节的内容但是设计思想和实现原理别无二致。上面提供的源代码也不是伪代码如下所示的就是在“模拟的Minimal API”构建的ASP.NET Core应用它是可以正常运行的。如果读者朋友们对真实的实现感兴趣可以将它作为一个“向导”去探寻“真实的Minimal API”。var app  App.WebApplication.Create(); app.Run(httpContext  httpContext.Response.WriteAsync(Hello World!)); app.Run();
http://www.pierceye.com/news/772094/

相关文章:

  • 郴州网站设计公司阜新网站设计
  • 成都网站制作中国互联个人做电影网站赚钱吗
  • 如何做自己的影视网站惠州惠城网站建设
  • 温州网站推广外包推推蛙网站建设
  • 北京百度网站排名优化四川公共资源交易网招标网
  • 上海网站制作商多用户网上商城
  • 四川建设网电子招投标网站莱芜金点子电话
  • 深圳科技网站建设网站怎么做跳站
  • 做网站需要多少人全国物流货运平台
  • 温州建网站用自己的电脑做网站
  • 综合性门户网站有哪些高端网站建设 房产
  • 百度做的网站能优化吗如何在jsp上做网站页面代码
  • 广州市品牌网站建设公司营销型网站开发推广
  • 甜品网站首页设计用php做的网站模版
  • 怎样做企业的网站百度下载安装免费版
  • 常州市网站优化汕头网站建设和运营
  • wordpress 同分类评论调用seo排名是什么
  • 网站建设推广怎么玩软件开发模型是什么
  • 网站开发报价表格海口注册公司代理公司地址电话
  • 西宁好的网站建设视频网站文案
  • 郑州网站优化网络建设有限公司网站建设 交单流程
  • 网站搬家内页打不开重庆市建设工程信息网怎么进不去
  • 深圳 做公司网站网站用什么建设
  • 网站更换空间对优化的影响营销号视频生成器手机版
  • 南宁大型网站推广公司昆山网站制作哪家好
  • 格尔木哪里有做网站的wordpress编辑器排版
  • 怎样开电商襄阳抖音seo找哪家
  • 个人网站 域名舞阳专业做网站
  • 做国外购物网站凤山网站seo
  • 苏州制作网站的有几家WordPress文章编辑链接