zoukankan      html  css  js  c++  java
  • web api 起步之一

    最近计划开始搭建asp.net core 的web api环境,我想把实验过程中的一些主要关键点记录下来,以备将来时间长了忘记的时候还有地方可以参考.

    开始之前,我们需要建立以下的概念:

    1.ORM  如dapper

    2.面向接口 interface driver design

    3.控制反转Ioc与依赖注入DI 如Autofac 微软自带的DI,在实验中,我们用Autofac来替代DI

    一  开发环境

    VS2019 + .net core 3.1 sdk

    二 建立项目

    1. asp.net core web 项目

    2. web api

    3. 启用docker支持

    三  添加swagger支持

    1. Nuget 中加入以下package

        Swashbuckle.AspNetCore.Swagger

        Swashbuckle.AspNetCore.SwaggerGen

        Swashbuckle.AspNetCore.SwaggerUI

        Microsoft.Extensions.PlatformAbstractions(非必须)

    2. 添加并配置 Swagger 中间件

      1) 重点在于startup.cs里面的配置。

          参考文章:ASP.NET Core WebApi使用Swagger生成api说明文档看这篇就够了 

      2) 如果controller中的某个action不想显示 出来,标示attribute[NonAction]

      3) 如果整 个Controller都不想显示,标示attribute[ApiexplorerSettings(Ignore=true)]

    四 新建一个.net standard 类库(.net standard 类库)

     1.名称:APIStarter.Service

     2. 新建文件夹:  IService  并建立一个接口文件 ILoginService.cs;

     3. 新建文件夹: Service 并建立一个类LoginService.cs 实现上面的接口,关注ALT+Enter键的使用,会带来很多方便。

    五 用Autofac 来替代自带的DI

    1 Nuget 安装 包 : 

       a. Autofac    b. Autofac.Extensions.DependencyInjection  c.Zq.SQLBuilder.Core(封装了对多种数据库的dapper操作)

    2 参考文章

       NET Core 3.0 AutoFac替换内置DI的新姿势  

    3 重点代码(注释的代码是.net core 2.x的写法)

      startup.cs   

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Threading.Tasks;
    using System.IO;
    using Microsoft.AspNetCore.Builder;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Configuration;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.Hosting;
    using Microsoft.OpenApi.Models;
    using Microsoft.Extensions.Logging;
    using Swashbuckle.AspNetCore.Swagger;
    using Swashbuckle.AspNetCore.SwaggerGen;
    using Microsoft.Extensions.PlatformAbstractions;
    using Autofac;
    using SQLBuilder.Core.Configuration;
    using SQLBuilder.Core.Repositories;
    using System.Reflection;
    using Autofac.Extensions.DependencyInjection;
    
    namespace APIStarter
    {
        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.AddControllers();
                //swagger依赖于MVC
                services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
                //添加 Swagger 生成器
                services.AddSwaggerGen(option =>
                {
                    option.SwaggerDoc("v1", new OpenApiInfo()
                    {
                        Title = "Martin API",
                        Version = "v1.0",
                        Contact = new OpenApiContact() { Name = "湖东", Email = "36323732@qq.com" }
                    });
    
                    var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                    var xmlPath = Path.Combine(basePath, "APIStarter.xml");
                    option.IncludeXmlComments(xmlPath, true);
                });
            }

    //public IServiceProvider ConfigureServices(IServiceCollection services) //{ // services.AddControllers(); // //swagger依赖于MVC // services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0); // //添加 Swagger 生成器 // services.AddSwaggerGen(option => // { // option.SwaggerDoc("v1", new OpenApiInfo() // { // Title = "Martin API", // Version = "v1.0", // Contact = new OpenApiContact() { Name = "湖东", Email = "36323732@qq.com" } // }); // var basePath = PlatformServices.Default.Application.ApplicationBasePath; // var xmlPath = Path.Combine(basePath, "APIStarter.xml"); // option.IncludeXmlComments(xmlPath, true); // }); // return RegisterAutofac.ForRegisterAutofac(services); //} // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.UseRouting(); //app.UseMvc(); //启用中间件服务生成Swagger作为JSON终结点 app.UseSwagger(); //启用中间件服务对swagger-ui,指定Swagger JSON终结点 app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "Martin API V1"); c.RoutePrefix = "api"; }); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); } public void ConfigureContainer(ContainerBuilder builder) { //添加依赖注入关系 builder.RegisterModule(new AutofacModuleRegister()); var controllerBaseType = typeof(ControllerBase); //在控制器中使用依赖注入 builder.RegisterAssemblyTypes(typeof(Program).Assembly) .Where(t => controllerBaseType.IsAssignableFrom(t) && t != controllerBaseType) .PropertiesAutowired(); } }
    public class AutofacModuleRegister : Autofac.Module
        {       
            protected override void Load(ContainerBuilder builder)
            {
    
                //程序集范围注入
                Assembly assembly = GetAssemblyByName("APIStarter.Service");
                builder.RegisterAssemblyTypes(assembly)
                     .Where(t => t.Name.EndsWith("Service"))
                     .AsImplementedInterfaces().PropertiesAutowired();
    
                

                   //加载配置文件这一段代码很重要,否则无法读取到appsettings.json中的配置信息
                   var basePath = PlatformServices.Default.Application.ApplicationBasePath; 
                   var configPath = Path.Combine(basePath, "appsettings.json");
                   ConfigurationManager.SetConfigurationFile(configPath);

                //循环注册多个数据库
                var ConnectionStrings = ConfigurationManager.Configuration.GetSection("ConnectionStrings").GetChildren();
                foreach(var item in ConnectionStrings)
                {
                    var split = item.Key.Split('#');
                    string DBType = split[0].ToUpper();
                    string DBName = split[1].ToUpper();
                    switch(DBType)
                    {
                        case "SQLSERVER":
                            builder.Register(c=>new SqlRepository(item.Value)).Named<IRepository>(DBName);
                            break;
                        case "ORACLE":
                            builder.Register(c=>new OracleRepository(item.Value)).Named<IRepository>(DBName);
                            break;
                        case "MYSQL":
                            builder.Register(c => new MySqlRepository(item.Value)).Named<IRepository>(DBName);
                            break;
                        default:
                            break;
                    }
                }
    
                //单个注册
                //builder.RegisterType<EmployeeSercice>().As<IEmployeeService>().PropertiesAutowired();
    
                //在控制器中使用属性依赖注入,其中注入属性必须标注为public
                //var controllersTypesInAssembly = typeof(Startup).Assembly.GetExportedTypes()
                //.Where(type => typeof(Microsoft.AspNetCore.Mvc.ControllerBase).IsAssignableFrom(type)).ToArray();
                //builder.RegisterTypes(controllersTypesInAssembly).PropertiesAutowired();
            }
    
            /// <summary>
            /// 根据程序集名称获取程序集
            /// </summary>
            /// <param name="AssemblyName">程序集名称</param>
            public static Assembly GetAssemblyByName(String AssemblyName)
            {
                return Assembly.Load(AssemblyName);
            }
        }

      program.cs (注释的代码是没有使用 Autofac之前的代码)

    //public static IHostBuilder CreateHostBuilder(string[] args) =>
            //    Host.CreateDefaultBuilder(args)
            //        .ConfigureWebHostDefaults(webBuilder =>
            //        {
            //            webBuilder.UseStartup<Startup>();
            //        });
            public static IHostBuilder CreateHostBuilder(string[] args) =>
               Host.CreateDefaultBuilder(args)
                   .ConfigureWebHostDefaults(webBuilder =>
                   {
                       webBuilder.UseStartup<Startup>();
                   })
          .UseServiceProviderFactory(new AutofacServiceProviderFactory());
        }
    }

     六  Swagger下简单的给WebApi分组

    1. Startup.cs下ConfigureServices代码,这里主要在DocInclusionPredicate控制输出那些api。

    //添加 Swagger 生成器
                services.AddSwaggerGen(option =>
                {
                    option.SwaggerDoc("V1", new OpenApiInfo()
                    {
                        Title = "Martin API",
                        Description = "Default",
                        Version = "v1.0",
                        Contact = new OpenApiContact() { Name = "湖东", Email = "36323732@qq.com" }
    
                    });
    
                    option.SwaggerDoc("Auth",new OpenApiInfo() { 
                       Title = "Auth API",
                       Description = "Auth API",
                       Version = "v1.0",
                       Contact = new OpenApiContact() { Name = "湖东", Email = "36323732@qq.com" }
                    });
    
                    option.SwaggerDoc("Login", new OpenApiInfo()
                    {
                        Title = "Login API",
                        Description = "Login API",
                        Version = "v1.0",
                        Contact = new OpenApiContact() { Name = "湖东", Email = "36323732@qq.com" }
                    });
    
                    option.DocInclusionPredicate((docName, apiDesc) =>
                    {
                        if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
                        var versions = methodInfo.DeclaringType
                           .GetCustomAttributes(true)
                           .OfType<ApiExplorerSettingsAttribute>()
                           .Select(attr => attr.GroupName);
                        if(docName.ToLower()=="v1" && versions.FirstOrDefault()==null)
                        {
                            return true;
                        }
                        return versions.Any(v => v.ToString() == docName);
                    });
    
                    var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                    var xmlPath = Path.Combine(basePath, "APIStarter.xml");
                    option.IncludeXmlComments(xmlPath, true);
                });

    2.  Startup.cs下Configure代码

     //启用中间件服务生成Swagger作为JSON终结点
                app.UseSwagger(c=>
                {
                    c.RouteTemplate = "swagger/{documentName}/swagger.json";
                
                });
                //启用中间件服务对swagger-ui,指定Swagger JSON终结点
                app.UseSwaggerUI(c =>
                {
                    c.SwaggerEndpoint("/swagger/V1/swagger.json", "Martin API V1");
                    c.SwaggerEndpoint("/swagger/Auth/swagger.json", "认证服务:Auth API ");
                    c.SwaggerEndpoint("/swagger/Login/swagger.json", "登录服务: Login API");
    
                    c.RoutePrefix = "api";
                });

    3. 给Controllers或Action添加[ApiExplorerSettings(GroupName= "ApiGroupName")]

        [ApiExplorerSettings(GroupName = "Auth")]
        [ApiController]
        [Route("api/[controller]")]
        public class AuthController : BaseController

     七. 添加Area 区域(为了方便API的管理)

    1. 新建目录Areas

    2. 在Area上右键,新建区域

    3. 删除 Data/Models/Views目录,保留Controllers目录

    4. startup.cs 文件中的Configure方法

    //启用Areas
                app.UseEndpoints(endpoints =>
                {
                    endpoints.MapControllerRoute(
                     name: "default",
                     pattern: "{controller=Auth}/{action=Login}/{id?}");
    
                    endpoints.MapControllerRoute(
                      name: "Area",
                      pattern: "{area:exists}/{controller=Auth}/{action=Login}/{id?}");
                });

    八. swagger增强:从appsettings.json中读取配置信息

    1.修改生成xml文件的路径

       在每个项目上点右键--属性--生成--勾选XML文档文件, 路径使用相对路径(如:..XmlDocAPIStarter.xml)

      新建一个Class: SwaggerConfig.cs  与 appsettings.json中的配置信息相对应

    using System;
    using System.Collections.Generic;
    using System.Text;
    
    namespace APIStarter.Dtos.Common
    {
        public class SwaggerConfig
        {
            public string XmlDocPath { get; set; }
            public Dictionary<string,string> ApiDoc { get; set; }
        }
    }

    2.appsettings.json

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*",
      "ConnectionStrings": {
        "SqlServer#DB_USER": "Server=192.168.1.5;Database=Study;uid=sa;pwd=g3@py3hd",
        "Oracle#DB_WMS": "",
        "Oracle#DB_COST": ""
      },
      "SwaggerConfig": {
        "XmlDocPath": "..\XmlDoc",
        "ApiDoc": {
          "AuthManager": "认证管理",
          "UserManager": "用户管理"
        }
      }
    }

    3.Program.cs 

     public static IHostBuilder CreateHostBuilder(string[] args)
            {
                var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                var Configuration = new ConfigurationBuilder().SetBasePath(basePath)
                    .AddJsonFile("appsettings.json")
                    .Build();
                return Host.CreateDefaultBuilder(args)
                     .ConfigureWebHostDefaults(webBuilder =>
                      {
                          webBuilder.UseConfiguration(Configuration);   
                          webBuilder.UseStartup<Startup>();
                      })
                     .UseServiceProviderFactory(new AutofacServiceProviderFactory());
    
            }

    4. startup.cs  也要做调整

    (a) ConfigureServices

    //添加 Swagger 生成器 (从appsettings.json中配置)
                services.AddSwaggerGen(option =>
                {
                    var SwaggerConfig = Configuration.GetSection("SwaggerConfig").Get<SwaggerConfig>();
                    foreach( var item in SwaggerConfig.ApiDoc)
                    {
                        option.SwaggerDoc(item.Key, new OpenApiInfo()
                        {
                            Version = item.Value,
                            Title   = "API_"+item.Value,                      
                            Contact = new OpenApiContact() { Name = "湖东", Email = "36323732@qq.com" }
                        });
                    }                           
    
                    option.DocInclusionPredicate((docName, apiDesc) =>
                    {
                        if (!apiDesc.TryGetMethodInfo(out MethodInfo methodInfo)) return false;
                        var versions = methodInfo.DeclaringType
                           .GetCustomAttributes(true)
                           .OfType<ApiExplorerSettingsAttribute>()
                           .Select(attr => attr.GroupName);
                        if (docName.ToLower() == "v1" && versions.FirstOrDefault() == null)
                        {
                            return true;
                        }
                        return versions.Any(v => v.ToString() == docName);
                    });
    
                    var basePath = PlatformServices.Default.Application.ApplicationBasePath;
                    new DirectoryInfo(SwaggerConfig.XmlDocPath).GetFiles().ToList().ForEach(c=>
                    {
                        var xmlFile = c.FullName;
                        option.IncludeXmlComments(xmlFile, true);
                    });
    
                });

    (b) Configure

     var SwaggerConfig = Configuration.GetSection("SwaggerConfig").Get<SwaggerConfig>();
                //启用中间件服务对swagger-ui,指定Swagger JSON终结点 (从配置文件中读取)
                app.UseSwaggerUI(c =>
                {
                    foreach(var item in SwaggerConfig.ApiDoc)
                    {
                        c.SwaggerEndpoint($"/swagger/{item.Key}/swagger.json", item.Value);
                    }
                    c.RoutePrefix = "api";
                });

    (3) AutofacModuleRegister :因为在内部要读取配置文件,所以在构造函数中注入IConfiguration

    public class AutofacModuleRegister : Autofac.Module
        {
            private readonly IConfiguration Configuration;
    
            //因为在内部要读取配置文件,所以在构造函数中注入IConfiguration
            public AutofacModuleRegister(IConfiguration configuration)
            {
                Configuration = configuration;
            }
    
            protected override void Load(ContainerBuilder builder)
            {
    
                //程序集范围注入
                Assembly assembly = GetAssemblyByName("APIStarter.Service");
                builder.RegisterAssemblyTypes(assembly)
                     .Where(t => t.Name.EndsWith("Service"))
                     .AsImplementedInterfaces().PropertiesAutowired();
    
                //加载配置文件这一段代码要注意
                //循环注册多个数据库
                var ConnectionStrings = Configuration.GetSection("ConnectionStrings").Get<Dictionary<string, string>>();
                foreach (var item in ConnectionStrings)
                {
                    var split = item.Key.Split('#');
                    string DBType = split[0].ToUpper();
                    string DBName = split[1].ToUpper();
                    switch(DBType)
                    {
                        case "SQLSERVER":
                            builder.Register(c=>new SqlRepository(item.Value)).Named<IRepository>(DBName);
                            break;
                        case "ORACLE":
                            builder.Register(c=>new OracleRepository(item.Value)).Named<IRepository>(DBName);
                            break;
                        case "MYSQL":
                            builder.Register(c => new MySqlRepository(item.Value)).Named<IRepository>(DBName);
                            break;
                        default:
                            break;
                    }
                }
    
                //单个注册
                //builder.RegisterType<EmployeeService>().As<IEmployeeService>().PropertiesAutowired();
    
            }
    
            /// <summary>
            /// 根据程序集名称获取程序集
            /// </summary>
            /// <param name="AssemblyName">程序集名称</param>
            public static Assembly GetAssemblyByName(String AssemblyName)
            {
                return Assembly.Load(AssemblyName);
            }
        }
    }
  • 相关阅读:
    谈软件开发工具的选择
    Windows下搭建Octopress博客
    Aspose Word模版使用总结篇2带示例
    强大的二分查找法(Binary Search)
    GhostDoc Pro v4.5.13017专业破解版本
    超炫的开源 JavaScript 物理引擎
    CQRS + DDD + MDP 实现快速应用程序开发
    数据结构之栈(Stack)与队列(Queue)
    插件框架实现
    集成服务监控器green.monitor发布
  • 原文地址:https://www.cnblogs.com/yuchsheng/p/13972668.html
Copyright © 2011-2022 走看看