簡體   English   中英

如何使用 appSettings.json 中的值自動設置 API 模型屬性的默認值?

[英]How to automatically set default value of API model's property with value from appSettings.json?

I'm creating a web API in Core 3.1 and I have PagingParams model that I will use on many controller actions. model 有PageNumberPageSize參數,這兩個參數都有一個默認值:

public class PagingParams
{
    [Range(1, Int32.MaxValue, ErrorMessage = "The field {0} must be greater than 0.")]
    public int? PageNumber { get; set; } = 1;

    [Range(1, 10000)] //TODO: Get 10000 from appsettings
    public int? PageSize { get; set; } = 10000; //TODO: Get 10000 from appsettings
}

PageSize參數值需要設置為 10000 並且與其Range屬性中的最大值相同。 這可以防止用戶每頁獲得超過 10k 個項目。

我希望能夠從appSettings.json中檢索該值,這樣我就可以修改它而無需每次都重新發布應用程序。 在整個代碼中,我一直在使用IOptionsSnapshotappSettings.json讀取值,但這里似乎無法完成,因為 model 需要具有無參數構造函數,導致以下錯誤:

System.InvalidOperationException:無法創建“WebAPI.Models.PagingParams”類型的實例。 Model 綁定的復雜類型不能是抽象類型或值類型,並且必須具有無參數構造函數。 或者,給“pagingParams”參數一個非空的默認值。

我如何設置 model 以便默認情況下從 appSettings 獲取int並在兩個地方設置?

這就是 class 的使用方式:

[Route("api/[controller]")]
    [ApiController]
    public class UsersController : ControllerBase
    {
        private readonly IMapper _mapper;
        private readonly IUserRepo _userRepo;

        public MissingNamesController(IMapper mapper, IUserRepo userRepo)
        {
            _mapper = mapper;
            _userRepo = userRepo;
        }

        [HttpGet]
        public IEnumerable<UserDto> Get([FromQuery] UsersQueryParams queryParams, [FromQuery] PagingParams pagingParams)
        {
            IEnumerable<User> models = _userRepo.Get(queryParams, pagingParams);
            IEnumerable<UserDto> dtoModels = _mapper.Map<IEnumerable<UserDto>>(models);
            return dtoModels;
        }
    }
}

注意:我的問題類似於這個問題,除了我希望能夠設置它以使其自動化。 我想避免每次在操作上使用PagingParams class 時調用方法,然后必須手動調用ModelState.IsValid並返回 model 錯誤。 使用我當前的設置, Range屬性會自動處理返回 model 錯誤,我不需要做任何進一步的事情。

您想要的是方便地使用一些默認值初始化一些屬性。 核心機制很簡單,就像您實例化 object 並在將其用於下一個管道之前設置其屬性。 有一些方法可以實現它:

  • 在 class 聲明中正確設置屬性:這不是您想要的,因為您想從某些設置中填充默認值(在運行時)。
  • 在您擁有 object 的任何地方設置屬性:這意味着在當前上下文中,您需要從設置/配置中加載默認值,以便您可以初始化屬性。

通常你用第二種方法。 但是,為了盡可能避免重復代碼,我們需要在管道(代碼執行 - 請求處理流程)中找到一個點,您可以在其中獲取 object 並在一個地方初始化其屬性(從配置加載)。

在您的情況下, PagingParams沒有在代碼中的任何地方實例化,這相當容易,它只是來自 controller 動作(由 model 綁定實例化)。 因此,在這種情況下,我們可以使用動作過濾器( IActionFilterIAsyncActionFilter可以)作為我們可以獲得參數(類型為PagingParams )並以我們想要的任何方式修改它(使用配置中加載的默認值初始化屬性)的點。

這很簡單:

public class InitPagingParamsAttribute : IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {
        
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        var pp = context.ActionArguments.Values.OfType<PagingParams>().FirstOrDefault();
        //this means there is at least 1 PagingParams in the controller action
        //NOTE that you can get all args of PagingParams, but looks like usually 
        //there should be just 1 arg of such type (in one same controller action)
        if (pp != null)
        {
            //modify the pp here
            //...
        }
    }
}

Startup.cs文件中,您可以配置 MVC 中間件以注冊全局操作過濾器。 如果不這樣做,您需要在 controller 或您想要的操作方法上裝飾屬性InitPagingParamsAttribute

public void ConfigureServices(IServiceCollection services){
    //...
    services.AddMvc(o => {
        o.Filters.Add<InitPagingParamsAttribute>();
    });
    //...
}

注意:您可以在InitPagingParamsAttribute構造函數中注入您的IOptionsSnapshot 因此,您可以從那里的配置中加載默認值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM