.Net Core Api: рд╡рд┐рднрд┐рдиреНрди рд╕реНрд░реЛрддреЛрдВ рд╕реЗ рдЕрдиреБрд░реЛрдз рдореЗрдВ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛

.Net рдХреЛрд░ рдореЗрдВ рдПрдХ рдЕрдВрддрд░реНрдирд┐рд╣рд┐рдд рдореЙрдбрд▓ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рддрдВрддреНрд░ рд╣реИ, рдЬреЛ рди рдХреЗрд╡рд▓ рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдореЗрдВ рдЗрдирдкреБрдЯ рдорд╛рдкрджрдВрдбреЛрдВ рдХреЛ рд╕реНрд╡реАрдХрд╛рд░ рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдмрд▓реНрдХрд┐ рддреБрд░рдВрдд рднрд░реЗ рд╣реБрдП рдХреНрд╖реЗрддреНрд░реЛрдВ рд╕реЗ рд╡рд╕реНрддреБрдУрдВ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред рдпрд╣ рдЖрдкрдХреЛ рдореЙрдбрд▓ рд╡реИрдзрддрд╛ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рд╕рднреА рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдВрдЪреЛрдВ рдХреЛ рдРрд╕реЗ рдСрдмреНрдЬреЗрдХреНрдЯ рдореЗрдВ рдПрдореНрдмреЗрдб рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИред

рдпрд╣рд╛рдВ рдПрдкреАрдЖрдИ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рдбреЗрдЯрд╛ рд╣реИрдВ, рди рдХреЗрд╡рд▓ рдХреНрд╡реЗрд░реА рдпрд╛ рдмреЙрдбреА рд╕реЗ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдЖрдПрдВред рдХреБрдЫ рдбреЗрдЯрд╛ рдХреЛ рд╣реЗрдбрд░ рд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реЛрддреА рд╣реИ (рдореЗрд░реЗ рдорд╛рдорд▓реЗ рдореЗрдВ рдмреЗрд╕ 64 рдореЗрдВ json рдерд╛), рдХреБрдЫ рдбреЗрдЯрд╛ рдмрд╛рд╣рд░реА рд╕реЗрд╡рд╛рдУрдВ рдпрд╛ рдПрдХреНрд╢рдирд░реАрдЯ рд╕реЗ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдП рдпрджрд┐ рдЖрдк REST рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рддреЗ рд╣реИрдВред рд╡рд╣рд╛рдВ рд╕реЗ рдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдк рдЕрдкрдиреА рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╕рдЪ рд╣реИ, рдПрдХ рд╕рдорд╕реНрдпрд╛ рд╣реИ: рдпрджрд┐ рдЖрдк рдирд┐рд░реНрдорд╛рдг рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдЗрдирдХреИрдкреНрд╕реБрд▓реЗрд╢рди рдХреЛ рддреЛрдбрд╝рдиреЗ рдФрд░ рдореЙрдбрд▓ рдХреЛ рдЗрдирд┐рд╢рд┐рдпрд▓рд╛рдЗрдЬрд╝ рдирд╣реАрдВ рдХрд░рдиреЗ рдХрд╛ рдирд┐рд░реНрдгрдп рд▓реЗрддреЗ рд╣реИрдВ, рддреЛ рдЖрдкрдХреЛ рд╢рд░реНрдорд╕рд╛рд░ рд╣реЛрдирд╛ рдкрдбрд╝реЗрдЧрд╛ред

рдЕрдкрдиреЗ рд▓рд┐рдП рдФрд░ рдЖрдиреЗ рд╡рд╛рд▓реА рдкреАрдврд╝рд┐рдпреЛрдВ рдХреЗ рд▓рд┐рдП, рдореИрдВрдиреЗ рдЗрд╕рдХреЗ рд╕рд╛рде рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдФрд░ рд╢рд░реНрдорд┐рдВрджрдЧреА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдиреЗ рдХреЗ рдирд┐рд░реНрджреЗрд╢реЛрдВ рдХреЗ рд░реВрдк рдореЗрдВ рдХреБрдЫ рд▓рд┐рдЦрдиреЗ рдХрд╛ рдлреИрд╕рд▓рд╛ рдХрд┐рдпрд╛ред

рдореБрд╕реАрдмрдд


рдПрдХ рд╡рд┐рд╢рд┐рд╖реНрдЯ рдирд┐рдпрдВрддреНрд░рдХ рдХреБрдЫ рдЗрд╕ рддрд░рд╣ рджрд┐рдЦрддрд╛ рд╣реИ:

[HttpGet]
public async Task<IActionResult> GetSomeData([FromQuery[IncomeData someData)
{
    var moreData = GetFromHeaderAndDecode("X-Property");
    if (moreData.Id == 0)
    {
        return StatusCode(400, "Nginx doesnt know your id");
    }
    var externalData = GetFromExternalService("http://myservice.com/MoreData");
    if (externalData == null)
    {
        return StatusCode(500, "Cant connect to external service");
    }
    var finalData = new FinalData(someData, moreData, externalData);
    return _myService.Handle(finalData);
}

рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рд╣рдореЗрдВ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рд╕рдорд╕реНрдпрд╛рдПрдВ рдЖрддреА рд╣реИрдВ:

  1. рд╕рддреНрдпрд╛рдкрди рддрд░реНрдХ рдХреЛ рдЕрдиреБрд░реЛрдз рдСрдмреНрдЬреЗрдХреНрдЯ, рд╣реЗрдбрд░ рд╕реЗ рдЕрдиреБрд░реЛрдз рд╡рд┐рдзрд┐, рд╕реЗрд╡рд╛ рд╕реЗ рдЕрдиреБрд░реЛрдз рд╡рд┐рдзрд┐ рдФрд░ рдирд┐рдпрдВрддреНрд░рдХ рд╡рд┐рдзрд┐ рджреНрд╡рд╛рд░рд╛ рд╕реНрдореАрдпрд░ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрд╣ рд╕реБрдирд┐рд╢реНрдЪрд┐рдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдЖрд╡рд╢реНрдпрдХ рдЬрд╛рдВрдЪ рдирд┐рд╢реНрдЪрд┐рдд рд░реВрдк рд╕реЗ рд╣реИ, рдЖрдкрдХреЛ рдкреВрд░реА рдЬрд╛рдВрдЪ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ!
  2. рдЖрд╕рдиреНрди рдирд┐рдпрдВрддреНрд░рдХ рд╡рд┐рдзрд┐ рдореЗрдВ рдмрд┐рд▓реНрдХреБрд▓ рд╕рдорд╛рди рдХреЛрдб рд╣реЛрдЧрд╛ред рд╣рдорд▓реЗ рдореЗрдВ рдХреЙрдкреА-рдкреЗрд╕реНрдЯ рдкреНрд░реЛрдЧреНрд░рд╛рдорд┐рдВрдЧред
  3. рдЖрдорддреМрд░ рдкрд░ рдЙрджрд╛рд╣рд░рдг рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдмрд╣реБрдд рдЕрдзрд┐рдХ рдЪреЗрдХ рд╣реЛрддреЗ рд╣реИрдВ, рдФрд░ рдкрд░рд┐рдгрд╛рдорд╕реНрд╡рд░реВрдк, рдХреЗрд╡рд▓ рдорд╣рддреНрд╡рдкреВрд░реНрдг рд▓рд╛рдЗрди - рд╡реНрдпрд╛рдкрд╛рд░ рддрд░реНрдХ рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рд╡рд┐рдзрд┐ рдХреЗ рд▓рд┐рдП рдХреЙрд▓ - рдХреЛрдб рдХреЗ рдвреЗрд░ рдореЗрдВ рдЫрд┐рдкрд╛ рд╣реБрдЖ рд╣реИред рдЙрд╕реЗ рджреЗрдЦрдиреЗ рдФрд░ рд╕рдордЭрдиреЗ рдХреЗ рд▓рд┐рдП рдХрд┐ рдпрд╣рд╛рдБ рдХреНрдпрд╛ рд╣реЛ рд░рд╣рд╛ рд╣реИ, рдХреБрдЫ рдкреНрд░рдпрд╛рд╕ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред

рдХрд╕реНрдЯрдо рдмрдВрдзрди (рдЖрд╕рд╛рди рдореЛрдб)


рдЕрдиреБрд░реЛрдз рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рдкрд╛рдЗрдкрд▓рд╛рдЗрди рдореЗрдВ рдЕрдкрдиреЗ рд╣реИрдВрдбрд▓рд░ рдХреЛ рд▓рд╛рдЧреВ рдХрд░рдХреЗ рд╕рдорд╕реНрдпрд╛ рдХрд╛ рд╣рд┐рд╕реНрд╕рд╛ рд╣рд▓ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдРрд╕рд╛ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рдкрд╣рд▓реЗ рдЕрдВрддрд┐рдо рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ рддреБрд░рдВрдд рд╡рд┐рдзрд┐ рд╕реЗ рдкрд╛рд╕ рдХрд░рдХреЗ рд╣рдорд╛рд░реЗ рдирд┐рдпрдВрддреНрд░рдХ рдХреЛ рдареАрдХ рдХрд░реЗрдВред рдпрд╣ рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд▓рдЧ рд░рд╣рд╛ рд╣реИ, рд╣реИ рдирд╛?

[HttpGet]
public async Task<IActionResult> GetSomeData([FromQuery]FinalData finalData)
{
    return _myService.Handle(finalData);
}

рдЗрд╕рдХреЗ рдмрд╛рдж, MoreData рдкреНрд░рдХрд╛рд░ рдХреЗ рд▓рд┐рдП рдЕрдкрдирд╛ рдмрд╛рдЗрдВрдбрд░ рдмрдирд╛рдПрдВред

public class MoreDataBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var moreData = GetFromHeaderAndDecode(bindingContext.HttpContext.Request.Headers);
        if (moreData != null)
        {
            bindingContext.Result = ModelBindingResult.Success(moreData);
        }
        return Task.CompletedTask;
    }
    private MoreData GetFromHeaderAndDecode(IHeaderDictionary headers) { ... }
}

рдЕрдВрдд рдореЗрдВ, рд╣рдо рд╡рд╣рд╛рдВ рд╕рдВрдкрддреНрддрд┐ рдореЗрдВ рдмрд╛рдЗрдВрдбрд░ рдмрд╛рдЗрдВрдбрд┐рдВрдЧ рдЬреЛрдбрд╝рдХрд░ рдлрд╝рд╛рдЗрдирд▓рдбрд╛рдЯрд╛ рдореЙрдбрд▓ рдХреЛ рдареАрдХ рдХрд░ рджреЗрдВрдЧреЗ:

public class FinalData
{
    public int SomeDataNumber { get; set; }

    public string SomeDataText { get; set; }

    [ModelBinder(BinderType = typeof(MoreDataBinder))]
    public MoreData MoreData { get; set; }
}

рдпрд╣ рдкрд╣рд▓реЗ рд╕реЗ рдмреЗрд╣рддрд░ рд╣реИ, рд▓реЗрдХрд┐рди рдмрд╡рд╛рд╕реАрд░ рдореЗрдВ рд╡реГрджреНрдзрд┐ рд╣реБрдИ рд╣реИ: рдЕрдм рдЖрдкрдХреЛ рдпрд╣ рдЬрд╛рдирдирд╛ рд╣реЛрдЧрд╛ рдХрд┐ рд╣рдорд╛рд░реЗ рдкрд╛рд╕ рдПрдХ рд╡рд┐рд╢реЗрд╖ рд╣реИрдВрдбрд▓рд░ рд╣реИ рдФрд░ рдЗрд╕реЗ рд╕рднреА рдореЙрдбрд▓реЛрдВ рдореЗрдВ рджрд░реНрд╢рд╛рдПрдВред рд▓реЗрдХрд┐рди рдпрд╣ рд╕реЙрд▓реНрд╡ рд╣реИред

рдЕрдкрдирд╛ BinderProvider рдмрдирд╛рдПрдВ:

public class MoreDataBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
        var modelType = context.Metadata.UnderlyingOrModelType;
        if (modelType == typeof(MoreData))
        {
            return new BinderTypeModelBinder(typeof(MoreDataBinder));
        }
        return null;
    }
}

рдФрд░ рдЗрд╕реЗ рд╕реНрдЯрд╛рд░реНрдЯрдЕрдк рдореЗрдВ рдкрдВрдЬреАрдХреГрдд рдХрд░реЗрдВ:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddMvc(options =>
    {
        options.ModelBinderProviders.Insert(0, new MoreDataBinderProvider());
     });
}

рдкреНрд░рджрд╛рддрд╛ рдХреЛ рдХрддрд╛рд░ рдХреЗ рдХреНрд░рдо рдореЗрдВ рдкреНрд░рддреНрдпреЗрдХ рдореЙрдбрд▓ рдСрдмреНрдЬреЗрдХреНрдЯ рдХреЗ рд▓рд┐рдП рдХрд╣рд╛ рдЬрд╛рддрд╛ рд╣реИред рдпрджрд┐ рд╣рдорд╛рд░рд╛ рдкреНрд░рджрд╛рддрд╛ рд╡рд╛рдВрдЫрд┐рдд рдкреНрд░рдХрд╛рд░ рд╕реЗ рдорд┐рд▓рддрд╛ рд╣реИ, рддреЛ рдпрд╣ рд╡рд╛рдВрдЫрд┐рдд рдмрд╛рдЗрдВрдбрд░ рд▓реМрдЯрд╛ рджреЗрдЧрд╛ред рдФрд░ рдпрджрд┐ рдирд╣реАрдВ, рддреЛ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдмрд╛рдЗрдВрдбрд░ рдХрд╛рдо рдХрд░реЗрдЧрд╛ред рддреЛ рдЕрдм рдЬрдм рднреА рд╣рдо MoreData рдХреЗ рдкреНрд░рдХрд╛рд░ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддреЗ рд╣реИрдВ, рддреЛ рдЗрд╕реЗ рд╣реЗрдбрд░ рд╕реЗ рд▓рд┐рдпрд╛ рдФрд░ рдбрд┐рдХреЛрдб рдХрд┐рдпрд╛ рдЬрд╛рдПрдЧрд╛ рдФрд░ рдореЙрдбрд▓ рдореЗрдВ рд╡рд┐рд╢реЗрд╖ рд╡рд┐рд╢реЗрд╖рддрд╛рдУрдВ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред

рдХрд╕реНрдЯрдо рдмрд╛рдЗрдВрдбрд┐рдВрдЧ (рд╣рд╛рд░реНрдб рдореЛрдб)


рдпрд╣ рд╕рдм рдмрд╣реБрдд рдЕрдЪреНрдЫрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдмрд╛рдд рд╣реИ рд▓реЗрдХрд┐рди: рдЬрд╛рджреВ рдХреЗ рдХрд╛рдо рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, рд╣рдорд╛рд░реЗ рдореЙрдбрд▓ рдореЗрдВ рд╕реЗрдЯ рдХреЗ рд╕рд╛рде рд╕рд╛рд░реНрд╡рдЬрдирд┐рдХ рдЧреБрдг рд╣реЛрдиреЗ рдЪрд╛рд╣рд┐рдПред рд▓реЗрдХрд┐рди рдЗрдирдХреИрдкреНрд╕реБрд▓реЗрд╢рди рдХрд╛ рдХреНрдпрд╛? рдХреНрдпрд╛ рд╣реЛрдЧрд╛ рдпрджрд┐ рдореИрдВ рдХреНрд▓рд╛рдЙрдб рдореЗрдВ рд╡рд┐рднрд┐рдиреНрди рд╕реНрдерд╛рдиреЛрдВ рдкрд░ рдЕрдиреБрд░реЛрдз рдбреЗрдЯрд╛ рд╕реНрдерд╛рдирд╛рдВрддрд░рд┐рдд рдХрд░рдирд╛ рдЪрд╛рд╣рддрд╛ рд╣реВрдВ рдФрд░ рдЬрд╛рдирддрд╛ рд╣реВрдВ рдХрд┐ рдЙрдиреНрд╣реЗрдВ рд╡рд╣рд╛рдВ рдирд╣реАрдВ рдмрджрд▓рд╛ рдЬрд╛рдПрдЧрд╛?

рд╕рдорд╕реНрдпрд╛ рдпрд╣ рд╣реИ рдХрд┐ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдмрд╛рдЗрдВрдбрд░ рдЙрди рдореЙрдбрд▓реЛрдВ рдХреЗ рд▓рд┐рдП рдХрд╛рдо рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ рдЬрд┐рдирдореЗрдВ рдбрд┐рдлрд╝реЙрд▓реНрдЯ рдХрдВрд╕реНрдЯреНрд░рдХреНрдЯрд░ рдирд╣реАрдВ рд╣реИред рд▓реЗрдХрд┐рди рдХреНрдпрд╛ рд╣рдореЗрдВ рдЦреБрдж рдХреЛ рд▓рд┐рдЦрдиреЗ рд╕реЗ рд░реЛрдХрддрд╛ рд╣реИ?
рдЬрд┐рд╕ рд╕реЗрд╡рд╛ рдХреЗ рд▓рд┐рдП рдореИрдВрдиреЗ рдпрд╣ рдХреЛрдб рд▓рд┐рдЦрд╛ рдерд╛ рд╡рд╣ REST рдХрд╛ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИ, рдкреИрд░рд╛рдореАрдЯрд░ рдХреЗрд╡рд▓ рдХреНрд╡реЗрд░реА рдФрд░ рдмреЙрдбреА рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдкреНрд░реЗрд╖рд┐рдд рд╣реЛрддреЗ рд╣реИрдВ, рдФрд░ рдХреЗрд╡рд▓ рджреЛ рдкреНрд░рдХрд╛рд░ рдХреЗ рдЕрдиреБрд░реЛрдзреЛрдВ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ - рдкреНрд░рд╛рдкреНрдд рдХрд░реЗрдВ
рдФрд░ рдкреЛрд╕реНрдЯ рдХрд░реЗрдВред рддрджрдиреБрд╕рд╛рд░, рдЖрд░рдИрдПрд╕рдЯреА рдПрдкреАрдЖрдИ рдХреЗ рдорд╛рдорд▓реЗ рдореЗрдВ, рдкреНрд░рд╕рдВрд╕реНрдХрд░рдг рддрд░реНрдХ рдереЛрдбрд╝рд╛ рдЕрд▓рдЧ рд╣реЛрдЧрд╛ред
рд╕рд╛рдорд╛рдиреНрдп рддреМрд░ рдкрд░, рдХреЛрдб рдЕрдкрд░рд┐рд╡рд░реНрддрд┐рдд рд░рд╣реЗрдЧрд╛, рдХреЗрд╡рд▓ рд╣рдорд╛рд░реЗ рдмрд╛рдЗрдВрдбрд░ рдХреЛ рд╢реЛрдзрди рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ рддрд╛рдХрд┐ рд╡рд╣ рдПрдХ рд╡рд╕реНрддреБ рдмрдирд╛ рд╕рдХреЗ рдФрд░ рдЕрдкрдиреЗ рдирд┐рдЬреА рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЛ рднрд░ рд╕рдХреЗред рдЖрдЧреЗ рдореИрдВ рдЯрд┐рдкреНрдкрдгрд┐рдпреЛрдВ рдХреЗ рд╕рд╛рде рдХреЛрдб рдХреЗ рдЯреБрдХрдбрд╝реЗ рджреВрдВрдЧрд╛, рдЬрд┐рдиреНрд╣реЗрдВ рдХреЛрдИ рджрд┐рд▓рдЪрд╕реНрдкреА рдирд╣реАрдВ рд╣реИ - рдмрд┐рд▓реНрд▓реА рдХреЗ рдиреАрдЪреЗ рд▓реЗрдЦ рдХреЗ рдЕрдВрдд рдореЗрдВ рдХрдХреНрд╖рд╛ рдХреА рдкреВрд░реА рд╕реВрдЪреА рд╣реИред

рдкрд╣рд▓реЗ, рдпрд╣ рдирд┐рд░реНрдзрд╛рд░рд┐рдд рдХрд░реЗрдВ рдХрд┐ рдХреНрдпрд╛ MoreData рдХреЗрд╡рд▓ рд╡рд░реНрдЧ рдХреА рд╕рдВрдкрддреНрддрд┐ рд╣реИред рдпрджрд┐ рд╣рд╛рдБ, рддреЛ рдЖрдкрдХреЛ рдСрдмреНрдЬреЗрдХреНрдЯ рд╕реНрд╡рдпрдВ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИ (рд╣реИрд▓реЛ, рдПрдХреНрдЯрд┐рд╡реЗрдЯрд░), рдФрд░ рдпрджрд┐ рдирд╣реАрдВ, рддреЛ JsonConvert рдХрд╛рдо рдХреЛ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдХрд░реЗрдЧрд╛, рдФрд░ рд╣рдо рд╕рд┐рд░реНрдл рдЖрд╡рд╢реНрдпрдХ рдбреЗрдЯрд╛ рдХреЛ рд╕рдВрдкрддреНрддрд┐ рдореЗрдВ рдкрд░реНрдЪреА рдХрд░рддреЗ рд╣реИрдВред

private static bool NeedActivator(IReflect modelType)
{
    var propFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
    var properties = modelType.GetProperties(propFlags);

    return properties.Select(p => p.Name).Distinct().Count() == 1;
}

JsonConvert рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдПрдХ рд╡рд╕реНрддреБ рдмрдирд╛рдирд╛ рд╕рд░рд▓ рд╣реИ, рд╢рд░реАрд░ рдХреЗ рд╕рд╛рде рдкреНрд░рд╢реНрдиреЛрдВ рдХреЗ рд▓рд┐рдП:

private static object? GetModelFromBody(ModelBindingContext bindingContext, Type modelType)
{
    using var reader = new StreamReader(bindingContext.HttpContext.Request.Body);
    var jsonString = reader.ReadToEnd();
    var data = JsonConvert.DeserializeObject(jsonString, modelType);
    return data;
}

рд▓реЗрдХрд┐рди рдХреНрд╡реЗрд░реА рдХреЗ рд╕рд╛рде рдореБрдЭреЗ рд▓реЗрдЯрдирд╛ рдкрдбрд╝рд╛ред рдореБрдЭреЗ рдЦреБрд╢реА рд╣реЛрдЧреА рдЕрдЧрд░ рдХреЛрдИ рдФрд░ рдЕрдзрд┐рдХ рд╕реБрдВрджрд░ рд╕рдорд╛рдзрд╛рди рд╕реБрдЭрд╛ рд╕рдХрддрд╛ рд╣реИред

рдПрдХ рд╕рд░рдгреА рдкрд╛рд╕ рдХрд░рддреЗ рд╕рдордп, рд╕рдорд╛рди рдирд╛рдо рд╡рд╛рд▓реЗ рдХрдИ рдкреИрд░рд╛рдореАрдЯрд░ рдкреНрд░рд╛рдкреНрдд рдХрд┐рдП рдЬрд╛рддреЗ рд╣реИрдВред рдПрдХ рдлреНрд▓реИрдЯ рдкреНрд░рдХрд╛рд░ рдореЗрдВ рдХрд╛рд╕реНрдЯрд┐рдВрдЧ рдХрд░рдиреЗ рд╕реЗ рдорджрдж рдорд┐рд▓рддреА рд╣реИ, рд▓реЗрдХрд┐рди рдХреНрд░рдорд╛рдВрдХрди рд╕рд░рдгреА рдкрд░ рдЕрддрд┐рд░рд┐рдХреНрдд рдЙрджреНрдзрд░рдг рдбрд╛рд▓рддрд╛ рд╣реИ [], рдЬрд┐рд╕реЗ рдореИрдиреНрдпреБрдЕрд▓ рд░реВрдк рд╕реЗ рд╣рдЯрд╛рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред

private static object? GetModelFromQuery(ModelBindingContext bindingContext, Type modelType)
{
    var valuesDictionary = QueryHelpers.ParseQuery(bindingContext.HttpContext.Request.QueryString.Value);
    var jsonDictionary = valuesDictionary.ToDictionary(pair => pair.Key, pair => pair.Value.Count < 2 ? pair.Value.ToString() : $"[{pair.Value}]");

    var jsonStr = JsonConvert.SerializeObject(jsonDictionary).Replace("\"[", "[").Replace("]\"", "]");
    var data = JsonConvert.DeserializeObject(jsonStr, modelType);
    return data;
}

рдЕрдВрдд рдореЗрдВ, рдСрдмреНрдЬреЗрдХреНрдЯ рдХрд╛ рдирд┐рд░реНрдорд╛рдг рдХрд░рддреЗ рд╣реБрдП, рд╣рдорд╛рд░реЗ рдбреЗрдЯрд╛ рдХреЛ рдЙрд╕рдХреА рдирд┐рдЬреА рд╕рдВрдкрддреНрддрд┐ рдореЗрдВ рд▓рд┐рдЦрдирд╛ рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдпрд╣ рдЗрд╕ shamanism рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдерд╛ рдЬреЛ рдореИрдВрдиреЗ рд▓реЗрдЦ рдХреА рд╢реБрд░реБрдЖрдд рдореЗрдВ рдмреЛрд▓рд╛ рдерд╛ред рдореБрдЭреЗ рдпрд╣ рд╕рдорд╛рдзрд╛рди рдпрд╣рд╛рдВ рдорд┐рд▓рд╛ , рдЬрд┐рд╕рдХреЗ рд▓рд┐рдП рд▓реЗрдЦрдХ рдХреЛ рдмрд╣реБрдд рдзрдиреНрдпрд╡рд╛рджред

private void ForceSetValue(PropertyInfo propertyInfo, object obj, object value)
{
    var propName = $"<{propertyInfo.Name}>k__BackingField";
    var propFlags = BindingFlags.Instance | BindingFlags.NonPublic;
            
    obj.GetType().GetField(propName, propFlags)?.SetValue(obj, value);
}

рдЦреИрд░, рд╣рдо рдЗрди рд╡рд┐рдзрд┐рдпреЛрдВ рдХреЛ рдПрдХ рдХреЙрд▓ рдореЗрдВ рд╕рдВрдпреЛрдЬрд┐рдд рдХрд░рддреЗ рд╣реИрдВ:

public Task BindModelAsync(ModelBindingContext bindingContext)
{
    var moreData = GetFromHeaderAndDecode(bindingContext.HttpContext.Request.Headers);
    if (moreData == null)
    {
        return Task.CompletedTask;
    }

    var modelType = bindingContext.ModelMetadata.UnderlyingOrModelType;
    if (NeedActivator(modelType))
    {
        var data = Activator.CreateInstance(modelType, moreData);
        bindingContext.Result = ModelBindingResult.Success(data);

        return Task.CompletedTask;
    }

    var model = bindingContext.HttpContext.Request.Method == "GET"
                            ? GetModelFromQuery(bindingContext, modelType)
                            : GetModelFromBody(bindingContext, modelType);

    if (model is null)
    {
        throw new Exception("  ");
    }

    var ignoreCase = StringComparison.InvariantCultureIgnoreCase;
    var dataProperty = modelType.GetProperties()
                            .FirstOrDefault(p => p.Name.Equals(typeof(T).Name, ignoreCase));

    if (dataProperty != null)
    {
        ForceSetValue(dataProperty, model, moreData);
    }

    bindingContext.Result = ModelBindingResult.Success(model);
    return Task.CompletedTask;
}

рдпрд╣ рдмрд╛рдЗрдВрдбрд░рдкреНрд░реЛрдЗрдбрд░ рдХреЛ рдареАрдХ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдмрдиреА рд╣реБрдИ рд╣реИ рддрд╛рдХрд┐ рдпрд╣ рд╡рд╛рдВрдЫрд┐рдд рд╕рдВрдкрддреНрддрд┐ рдХреЗ рд╕рд╛рде рдХрд┐рд╕реА рднреА рд╡рд░реНрдЧ рдХреЛ рдЬрд╡рд╛рдм рджреЗ:

public class MoreDataBinderProvider : IModelBinderProvider
{
    public IModelBinder GetBinder(ModelBinderProviderContext context)
    {
       var modelType = context.Metadata.UnderlyingOrModelType;
       if (HasDataProperty(modelType))
       {
           return new BinderTypeModelBinder(typeof(PrivateDataBinder<MoreData>));
       }
       return null;
    }
    private bool HasDataProperty(IReflect modelType)
    {
        var propFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
        var properties = modelType.GetProperties(propFlags);

        return properties.Select(p => p.Name) .Contains(nameof(MoreData));
    }
}


рдмрд╕ рдЗрддрдирд╛ рд╣реАред рдмрд╛рдЗрдВрдбрд░ рдИрдЬрд╝реА рдореЛрдб рдХреА рддреБрд▓рдирд╛ рдореЗрдВ рдереЛрдбрд╝рд╛ рдЕрдзрд┐рдХ рдЬрдЯрд┐рд▓ рдирд┐рдХрд▓рд╛, рд▓реЗрдХрд┐рди рдЕрдм рд╣рдо рдЕрддрд┐рд░рд┐рдХреНрдд рдкреНрд░рдпрд╛рд╕реЛрдВ рдХреЗ рдмрд┐рдирд╛ рд╕рднреА рдирд┐рдпрдВрддреНрд░рдХреЛрдВ рдХреЗ рд╕рднреА рддрд░реАрдХреЛрдВ рдореЗрдВ "рдмрд╛рд╣рд░реА" рдЧреБрдгреЛрдВ рдХреЛ рдмрд╛рдВрдз рд╕рдХрддреЗ рд╣реИрдВред Minuses рдХреА:

  1. рдирд┐рдЬреА рдХреНрд╖реЗрддреНрд░реЛрдВ рдХреЗ рд╕рд╛рде рд╡рд╕реНрддреБрдУрдВ рдХреЗ рдирд┐рд░реНрдорд╛рддрд╛ рдХреЛ [JsonConstrustor] рд╡рд┐рд╢реЗрд╖рддрд╛ рдХреЛ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдирд╛ рдЪрд╛рд╣рд┐рдПред рд▓реЗрдХрд┐рди рдпрд╣ рдкреВрд░реА рддрд░рд╣ рд╕реЗ рдореЙрдбрд▓ рдХреЗ рддрд░реНрдХ рдореЗрдВ рдлрд┐рдЯ рдмреИрдарддрд╛ рд╣реИ рдФрд░ рдЗрд╕рдХреА рдзрд╛рд░рдгрд╛ рдореЗрдВ рд╣рд╕реНрддрдХреНрд╖реЗрдк рдирд╣реАрдВ рдХрд░рддрд╛ рд╣реИред
  2. рдХрд╣реАрдВ, рдЖрдкрдХреЛ рд╣реЗрдбрд░ рд╕реЗ рдореЛрд░реЗрдбреЗрдЯрд╛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рдирд╣реАрдВ рд╣реИред рд▓реЗрдХрд┐рди рдПрдХ рдЕрд▓рдЧ рд╡рд░реНрдЧ рдмрдирд╛рдХрд░ рдЗрд╕рдХрд╛ рдЗрд▓рд╛рдЬ рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИред
  3. рдмрд╛рдХреА рдЯреАрдо рдХреЛ рдЬрд╛рджреВ рдХреА рдЙрдкрд╕реНрдерд┐рддрд┐ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдкрддрд╛ рд╣реЛрдирд╛ рдЪрд╛рд╣рд┐рдПред рд▓реЗрдХрд┐рди рдкреНрд░рд▓реЗрдЦрди рдорд╛рдирд╡рддрд╛ рдХреЛ рдмрдЪрд╛рдПрдЧрд╛ред

рдкрд░рд┐рдгрд╛рдореА рдмрд╛рдЗрдВрдбрд░ рдХреА рдкреВрд░реА рд╕реВрдЪреА рдпрд╣рд╛рдБ рд╣реИ:

PrivateMoreDataBinder.cs
public class PrivateDataBinder<T> : IModelBinder
    {
        /// <summary></summary>
        /// <param name="bindingContext"></param>
        public Task BindModelAsync(ModelBindingContext bindingContext)
        {
            var moreData = GetFromHeaderAndDecode(bindingContext.HttpContext.Request.Headers);
            if (moreData == null)
            {
                return Task.CompletedTask;
            }

            var modelType = bindingContext.ModelMetadata.UnderlyingOrModelType;
            if (NeedActivator(modelType))
            {
                var data = Activator.CreateInstance(modelType, moreData);
                bindingContext.Result = ModelBindingResult.Success(data);

                return Task.CompletedTask;
            }

            var model = bindingContext.HttpContext.Request.Method == "GET"
                            ? GetModelFromQuery(bindingContext, modelType)
                            : GetModelFromBody(bindingContext, modelType);

            if (model is null)
            {
                throw new Exception("  ");
            }

            var ignoreCase = StringComparison.InvariantCultureIgnoreCase;
            var dataProperty = modelType.GetProperties()
                                        .FirstOrDefault(p => p.Name.Equals(typeof(T).Name, ignoreCase));

            if (dataProperty != null)
            {
                ForceSetValue(dataProperty, model, moreData);
            }

            bindingContext.Result = ModelBindingResult.Success(model);

            return Task.CompletedTask;
        }

        private static object? GetModelFromQuery(ModelBindingContext bindingContext,
                                                 Type modelType)
        {
            var valuesDictionary = QueryHelpers.ParseQuery(bindingContext.HttpContext.Request.QueryString.Value);

            var jsonDictionary = valuesDictionary.ToDictionary(pair => pair.Key, pair => pair.Value.Count < 2 ? pair.Value.ToString() : $"[{pair.Value}]");

            var jsonStr = JsonConvert.SerializeObject(jsonDictionary)
                                     .Replace("\"[", "[")
                                     .Replace("]\"", "]");

            var data = JsonConvert.DeserializeObject(jsonStr, modelType);

            return data;
        }

        private static object? GetModelFromBody(ModelBindingContext bindingContext,
                                                Type modelType)
        {
            using var reader = new StreamReader(bindingContext.HttpContext.Request.Body);
            var jsonString = reader.ReadToEnd();
            var data = JsonConvert.DeserializeObject(jsonString, modelType);

            return data;
        }

        private static bool NeedActivator(IReflect modelType)
        {
            var propFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance;
            var properties = modelType.GetProperties(propFlags);

            return properties.Select(p => p.Name).Distinct().Count() == 1;
        }

        private void ForceSetValue(PropertyInfo propertyInfo, object obj, object value)
        {
            var propName = $"<{propertyInfo.Name}>k__BackingField";
            var propFlags = BindingFlags.Instance | BindingFlags.NonPublic;
            
            obj.GetType().GetField(propName, propFlags)?.SetValue(obj, value);
        }

        private T GetFromHeaderAndDecode(IHeaderDictionary headers) { return (T)Activator.CreateInstance(typeof(T), new object[] { "ok" }); }
    }


All Articles