RestSharp 将复杂模型发送到 API,可以通过 FromForm 读取

ResrSharp send complex model to API that can be read via FromForm

我在 ASP.NET Core 2.2 WebAPI 中有一个非常简单的方法:

[HttpPut]
public async Task<IActionResult> Put([FromForm] SimpleRequest request, [FromForm] string param1)
{
    if (request.ExtraData == null) return BadRequest("Please send data");
    await Task.CompletedTask;
    return Ok("Works");
}

我的模型是这样的:

public class SimpleRequest
{
    [Required]
    public string UserId { get; set; }
    public RequestType? RequestType { get; set; }
    public DateTime Timestamp { get; set; }
    public bool Test { get; set; }
    public ExtraData ExtraData { get; set; }
}
public enum RequestType
{
    Simple,
    Complex,
}
public class ExtraData
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public ulong Id { get; set; }
    public DateTime RDate { get; set; }
    public uint Nr { get; set; }
}

当我向 Postman 提出请求时,我的模型绑定正确:

现在我尝试使用 RestSharp 创建相同的内容。当我使用下面的代码时它工作正常:

var client = new RestClient("https://localhost:44325/api/values");
var request = new RestRequest(Method.PUT);

request.AddParameter("UserId", "Sample", ParameterType.GetOrPost);
request.AddParameter("RequestType", "Simple", ParameterType.GetOrPost);
request.AddParameter("Timestamp", DateTime.Now, ParameterType.GetOrPost);
request.AddParameter("Test", true, ParameterType.GetOrPost);
request.AddParameter("ExtraData.FirstName", "John", ParameterType.GetOrPost);
request.AddParameter("ExtraData.LastName", "Smith", ParameterType.GetOrPost);
request.AddParameter("ExtraData.Id", 1234, ParameterType.GetOrPost);
request.AddParameter("ExtraData.Nr", 1, ParameterType.GetOrPost);
request.AddParameter("ExtraData.RDate", DateTime.Now.AddDays(-2), ParameterType.GetOrPost);

request.AddParameter("param1", "YES", ParameterType.GetOrPost);

var response = client.Execute(request);

但我想重用我的模型,因为它们在单独的 DLL 中共享。

我这样创建我的模型:

var model = new SimpleRequest
{
    UserId = "Sample",
    RequestType = RequestType.Simple,
    Timestamp = DateTime.Now,
    Test = true,
    ExtraData = new ExtraData
    {
        FirstName = "John",
        LastName = "Smith",
        Id = 1234,
        Nr = 1,
        RDate = DateTime.Now.AddDays(-2)
    }
};

但我无法通过请求传递此模型,以便它可以正确反序列化为我的对象。 我试过使用 request.AddJsonBody 但失败了。

通过 RestSharp 传递上述模型的正确方法是什么? 我应该如何序列化它(或添加为参数)才能使其正常工作。

对于FromForm,我们需要通过form-datax-www-form-urlencoded发送请求。您可以实现自己的方式将模型转换为 x-www-form-urlencoded,例如:

  1. 要转换的扩展方法

    public static class RestSharpExtension
    {
            public static IDictionary<string, string> ToKeyValue(this object metaToken)
            {
            if (metaToken == null)
            {
                    return null;
            }
    
            JToken token = metaToken as JToken;
            if (token == null)
            {
                    return ToKeyValue(JObject.FromObject(metaToken));
            }
    
            if (token.HasValues)
            {
                    var contentData = new Dictionary<string, string>();
                    foreach (var child in token.Children().ToList())
                    {
                    var childContent = child.ToKeyValue();
                    if (childContent != null)
                    {
                            contentData = contentData.Concat(childContent)
                                                    .ToDictionary(k => k.Key, v => v.Value);
                    }
                    }
    
                    return contentData;
            }
    
            var jValue = token as JValue;
            if (jValue?.Value == null)
            {
                    return null;
            }
    
            var value = jValue?.Type == JTokenType.Date ?
                            jValue?.ToString("o", CultureInfo.InvariantCulture) :
                            jValue?.ToString(CultureInfo.InvariantCulture);
    
            return new Dictionary<string, string> { { token.Path, value } };
            }
    }
    
  2. 用例

    public async Task<IActionResult> Index()
    {
        var model = new SimpleRequest
                            {
                                UserId = "Sample",
                                RequestType = RequestType.Simple,
                                Timestamp = DateTime.Now,
                                Test = true,
                                ExtraData = new ExtraData
                                {
                                    FirstName = "John",
                                    LastName = "Smith",
                                    Id = 1234,
                                    Nr = 1,
                                    RDate = DateTime.Now.AddDays(-2)
                                }
                            };
        var keyValueContent = model.ToKeyValue();
        keyValueContent.Add("param1", "YES");
        var formUrlEncodedContent = new FormUrlEncodedContent(keyValueContent);
        var urlEncodedString = await formUrlEncodedContent.ReadAsStringAsync();
    
        var client = new RestClient("http://localhost:51420/api/values/Put");
        var request = new RestRequest(Method.PUT);
    
        request.AddParameter("application/x-www-form-urlencoded", urlEncodedString, ParameterType.RequestBody);
    
        var response = client.Execute(request);
    }