欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

為ABP框架添加基礎集成服務

 更新時間:2022年02月23日 11:16:21   作者:癡者工良  
這篇文章介紹了為ABP框架添加基礎集成服務的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下

定義一個特性標記

這個標記用于標記一個枚舉代表的信息。

在 AbpBase.Domain.Shared 項目,創(chuàng)建 Attributes目錄,然后創(chuàng)建一個 SchemeNameAttribute 類,其內(nèi)容如下:

    /// <summary>
    /// 標記枚舉代表的信息
    /// </summary>
    [AttributeUsage(AttributeTargets.Field)]
    public class SchemeNameAttribute : Attribute
    {
        public string Message { get; set; }
        public SchemeNameAttribute(string message)
        {
            Message = message;
        }
    }

全局統(tǒng)一消息格式

為了使得 Web 應用統(tǒng)一響應格式以及方便編寫 API 時有一個統(tǒng)一的標準,我們需要定義一個合適的模板。

在 AbpBase.Domain.Shared 創(chuàng)建一個Apis 目錄。

Http 狀態(tài)碼

為了適配各種 HTTP 請求的響應狀態(tài),我們定義一個識別狀態(tài)碼的枚舉。

在 Apis 目錄,創(chuàng)建一個 HttpStateCode.cs 文件,其內(nèi)容如下:

namespace AbpBase.Domain.Shared.Apis
{
    /// <summary>
    /// 標準 HTTP 狀態(tài)碼
    /// <para>文檔地址<inheritdoc cref="https://www.runoob.com/http/http-status-codes.html"/></para>
    /// </summary>
    public enum HttpStateCode
    {
        Status412PreconditionFailed = 412,
        Status413PayloadTooLarge = 413,
        Status413RequestEntityTooLarge = 413,
        Status414RequestUriTooLong = 414,
        Status414UriTooLong = 414,
        Status415UnsupportedMediaType = 415,
        Status416RangeNotSatisfiable = 416,
        Status416RequestedRangeNotSatisfiable = 416,
        Status417ExpectationFailed = 417,
        Status418ImATeapot = 418,
        Status419AuthenticationTimeout = 419,
        Status421MisdirectedRequest = 421,
        Status422UnprocessableEntity = 422,
        Status423Locked = 423,
        Status424FailedDependency = 424,
        Status426UpgradeRequired = 426,
        Status428PreconditionRequired = 428,
        Status429TooManyRequests = 429,
        Status431RequestHeaderFieldsTooLarge = 431,
        Status451UnavailableForLegalReasons = 451,
        Status500InternalServerError = 500,
        Status501NotImplemented = 501,
        Status502BadGateway = 502,
        Status503ServiceUnavailable = 503,
        Status504GatewayTimeout = 504,
        Status505HttpVersionNotsupported = 505,
        Status506VariantAlsoNegotiates = 506,
        Status507InsufficientStorage = 507,
        Status508LoopDetected = 508,
        Status411LengthRequired = 411,
        Status510NotExtended = 510,
        Status410Gone = 410,
        Status408RequestTimeout = 408,
        Status101SwitchingProtocols = 101,
        Status102Processing = 102,
        Status200OK = 200,
        Status201Created = 201,
        Status202Accepted = 202,
        Status203NonAuthoritative = 203,
        Status204NoContent = 204,
        Status205ResetContent = 205,
        Status206PartialContent = 206,
        Status207MultiStatus = 207,
        Status208AlreadyReported = 208,
        Status226IMUsed = 226,
        Status300MultipleChoices = 300,
        Status301MovedPermanently = 301,
        Status302Found = 302,
        Status303SeeOther = 303,
        Status304NotModified = 304,
        Status305UseProxy = 305,
        Status306SwitchProxy = 306,
        Status307TemporaryRedirect = 307,
        Status308PermanentRedirect = 308,
        Status400BadRequest = 400,
        Status401Unauthorized = 401,
        Status402PaymentRequired = 402,
        Status403Forbidden = 403,
        Status404NotFound = 404,
        Status405MethodNotAllowed = 405,
        Status406NotAcceptable = 406,
        Status407ProxyAuthenticationRequired = 407,
        Status409Conflict = 409,
        Status511NetworkAuthenticationRequired = 511
    }
}

