CloudYxt.Api 4.1.3

dotnet add package CloudYxt.Api --version 4.1.3                
NuGet\Install-Package CloudYxt.Api -Version 4.1.3                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CloudYxt.Api" Version="4.1.3" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add CloudYxt.Api --version 4.1.3                
#r "nuget: CloudYxt.Api, 4.1.3"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install CloudYxt.Api as a Cake Addin
#addin nuget:?package=CloudYxt.Api&version=4.1.3

// Install CloudYxt.Api as a Cake Tool
#tool nuget:?package=CloudYxt.Api&version=4.1.3                

云享通.Net Core针对WEBAPI常规操作库

一个常见的Startup.cs的Swagger相关定义示例

public void ConfigureServices(IServiceCollection services)
{
    //使用NewtonsoftJson加载API接口
    services.AddControllers().AddNewtonsoftJson((opt) =>
    {
        //json字符串大小写原样输出
        opt.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver();
    });

    //设置接收文件长度的最大值。
    services.Configure<Microsoft.AspNetCore.Http.Features.FormOptions>(x =>
    {
        x.ValueLengthLimit = int.MaxValue;
        x.MultipartBodyLengthLimit = int.MaxValue;
        x.MultipartHeadersLengthLimit = int.MaxValue;
        x.MultipartBoundaryLengthLimit = int.MaxValue;
    });

    //全局拦截模型错误
    services.Configure<ApiBehaviorOptions>(options =>
    {
        options.InvalidModelStateResponseFactory = ApiHelperExtend.ApiMessageInvalidModelState;
    });

    services.AddSwaggerGen(c =>
    {
        c.SwaggerDoc("CloudYxtTestApi", new OpenApiInfo()
        {
            Title = "CloudYxtTestApi",
            Version = "v2",
            Description = "Api测试",
        });

        //类似JWT的认证模型
        c.AddSecurityDefinition("Authorization", new Microsoft.OpenApi.Models.OpenApiSecurityScheme()
        {
            Description = "在下框中输入请求头中需要添加授权信息,格式:“{协议版本} {token}”(注意两者之间是一个空格)",
            Name = "Authorization",
            In = Microsoft.OpenApi.Models.ParameterLocation.Header,
            Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey
        });

        //加载ApiMessageAuthorization认证的过滤器(当方法含有ApiMessageAuthorization时才出现锁)
        c.OperationFilter<ApiMessageAuthorizationSwaggerFilter>("Authorization");
        //使用DescriptionAttribute作为Description说明
        c.UseDescriptionAttributeAsTagDescription();

        //属性名称使用模型的完整名称
        //c.CustomSchemaIds(type => type.FullName); 
        //仅显示属性名称
        //c.SchemaFilter<PropertyOnlySchemaFilter>();

        //加载目录下的xml注释文件
        var xmlfiles = new DirectoryInfo(AppContext.BaseDirectory).GetFiles("*.xml");
        foreach (var file in xmlfiles)
            c.IncludeXmlComments(file.FullName);
    });
    //**重要:新版本swagger务必使用此方法校正**
    services.AddSwaggerGenNewtonsoftSupport();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.Use(async (ctx, next) =>
    {
        ctx.Request.EnableBuffering();
        await next();
    });

    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    //全局跨域支持
    app.UseMiddleware<AllowDomainCorsHeaderMiddleware>();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });

    //使用静态文件时
    //app.UseStaticFiles();

    app.UseSwagger(c =>
    {
        c.RouteTemplate = "/{documentName}/swagger.json";
    });
    app.UseSwaggerUI(c =>
    {
        c.DocumentTitle = "测试的应用API";
        c.RoutePrefix = "CloudYxtTestApi/doc";
        c.DocExpansion(Swashbuckle.AspNetCore.SwaggerUI.DocExpansion.List);

        c.SwaggerEndpoint("/CloudYxtTestApi/swagger.json", "CloudYxtTestApi名称");
        c.DefaultModelExpandDepth(4);
    });

}

使用DescriptionAttribute作为Description说明,类似SwaggerTag功能(无需Swashbuckle.AspNetCore.Annotations依赖)

在services.AddSwaggerGen中开启

c.UseDescriptionAttributeAsTagDescription();

支持Controller、方法、模型

[Description("用于test的描述")]
public class testController : Controller 
{
        [HttpGet]
        [Description("用于Hello的描述")]
        public string Hello()
        {
            return "Hello World";
        }

        [HttpPost]
        [Description("用于PostHello的描述")]
        public string PostHello([FromBody]request_Hello request)
        {
            return $"Hello World:{request.name}";
        }
}

public class request_Hello 
{
        /// <summary>
        /// ID
        /// </summary>
        public string id { get; set; }
        
        [Description("用于name的描述")]
        public string name { get; set; }
}_

跨域中间件使用

在Startup的Configure中定义

//支持所有域
app.UseMiddleware<AllowDomainCorsHeaderMiddleware>();

//支持一个域名跨域
app.UseMiddleware<AllowDomainCorsHeaderMiddleware>("https://www.domain1.com");

//支持多个域名跨域
app.UseMiddleware<AllowDomainCorsHeaderMiddleware>("https://www.domain1.com,https://www.domain2.com");

上传文件

/// <summary>
/// 上传演示
/// </summary>
/// <param name="id">使用query参数的id</param>
/// <param name="type">使用form参数的type</param>
/// <param name="fileToUpload">文件的表单名fileToUpload,特别注意此处切勿加“[FromForm]”</param>
/// <returns></returns>
[HttpPost]
public messageData<long> PostUpload([Required][FromQuery] string id, [Required][FromForm] string type, [Required] IFormFile fileToUpload)
{
    return new messageData<long>() { data = fileToUpload.Length };
}

过滤器常见用法

在Startup中定义全局错误拦截

services.Configure<ApiBehaviorOptions>(options =>
{
    options.InvalidModelStateResponseFactory = ApiHelperExtend.ApiMessageInvalidModelState;
});

使用ApiMessageLog时,部分信息记录不到时,可在Startup的Configure中增加buffer回写

app.Use(async (ctx, next) =>
{
    ctx.Request.EnableBuffering();
    await next();
});

定义全局的Controller

[Route("Api/[controller]/[action]")]	//API路由
[ApiController]                         //声明为API控制器
[ApiMessageLog(ApiName = "Api名称")]	//API日志名称
[ApiMessagePackage]                     //使用code、message包装输出结果
public class extController : ControllerBase
{
}

演示的demo控制器,继承自extController

/// <summary>
/// 演示
/// </summary>
[OpenApiTag("demo", Description = "演示")]
public class demoController : extController
{
    /// <summary>
    /// 获取数据,并按code、message包装输出结果
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    public async Task<messageData<response_class>> GetSomething()
    {
        var data = await......;

        if (something wrong) 
        {
            //抛出code、message错误信息
            throw new ApiMessageException(1, "错误提示");
        }

        return new messageData() { data = data };
    }

    /// <summary>
    /// 使用自定义包装、自定义状态码的输出
    /// </summary>
    /// <returns></returns>
    [HttpPost]
    [ApiMessageTException]      //自定义错误message
    [ApiMessagePackageIgnore]   //不使用code、message包装
    public async Task<response_result> PostSomething([Required][FromBody] request_something request)
    {
        var data = await......;

        if (something wrong) 
        {
            //抛出402状态码的错误信息
            throw new ApiMessageTException<response_result>(类实例变量, 402);    //402状态码
        }

        return new response_result();
    }

    /// <summary>
    /// 获取当前服务器时间相对1970-1-1的毫秒数
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    [ApiMessageLogIgnore]       //忽略API日志
    [ApiMessagePackageIgnore]   //忽略使用结果包装
    public string GetMillTimer()
    {
        return $"{DateTime.Now.toMillTimer():F0}";
    }

}

ApiMessageAuthorization权限检测Filter

注意权限检测需加在方法上

权限认证成功后自动编写context.HttpContext.Items["userId"]

默认认证回调检查方法为用户自定义实现protected object mApiAuthorization(string Policy, string Roles, string AuthenticationSchemes, ActionExecutingContext context, string Scheme, string Parameter)

在WEBAPI中可通过User.Identities.FirstOrDefault(m => m.AuthenticationType == "Scheme")?.BootstrapContext获取权限检查成功的用户信息

例:

//权限验证
protected object mApiAuthorization(string Policy, string Roles, string AuthenticationSchemes, ActionExecutingContext context, string Scheme, string Parameter)
{
    //AuthenticationSchemes
    if (!string.IsNullOrEmpty(AuthenticationSchemes) && !AuthenticationSchemes.Split(',').Contains(Scheme))
        throw new ApiMessageException(4020, "不允许的权限协议", $"{Scheme} not in ({AuthenticationSchemes})");

    if (Scheme == "PRC1")
    {
        //验证用户
        var userTag = ......;
        
        return userTag;
    }
    else if (Scheme == "PRC2")
    {
        //验证用户
        var userTag = ......;
        
        return userTag;
    }

    //验证未通过则返回空
    return null;
}

//在API中获取用户信息
private ClaimsIdentity _claims;

/// <summary>
/// 获取当前用户验证的Scheme
/// </summary>
/// <returns></returns>
protected string currentUserScheme()
{
    if (_claims == null)
        _claims = User.Identities.FirstOrDefault(m => m.AuthenticationType == "Scheme");

    if (_claims == null)
        return string.Empty;

    return _claims.NameClaimType;
}

/// <summary>
/// 获取当前用户验证的用户信息
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
protected T currentUserTag<T>()
{
    if (_claims == null)
        _claims = User.Identities.FirstOrDefault(m => m.AuthenticationType == "Scheme");

    if (_claims == null || _claims?.BootstrapContext == null)
        return default(T);

    return (T)_claims?.BootstrapContext;
}

//支持PRC1,PRC2的权限协议,并且Roles为0才可访问
[ApiMessageAuthorization(AuthenticationSchemes = "PRC1,PRC2", Roles = "0")]
public async Task<messageData<response_class>> GetSomething() 
{
    //获取当前用户
    var userTag = currentUserTag<用户类>();
    .....
}

基于HttpContext的扩展

var ip = HttpContext.remoteRealIp(); //来源IP
var from = HttpContext.remoteFrom(); //来源URL
var agent = HttpContext.remoteAgent(); //来源AGENT

NSwag常见定义(已弃用)

services.AddOpenApiDocument(c =>
{
    c.Title = "WebApi";
    c.Version = "v1";
    c.Description = "WebApi说明";

    c.RequireParametersWithoutDefault = true;
    c.DocumentName = c.Title;
    c.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings() { ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver() };

    c.AddSecurity("Authorization", new NSwag.OpenApiSecurityScheme()
    {
        Description = "在下框中输入请求头中需要添加授权信息,格式:“{协议版本} {token}”(注意两者之间是一个空格)",
        Name = "Authorization",
        In = NSwag.OpenApiSecurityApiKeyLocation.Header,
        Type = NSwag.OpenApiSecuritySchemeType.ApiKey
    });

    //将控制器Summary显示为描述
    c.UseControllerSummaryAsTagDescription = true;

    //标记ApiMessageAuthorization为需授权接口
    c.OperationProcessors.Add(new ApiMessageAuthorizationNSwagProcessor("Authorization"));
});
Product Compatible and additional computed target framework versions.
.NET net6.0 is compatible.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 was computed.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.1.3 85 11/14/2024
4.1.2 79 11/13/2024
4.1.1 80 10/21/2024
4.0.3 123 5/17/2024
4.0.1 121 5/16/2024
4.0.0 100 5/15/2024
3.3.4 128 2/29/2024
3.3.1 180 7/31/2023
3.3.0 155 7/19/2023
3.2.1 160 6/29/2023
3.2.0 146 6/28/2023
3.1.1 143 5/6/2023
3.1.0 247 1/31/2023
3.0.1 432 7/25/2022
3.0.0 463 7/14/2022
2.4.8 610 1/21/2022
2.4.7 561 1/20/2022
2.4.6 581 1/20/2022
2.4.5 323 12/24/2021
2.4.4 363 12/1/2021
2.4.3 314 11/29/2021
2.4.2 399 11/12/2021
2.4.1 385 11/12/2021
2.4.0 387 11/12/2021
2.3.3 443 10/25/2021
2.3.2 442 10/20/2021
2.3.1 434 9/10/2021
2.3.0 464 9/10/2021
2.2.1 414 9/10/2021
2.2.0 394 9/9/2021
2.1.0 322 9/7/2021
2.0.0 331 9/3/2021
1.0.1 310 9/2/2021
1.0.0 332 9/2/2021

云享通.Net Core针对WEBAPI常规操作库。

4.1.3
日志记录细节修复

4.1.2
升级Swashbuckle.AspNetCore依赖至7.0

4.1.1
增加依赖Swashbuckle.AspNetCore.Newtonsoft适配Newtonsoft
新增PropertyOnlySchemaFilter可设置基本Gen时只显示类型名称,特别注意需要在services.AddSwaggerGen后添加services.AddSwaggerGenNewtonsoftSupport();

4.0.3
为Swashbuckle.AspNetCore增加[Description("描述")]支持

4.0.1
升级Swashbuckle.AspNetCore依赖至6.6.1

4.0.0
由于NSwag在打包WebApi为单个文件时无法加载xml文件,并且无法指定外部swagger.json,因此将Swagger引擎改为Swashbuckle.AspNetCore

3.3.4
升级NSwag.AspNetCore依赖至14.0.3,及其他细节修正

3.3.1
修正跨域支持OPTIONS响应

3.3
增加以中间件方式支持跨域头的标签

3.2.1
调整当API属性包含ApiMessageTExceptionAttribute时,返回的StatusCode状态码将保持原有400或500状态码,不会转成200正常状态码

3.2
增加ApiMessageTException<T>错误类型,可自定义出错时的Json输出类对象
throw new ApiMessageTException<messageErrorCode>(new messageErrorCode()
   {
       errcode = 10,
       errmsg = "出错啦"
   }, 501);
修复ApiMessagePackageIgnore时也会包装出错结果的BUG
修复ApiMessageLog空body的错误回收

3.1.1
升级nuget,并将ApiMessageLog类型移至CloudYxt.Base包中,以方便处理数据转储

3.1.0
取消对CloudYxt.Models的依赖

3.0.1
增加ApiMessageInfoException错误包装输出方法

3.0.0
升级包目标为.net6,增加remoteRealIp的ipv6支持

2.4.8
增加HttpContext.outputHtml、HttpContext.outputByte的ContentType类型设置

2.4.7
修复await的可返回BUG

2.4.6
增加HttpContext.outputHtml、HttpContext.outputByte用于WebApi直接输出HTML、字节数组到客户端

2.4.5
增加ApiMessagePackage支持Task控制器输出数据流的异常抛出和数据过滤包装,升级nuget版本

2.4.4
增加ApiMessageLog_Ch的入库字段名称序列

2.4.3
增加ApiMessageLog的ClickHouse类型ApiMessageLog_Ch

2.4.2
修复ApiMessagePackageIgnore属性未生效的BUG及日志记录BUG

2.4.0
同步支持CloudYxt.Base

2.3.3
修复当控制器带有动态类参数时日志未完整记录内容的BUG

2.3.2
修复BUG

2.3.1
通过ApiMessageAuthorizationAttribute认证的userId增加返回认证的Scheme

2.3.0
增加InvalidModelStateResponseFactory的ApiMessage处理方法:
services.Configure<ApiBehaviorOptions>(options =>
           {
               options.InvalidModelStateResponseFactory = ApiHelperExtend.ApiMessageInvalidModelState;
           });

注意:若要获取未验证通过的提交内容,务必EnableBuffering:
app.Use(async (ctx, next) =>
           {
               ctx.Request.EnableBuffering();
               await next();
           });

2.2.1
为ApiMessageLogAttribute增加自定义回调方法CallBackMethodName支持

2.2.0
增加权限认证属性[ApiMessageAuthorization]
权限认证成功后自动编写context.HttpContext.Items["userId"]
默认认证回调检查方法为用户自定义实现protected object mApiAuthorization(string Policy, string Roles, string AuthenticationSchemes, ActionExecutingContext context, string Scheme, string Parameter)
在WEBAPI中可通过User.Identities.FirstOrDefault(m => m.AuthenticationType == "Scheme")?.BootstrapContext获取权限检查成功的用户信息

2.1.0
增加无需日志的属性[ApiMessageLogIgnore]
调整回调日志方法mApiLog可为静态方法
context.HttpContext.Items存储的可选扩展字段名为userId、appId、custom

2.0.0
更名ApiMessage属性为ApiMessagePackage
增加ApiMessageLog,其中通用扩展属性字段可使用context.HttpContext.Items["字段名"]传递
例:(注意属性的绑定顺序)
[ApiController]
[ApiMessageLog(ApiName = "myApi")]
[ApiMessagePackage]
public class extController : ControllerBase
   {
       public void mApiLog(ApiMessageLog log)
       {
//由用户实现log的存储
       }

1.0.1
修复一个类型判断时的BUG

1.0.0:
建立基本处理模型。

[ApiMessage] :数据结果进行messageData包装
[ApiMessageException]:拦截API内报错输出为messageData模式

ApiValidationError:模型验证错误类型
services.Configure<ApiBehaviorOptions>(options =>
{
   options.InvalidModelStateResponseFactory = (context) =>
   {
       var result = context.ModelState.ToMessageResult();
       return result;
   };
});

HttpContext扩展:
remoteRealIp:来源IP
remoteFrom:来源URL
remoteAgent:来源AGENT