常用的請求結果

在相同目錄,創(chuàng)建一個 CommonResponseType 枚舉,其內(nèi)容如下:

    /// <summary>
    /// 常用的 API 響應信息
    /// </summary>
    public enum CommonResponseType
    {
        [SchemeName("")] Default = 0,

        [SchemeName("請求成功")] RequstSuccess = 1,

        [SchemeName("請求失敗")] RequstFail = 2,

        [SchemeName("創(chuàng)建資源成功")] CreateSuccess = 4,

        [SchemeName("創(chuàng)建資源失敗")] CreateFail = 8,

        [SchemeName("更新資源成功")] UpdateSuccess = 16,

        [SchemeName("更新資源失敗")] UpdateFail = 32,

        [SchemeName("刪除資源成功")] DeleteSuccess = 64,

        [SchemeName("刪除資源失敗")] DeleteFail = 128,

        [SchemeName("請求的數(shù)據(jù)未能通過驗證")] BadRequest = 256,

        [SchemeName("服務器出現(xiàn)嚴重錯誤")] Status500InternalServerError = 512
    }

響應模型

在 Apis 目錄,創(chuàng)建一個 ApiResponseModel`.cs 泛型類文件,其內(nèi)容如下:

namespace AbpBase.Domain.Shared.Apis
{
    /// <summary>
    /// API 響應格式
    /// <para>避免濫用,此類不能實例化,只能通過預定義的靜態(tài)方法生成</para>
    /// </summary>
    /// <typeparam name="TData"></typeparam>
    public abstract class ApiResponseModel<TData>
    {
        public HttpStateCode StatuCode { get; set; }
        public string Message { get; set; }
        public TData Data { get; set; }


        /// <summary>
        /// 私有類
        /// </summary>
        /// <typeparam name="TResult"></typeparam>
        private class PrivateApiResponseModel<TResult> : ApiResponseModel<TResult> { }
    }
}

StatuCode:用于說明此次響應的狀態(tài);

Message:響應的信息;

Data:響應的數(shù)據(jù);

可能你會覺得這樣很奇怪,先不要問,也不要猜,照著做,后面我會告訴你為什么這樣寫。

然后再創(chuàng)建一個類:

using AbpBase.Domain.Shared.Helpers;
using System;

namespace AbpBase.Domain.Shared.Apis
{
    /// <summary>
    /// Web 響應格式
    /// <para>避免濫用,此類不能實例化,只能通過預定義的靜態(tài)方法生成</para>
    /// </summary>
    public abstract class ApiResponseModel : ApiResponseModel<dynamic>
    {
        /// <summary>
        /// 根據(jù)枚舉創(chuàng)建響應格式
        /// </summary>
        /// <typeparam name="TEnum"></typeparam>
        /// <param name="code"></param>
        /// <param name="enumType"></param>
        /// <returns></returns>
        public static ApiResponseModel Create<TEnum>(HttpStateCode code, TEnum enumType) where TEnum : Enum
        {
            return new PrivateApiResponseModel
            {
                StatuCode = code,
                Message = SchemeHelper.Get(enumType),
            };
        }

        /// <summary>
        /// 創(chuàng)建標準的響應
        /// </summary>
        /// <typeparam name="TEnum"></typeparam>
        /// <typeparam name="TData"></typeparam>
        /// <param name="code"></param>
        /// <param name="enumType"></param>
        /// <param name="Data"></param>
        /// <returns></returns>
        public static ApiResponseModel Create<TEnum>(HttpStateCode code, TEnum enumType, dynamic Data)
        {
            return new PrivateApiResponseModel
            {
                StatuCode = code,
                Message = SchemeHelper.Get(enumType),
                Data = Data
            };
        }

        /// <summary>
        /// 請求成功
        /// </summary>
        /// <param name="code"></param>
        /// <param name="Data"></param>
        /// <returns></returns>
        public static ApiResponseModel CreateSuccess(HttpStateCode code, dynamic Data)
        {
            return new PrivateApiResponseModel
            {
                StatuCode = code,
                Message = "Success",
                Data = Data
            };
        }

        /// <summary>
        /// 私有類
        /// </summary>
        private class PrivateApiResponseModel : ApiResponseModel { }
    }
}

同時在項目中創(chuàng)建一個 Helpers 文件夾,再創(chuàng)建一個 SchemeHelper 類,其內(nèi)容如下:

using AbpBase.Domain.Shared.Attributes;
using System;
using System.Linq;
using System.Reflection;

namespace AbpBase.Domain.Shared.Helpers
{
    /// <summary>
    /// 獲取各種枚舉代表的信息
    /// </summary>
    public static class SchemeHelper
    {
        private static readonly PropertyInfo SchemeNameAttributeMessage = typeof(SchemeNameAttribute).GetProperty(nameof(SchemeNameAttribute.Message));

        /// <summary>
        /// 獲取一個使用了 SchemeNameAttribute 特性的 Message 屬性值
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <returns></returns>
        public static string Get<T>(T type)
        {
            return GetValue(type);
        }

        private static string GetValue<T>(T type)
        {
            var attr = typeof(T).GetField(Enum.GetName(type.GetType(), type))
                .GetCustomAttributes()
                .FirstOrDefault(x => x.GetType() == typeof(SchemeNameAttribute));

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

            var value = (string)SchemeNameAttributeMessage.GetValue(attr);
            return value;
        }
    }
}

上面的類到底是干嘛的,你先不要問。

全局異常攔截器

在 AbpBase.Web 項目中,新建一個 Filters 文件夾,添加一個 WebGlobalExceptionFilter.cs 文件,其文件內(nèi)容如下:

using AbpBase.Domain.Shared.Apis;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Newtonsoft.Json;
using System.Threading.Tasks;

namespace ApbBase.HttpApi.Filters
{

    /// <summary>
    /// Web 全局異常過濾器,處理 Web 中出現(xiàn)的、運行時未處理的異常
    /// </summary>
    public class WebGlobalExceptionFilter : IAsyncExceptionFilter
    {

        public async Task OnExceptionAsync(ExceptionContext context)
        {
            if (!context.ExceptionHandled)
            {

                ApiResponseModel model = ApiResponseModel.Create(HttpStateCode.Status500InternalServerError,
                    CommonResponseType.Status500InternalServerError);
                context.Result = new ContentResult
                {
                    Content = JsonConvert.SerializeObject(model),
                    StatusCode = StatusCodes.Status200OK,
                    ContentType = "application/json; charset=utf-8"
                };
            }

            context.ExceptionHandled = true;

            await Task.CompletedTask;
        }
    }
}

然后 在 AbpBaseWebModule 模塊的 ConfigureServices 函數(shù)中,加上:

            Configure<MvcOptions>(options =>
            {
                options.Filters.Add(typeof(WebGlobalExceptionFilter));
            });

這里我們還沒有將寫入日志,后面再增加這方面的功能。

先說明一下

前面我們定義了 ApiResponseModel 和其他一些特性還有枚舉,這里解釋一下原因。

ApiResponseModel 是抽象類

ApiResponseModel<T> 和 ApiResponseModel 是抽象類,是為了避免開發(fā)者使用時,直接這樣用:

            ApiResponseModel mode = new ApiResponseModel
            {
                Code = 500,
                Message = "失敗",
                Data = xxx
            };

首先這個 Code 需要按照 HTTP 狀態(tài)的標準來填寫,我們使用 HttpStateCode 枚舉來標記,代表異常時,使用 Status500InternalServerError 來標識。

我非常討厭一個 Action 的一個返回,就寫一次消息的。

if(... ...)
	return xxxx("請求數(shù)據(jù)不能為空");

if(... ...)
	return xxxx("xxx 要大于 10");
... ..

這樣每個地方一個消息說明,十分不統(tǒng)一,也不便于修改。

直接使用一個枚舉來代表消息,而不能直接寫出來,這樣就可以達到統(tǒng)一了。

使用抽象類,可以避免開發(fā)者直接 new 一個,強制要求一定的消息格式來響應。后面可以進行更多的嘗試,來體會我這樣設計的便利性。

跨域請求

這里我們將配置 Web 全局允許跨域請求。

在 AbpBaseWebModule 模塊中:

添加一個靜態(tài)變量

private const string AbpBaseWebCosr = "AllowSpecificOrigins";

創(chuàng)建一個配置函數(shù):

        /// <summary>
        /// 配置跨域
        /// </summary>
        /// <param name="context"></param>
        private void ConfigureCors(ServiceConfigurationContext context)
        {
            context.Services.AddCors(options =>
            {
                options.AddPolicy(AbpBaseWebCosr,
                    builder => builder.AllowAnyHeader()
                        .AllowAnyMethod()
                        .AllowAnyOrigin());
            });
        }

在 ConfigureServices 函數(shù)中添加:

            // 跨域請求
            ConfigureCors(context);

在 OnApplicationInitialization 中添加:

            app.UseCors(AbpBaseWebCosr);	// 位置在 app.UseRouting(); 后面

就這樣,允許全局跨域請求就完成了。

配置 API 服務

你可以使用以下模塊來配置一個 API 模塊服務:

            Configure<AbpAspNetCoreMvcOptions>(options =>
            {
                options
                    .ConventionalControllers
                    .Create(typeof(AbpBaseHttpApiModule).Assembly, opts =>
                    {
                        opts.RootPath = "api/1.0";
                    });
            });

我們在 AbpBase.HttpApi 中將其本身用于創(chuàng)建一個 API 服務,ABP 會將繼承了 AbpController 、ControllerBase 等的類識別為 API控制器。上面的代碼同時將其默認路由的前綴設置為 api/1.0。

也可以不設置前綴:

            Configure<AbpAspNetCoreMvcOptions>(options =>
            {                options.ConventionalControllers.Create(typeof(IoTCenterWebModule).Assembly);
            });

由于 API 模塊已經(jīng)在自己的 ConfigureServices 創(chuàng)建了 API 服務,因此可以不在 Web 模塊里面編寫這部分代碼。當然,也可以統(tǒng)一在 Web 中定義所有的 API 模塊。

統(tǒng)一 API 模型驗證消息

創(chuàng)建前

首先,如果我們這樣定義一個 Action:

        public class TestModel
        {
            [Required]
            public int Id { get; set; }
            
            [MaxLength(11)]
            public int Iphone { get; set; }
            
            [Required]
            [MinLength(5)]
            public string Message { get; set; }
        }

        [HttpPost("/T2")]
        public string MyWebApi2([FromBody] TestModel model)
        {
            return "請求完成";
        }

使用以下參數(shù)請求:

{
    "Id": "1",
    "Iphone": 123456789001234567890,
    "Message": null
}

會得到以下結果:

{
    "errors": {
        "Iphone": [
            "JSON integer 123456789001234567890 is too large or small for an Int32. Path 'Iphone', line 3, position 35."
        ]
    },
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "|af964c79-41367b2145701111."
}

這樣的信息閱讀起來十分不友好,前端對接也會有一定的麻煩。

這個時候我們可以統(tǒng)一模型驗證攔截器,定義一個友好的響應格式。

創(chuàng)建方式

在 AbpBase.Web 的項目 的 Filters 文件夾中,創(chuàng)建一個 InvalidModelStateFilter 文件,其文件內(nèi)容如下:

using AbpBase.Domain.Shared.Apis;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using System.Linq;

namespace AbpBase.Web.Filters
{
    public static class InvalidModelStateFilter
    {
        /// <summary>
        /// 統(tǒng)一模型驗證
        /// <para>控制器必須添加 [ApiController] 才能被此過濾器攔截</para>
        /// </summary>
        /// <param name="services"></param>
        public static void GlabalInvalidModelStateFilter(this IServiceCollection services)
        {
            services.Configure<ApiBehaviorOptions>(options =>
            {
                options.InvalidModelStateResponseFactory = actionContext =>
                {
                    if (actionContext.ModelState.IsValid)
                        return new BadRequestObjectResult(actionContext.ModelState);

                    int count = actionContext.ModelState.Count;
                    ValidationErrors[] errors = new ValidationErrors[count];
                    int i = 0;
                    foreach (var item in actionContext.ModelState)
                    {
                        errors[i] = new ValidationErrors
                        {
                            Member = item.Key,
                            Messages = item.Value.Errors?.Select(x => x.ErrorMessage).ToArray()
                        };
                        i++;
                    }

                    // 響應消息
                    var result = ApiResponseModel.Create(HttpStateCode.Status400BadRequest, CommonResponseType.BadRequest, errors);
                    var objectResult = new BadRequestObjectResult(result);
                    objectResult.StatusCode = StatusCodes.Status400BadRequest;
                    return objectResult;
                };
            });
        }


        /// <summary>
        /// 用于格式化實體驗證信息的模型
        /// </summary>
        private class ValidationErrors
        {
            /// <summary>
            /// 驗證失敗的字段
            /// </summary>
            public string Member { get; set; }

            /// <summary>
            /// 此字段有何種錯誤
            /// </summary>
            public string[] Messages { get; set; }
        }
    }
}

在 ConfigureServices 函數(shù)中,添加以下代碼:

            // 全局 API 請求實體驗證失敗信息格式化
            context.Services.GlabalInvalidModelStateFilter();

創(chuàng)建后

讓我們看看增加了統(tǒng)一模型驗證器后,同樣的請求返回的消息。

請求:

{
    "Id": "1",
    "Iphone": 123456789001234567890,
    "Message": null
}

返回:

{
    "statuCode": 400,
    "message": "請求的數(shù)據(jù)未能通過驗證",
    "data": [
        {
            "member": "Iphone",
            "messages": [
                "JSON integer 123456789001234567890 is too large or small for an Int32. Path 'Iphone', line 3, position 35."
            ]
        }
    ]
}

說明我們的統(tǒng)一模型驗證響應起到了作用。

但是有些驗證會直接報異常而不會流轉到上面的攔截器中,有些模型驗證特性用錯對象的話,他會報錯異常的。例如上面的 MaxLength ,已經(jīng)用錯了,MaxLength 是指定屬性中允許的數(shù)組或字符串數(shù)據(jù)的最大長度,不能用在 int 類型上。大家測試一下請求下面的 json,會發(fā)現(xiàn)報異常。

{
    "Id": 1,
    "Iphone": 1234567900,
    "Message": "nullable"
}

以下是一些 ASP.NET Core 內(nèi)置驗證特性,大家記得別用錯:

  • [CreditCard]:驗證屬性是否具有信用卡格式。 需要 JQuery 驗證其他方法。
  • [Compare]:驗證模型中的兩個屬性是否匹配。
  • [EmailAddress]:驗證屬性是否具有電子郵件格式。
  • [Phone]:驗證屬性是否具有電話號碼格式。
  • [Range]:驗證屬性值是否在指定的范圍內(nèi)。
  • [RegularExpression]:驗證屬性值是否與指定的正則表達式匹配。
  • [Required]:驗證字段是否不為 null。 有關此屬性的行為的詳細信息
  • [StringLength]:驗證字符串屬性值是否不超過指定長度限制。
  • [Url]:驗證屬性是否具有 URL 格式。
  • [Remote]:通過在服務器上調用操作方法來驗證客戶端上的輸入。
  • [MaxLength ] MaxLength 是指定屬性中允許的數(shù)組或字符串數(shù)據(jù)的最大長度

參考:https://docs.microsoft.com/zh-cn/dotnet/api/system.componentmodel.dataannotations?view=netcore-3.1

本系列第二篇到此,接下來第三篇會繼續(xù)添加一些基礎服務。

補充:為什么需要統(tǒng)一格式

首先,你看一下這樣的代碼:

在每個 Action 中,都充滿了這種寫法,每個相同的驗證問題,在每個 Action 返回的文字都不一樣,沒有規(guī)范可言。一個人寫一個 return,就加上一下自己要表達的 文字,一個項目下來,多少 return ?全是這種代碼,不堪入目。

通過統(tǒng)一模型驗證和統(tǒng)一消息返回格式,就可以避免這些情況。

源碼地址:https://github.com/whuanle/AbpBaseStruct

本教程結果代碼位置:https://github.com/whuanle/AbpBaseStruct/tree/master/src/2/AbpBase

到此這篇關于為ABP框架添加基礎集成服務的文章就介紹到這了。希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • ASP.NET?Core配置和管理Web主機

    ASP.NET?Core配置和管理Web主機

    這篇文章介紹了ASP.NET?Core配置和管理Web主機的方法,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-04-04
  • System.Diagnostics.Metrics .NET 6 全新指標API講解

    System.Diagnostics.Metrics .NET 6 全新指標API講解

    本文詳細講解了.NET 6全新指標System.Diagnostics.Metrics,文中通過示例代碼介紹的非常詳細。對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-11-11
  • ASP.NET實現(xiàn)word文檔在線預覽功能代碼

    ASP.NET實現(xiàn)word文檔在線預覽功能代碼

    文檔管理系統(tǒng)需要實現(xiàn)WORD能在線預覽功能,以前覺得挺難的,經(jīng)過一番研究發(fā)現(xiàn),WORD自帶的另存為可以保存為HTMl文件。
    2010-07-07
  • 使用vs2022在.net6中調試帶typescript的靜態(tài)頁面

    使用vs2022在.net6中調試帶typescript的靜態(tài)頁面

    這篇文章介紹了使用vs2022在.net6中調試帶typescript的靜態(tài)頁面,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-12-12
  • .Net創(chuàng)建型設計模式之原型模式(Prototype)

    .Net創(chuàng)建型設計模式之原型模式(Prototype)

    這篇文章介紹了.Net設計模式之原型模式(Prototype),文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • C#編碼好習慣小結

    C#編碼好習慣小結

    c#編寫比較好的習慣
    2008-04-04
  • .Net結構型設計模式之組合模式(Composite)

    .Net結構型設計模式之組合模式(Composite)

    這篇文章介紹了.Net結構型設計模式之組合模式(Composite),文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • .NET?6中System.Text.Json的七個特性

    .NET?6中System.Text.Json的七個特性

    這篇文章介紹了.NET?6中System.Text.Json的七個特性,文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-01-01
  • .Net創(chuàng)建型設計模式之抽象工廠模式(Abstract?Factory)

    .Net創(chuàng)建型設計模式之抽象工廠模式(Abstract?Factory)

    這篇文章介紹了.Net設計模式之抽象工廠模式(Abstract?Factory),文中通過示例代碼介紹的非常詳細。對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • ASP.NET緩存介紹

    ASP.NET緩存介紹

    緩存是在內(nèi)存存儲數(shù)據(jù)的一項技術,也是ASP.NET中提供的重要特性之一。例如你可以在復雜查詢的時候緩存數(shù)據(jù),這樣后來的請求就不需要從數(shù)據(jù)庫中取數(shù)據(jù),而是直接從緩存中獲取。通過使用緩存可以提高應用程序的性能
    2012-04-04

最新評論